summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityThread.java444
-rw-r--r--core/java/android/app/ClientTransactionHandler.java54
-rw-r--r--core/java/android/app/LocalActivityManager.java31
-rw-r--r--core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java12
-rw-r--r--core/java/android/app/servertransaction/ActivityLifecycleItem.java2
-rw-r--r--core/java/android/app/servertransaction/ActivityRelaunchItem.java30
-rw-r--r--core/java/android/app/servertransaction/ActivityResultItem.java11
-rw-r--r--core/java/android/app/servertransaction/ActivityTransactionItem.java69
-rw-r--r--core/java/android/app/servertransaction/DestroyActivityItem.java8
-rw-r--r--core/java/android/app/servertransaction/EnterPipRequestedItem.java8
-rw-r--r--core/java/android/app/servertransaction/LaunchActivityItem.java3
-rw-r--r--core/java/android/app/servertransaction/MoveToDisplayItem.java13
-rw-r--r--core/java/android/app/servertransaction/NewIntentItem.java11
-rw-r--r--core/java/android/app/servertransaction/PauseActivityItem.java9
-rw-r--r--core/java/android/app/servertransaction/ResumeActivityItem.java8
-rw-r--r--core/java/android/app/servertransaction/StartActivityItem.java9
-rw-r--r--core/java/android/app/servertransaction/StopActivityItem.java8
-rw-r--r--core/java/android/app/servertransaction/TopResumedActivityChangeItem.java26
-rw-r--r--core/java/android/app/servertransaction/TransactionExecutor.java12
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java56
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java66
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java1
23 files changed, 493 insertions, 408 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d67b98620f37..267b81823688 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -614,7 +614,7 @@ public final class ActivityThread extends ClientTransactionHandler {
throw new IllegalStateException(
"Received config update for non-existing activity");
}
- activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig,
+ activity.mMainThread.handleActivityConfigurationChanged(this, overrideConfig,
newDisplayId);
};
}
@@ -3475,13 +3475,9 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) {
- final ActivityClientRecord r = mActivities.get(token);
+ public void handleStartActivity(ActivityClientRecord r,
+ PendingTransactionActions pendingActions) {
final Activity activity = r.activity;
- if (r.activity == null) {
- // TODO(lifecycler): What do we do in this case?
- return;
- }
if (!r.stopped) {
throw new IllegalStateException("Can't start activity that is not stopped.");
}
@@ -3687,12 +3683,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleNewIntent(IBinder token, List<ReferrerIntent> intents) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r == null) {
- return;
- }
-
+ public void handleNewIntent(ActivityClientRecord r, List<ReferrerIntent> intents) {
checkAndBlockForNetworkAccess();
deliverNewIntents(r, intents);
}
@@ -3881,13 +3872,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handlePictureInPictureRequested(IBinder token) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r == null) {
- Log.w(TAG, "Activity to request PIP to no longer exists");
- return;
- }
-
+ public void handlePictureInPictureRequested(ActivityClientRecord r) {
final boolean receivedByApp = r.activity.onPictureInPictureRequested();
if (!receivedByApp) {
// Previous recommendation was for apps to enter picture-in-picture in
@@ -4417,22 +4402,21 @@ public final class ActivityThread extends ClientTransactionHandler {
/**
* Resume the activity.
- * @param token Target activity token.
+ * @param r Target activity record.
* @param finalStateRequest Flag indicating if this is part of final state resolution for a
* transaction.
* @param reason Reason for performing the action.
*
- * @return The {@link ActivityClientRecord} that was resumed, {@code null} otherwise.
+ * @return {@code true} that was resumed, {@code false} otherwise.
*/
@VisibleForTesting
- public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
+ public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
String reason) {
- final ActivityClientRecord r = mActivities.get(token);
if (localLOGV) {
Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);
}
- if (r == null || r.activity.mFinished) {
- return null;
+ if (r.activity.mFinished) {
+ return false;
}
if (r.getLifecycleState() == ON_RESUME) {
if (!finalStateRequest) {
@@ -4446,7 +4430,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// handle two resume requests for the final state. For cases other than this
// one, we don't expect it to happen.
}
- return null;
+ return false;
}
if (finalStateRequest) {
r.hideForNow = false;
@@ -4477,7 +4461,7 @@ public final class ActivityThread extends ClientTransactionHandler {
+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);
}
}
- return r;
+ return true;
}
static final void cleanUpPendingRemoveWindows(ActivityClientRecord r, boolean force) {
@@ -4498,20 +4482,19 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
- String reason) {
+ public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
+ boolean isForward, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
- final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
- if (r == null) {
- // We didn't actually resume the activity, so skipping any follow-up actions.
+ // skip below steps for double-resume and r.mFinish = true case.
+ if (!performResumeActivity(r, finalStateRequest, reason)) {
return;
}
- if (mActivitiesToBeDestroyed.containsKey(token)) {
+ if (mActivitiesToBeDestroyed.containsKey(r.token)) {
// Although the activity is resumed, it is going to be destroyed. So the following
// UI operations are unnecessary and also prevents exception because its token may
// be gone that window manager cannot recognize it. All necessary cleanup actions
@@ -4629,13 +4612,8 @@ public final class ActivityThread extends ClientTransactionHandler {
@Override
- public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) {
- ActivityClientRecord r = mActivities.get(token);
- if (r == null || r.activity == null) {
- Slog.w(TAG, "Not found target activity to report position change for token: " + token);
- return;
- }
-
+ public void handleTopResumedActivityChanged(ActivityClientRecord r, boolean onTop,
+ String reason) {
if (DEBUG_ORDER) {
Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r);
}
@@ -4668,23 +4646,20 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
+ public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving,
int configChanges, PendingTransactionActions pendingActions, String reason) {
- ActivityClientRecord r = mActivities.get(token);
- if (r != null) {
- if (userLeaving) {
- performUserLeavingActivity(r);
- }
+ if (userLeaving) {
+ performUserLeavingActivity(r);
+ }
- r.activity.mConfigChangeFlags |= configChanges;
- performPauseActivity(r, finished, reason, pendingActions);
+ r.activity.mConfigChangeFlags |= configChanges;
+ performPauseActivity(r, finished, reason, pendingActions);
- // Make sure any pending writes are now committed.
- if (r.isPreHoneycomb()) {
- QueuedWork.waitToFinish();
- }
- mSomeActivitiesChanged = true;
+ // Make sure any pending writes are now committed.
+ if (r.isPreHoneycomb()) {
+ QueuedWork.waitToFinish();
}
+ mSomeActivitiesChanged = true;
}
final void performUserLeavingActivity(ActivityClientRecord r) {
@@ -4781,8 +4756,11 @@ public final class ActivityThread extends ClientTransactionHandler {
r.setState(ON_PAUSE);
}
+ // TODO(b/127877792): Make LocalActivityManager call performStopActivityInner. We cannot do this
+ // since it's a high usage hidden API.
/** Called from {@link LocalActivityManager}. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 127877792,
+ publicAlternatives = "{@code N/A}")
final void performStopActivity(IBinder token, boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */,
@@ -4823,39 +4801,37 @@ public final class ActivityThread extends ClientTransactionHandler {
private void performStopActivityInner(ActivityClientRecord r, StopInfo info,
boolean saveState, boolean finalStateRequest, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
- if (r != null) {
- if (r.stopped) {
- if (r.activity.mFinished) {
- // If we are finishing, we won't call onResume() in certain
- // cases. So here we likewise don't want to call onStop()
- // if the activity isn't resumed.
- return;
- }
- if (!finalStateRequest) {
- final RuntimeException e = new RuntimeException(
- "Performing stop of activity that is already stopped: "
- + r.intent.getComponent().toShortString());
- Slog.e(TAG, e.getMessage(), e);
- Slog.e(TAG, r.getStateString());
- }
+ if (r.stopped) {
+ if (r.activity.mFinished) {
+ // If we are finishing, we won't call onResume() in certain
+ // cases. So here we likewise don't want to call onStop()
+ // if the activity isn't resumed.
+ return;
+ }
+ if (!finalStateRequest) {
+ final RuntimeException e = new RuntimeException(
+ "Performing stop of activity that is already stopped: "
+ + r.intent.getComponent().toShortString());
+ Slog.e(TAG, e.getMessage(), e);
+ Slog.e(TAG, r.getStateString());
}
+ }
- // One must first be paused before stopped...
- performPauseActivityIfNeeded(r, reason);
+ // One must first be paused before stopped...
+ performPauseActivityIfNeeded(r, reason);
- if (info != null) {
- try {
- // First create a thumbnail for the activity...
- // For now, don't create the thumbnail here; we are
- // doing that by doing a screen snapshot.
- info.setDescription(r.activity.onCreateDescription());
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to save state of activity "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
+ if (info != null) {
+ try {
+ // First create a thumbnail for the activity...
+ // For now, don't create the thumbnail here; we are
+ // doing that by doing a screen snapshot.
+ info.setDescription(r.activity.onCreateDescription());
+ } catch (Exception e) {
+ if (!mInstrumentation.onException(r.activity, e)) {
+ throw new RuntimeException(
+ "Unable to save state of activity "
+ + r.intent.getComponent().toShortString()
+ + ": " + e.toString(), e);
}
}
@@ -4927,9 +4903,8 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleStopActivity(IBinder token, int configChanges,
+ public void handleStopActivity(ActivityClientRecord r, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
- final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
@@ -4965,8 +4940,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void performRestartActivity(IBinder token, boolean start) {
- ActivityClientRecord r = mActivities.get(token);
+ public void performRestartActivity(ActivityClientRecord r, boolean start) {
if (r.stopped) {
r.activity.performRestart(start, "performRestartActivity");
if (start) {
@@ -5053,107 +5027,101 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleSendResult(IBinder token, List<ResultInfo> results, String reason) {
- ActivityClientRecord r = mActivities.get(token);
+ public void handleSendResult(ActivityClientRecord r, List<ResultInfo> results, String reason) {
if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r);
- if (r != null) {
- final boolean resumed = !r.paused;
- if (!r.activity.mFinished && r.activity.mDecor != null
- && r.hideForNow && resumed) {
- // We had hidden the activity because it started another
- // one... we have gotten a result back and we are not
- // paused, so make sure our window is visible.
- updateVisibility(r, true);
- }
- if (resumed) {
- try {
- // Now we are idle.
- r.activity.mCalled = false;
- mInstrumentation.callActivityOnPause(r.activity);
- if (!r.activity.mCalled) {
- throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString()
- + " did not call through to super.onPause()");
- }
- } catch (SuperNotCalledException e) {
- throw e;
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to pause activity "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
+ final boolean resumed = !r.paused;
+ if (!r.activity.mFinished && r.activity.mDecor != null
+ && r.hideForNow && resumed) {
+ // We had hidden the activity because it started another
+ // one... we have gotten a result back and we are not
+ // paused, so make sure our window is visible.
+ updateVisibility(r, true);
+ }
+ if (resumed) {
+ try {
+ // Now we are idle.
+ r.activity.mCalled = false;
+ mInstrumentation.callActivityOnPause(r.activity);
+ if (!r.activity.mCalled) {
+ throw new SuperNotCalledException(
+ "Activity " + r.intent.getComponent().toShortString()
+ + " did not call through to super.onPause()");
+ }
+ } catch (SuperNotCalledException e) {
+ throw e;
+ } catch (Exception e) {
+ if (!mInstrumentation.onException(r.activity, e)) {
+ throw new RuntimeException(
+ "Unable to pause activity "
+ + r.intent.getComponent().toShortString()
+ + ": " + e.toString(), e);
}
- }
- checkAndBlockForNetworkAccess();
- deliverResults(r, results, reason);
- if (resumed) {
- r.activity.performResume(false, reason);
}
}
+ checkAndBlockForNetworkAccess();
+ deliverResults(r, results, reason);
+ if (resumed) {
+ r.activity.performResume(false, reason);
+ }
}
/** Core implementation of activity destroy call. */
- ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
+ ActivityClientRecord performDestroyActivity(ActivityClientRecord r, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
- ActivityClientRecord r = mActivities.get(token);
Class<? extends Activity> activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
- if (r != null) {
- activityClass = r.activity.getClass();
- r.activity.mConfigChangeFlags |= configChanges;
- if (finishing) {
- r.activity.mFinished = true;
- }
+ activityClass = r.activity.getClass();
+ r.activity.mConfigChangeFlags |= configChanges;
+ if (finishing) {
+ r.activity.mFinished = true;
+ }
- performPauseActivityIfNeeded(r, "destroy");
+ performPauseActivityIfNeeded(r, "destroy");
- if (!r.stopped) {
- callActivityOnStop(r, false /* saveState */, "destroy");
- }
- if (getNonConfigInstance) {
- try {
- r.lastNonConfigurationInstances
- = r.activity.retainNonConfigurationInstances();
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to retain activity "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
- }
- }
+ if (!r.stopped) {
+ callActivityOnStop(r, false /* saveState */, "destroy");
+ }
+ if (getNonConfigInstance) {
try {
- r.activity.mCalled = false;
- mInstrumentation.callActivityOnDestroy(r.activity);
- if (!r.activity.mCalled) {
- throw new SuperNotCalledException(
- "Activity " + safeToComponentShortString(r.intent) +
- " did not call through to super.onDestroy()");
- }
- if (r.window != null) {
- r.window.closeAllPanels();
- }
- } catch (SuperNotCalledException e) {
- throw e;
+ r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
- "Unable to destroy activity " + safeToComponentShortString(r.intent)
+ "Unable to retain activity "
+ + r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.setState(ON_DESTROY);
mLastReportedWindowingMode.remove(r.activity.getActivityToken());
}
+ try {
+ r.activity.mCalled = false;
+ mInstrumentation.callActivityOnDestroy(r.activity);
+ if (!r.activity.mCalled) {
+ throw new SuperNotCalledException(
+ "Activity " + safeToComponentShortString(r.intent)
+ + " did not call through to super.onDestroy()");
+ }
+ if (r.window != null) {
+ r.window.closeAllPanels();
+ }
+ } catch (SuperNotCalledException e) {
+ throw e;
+ } catch (Exception e) {
+ if (!mInstrumentation.onException(r.activity, e)) {
+ throw new RuntimeException(
+ "Unable to destroy activity " + safeToComponentShortString(r.intent)
+ + ": " + e.toString(), e);
+ }
+ }
+ r.setState(ON_DESTROY);
schedulePurgeIdler();
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
- mActivities.remove(token);
+ mActivities.remove(r.token);
}
StrictMode.decrementExpectedActivityCount(activityClass);
return r;
@@ -5170,70 +5138,67 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
+ public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
boolean getNonConfigInstance, String reason) {
- ActivityClientRecord r = performDestroyActivity(token, finishing,
- configChanges, getNonConfigInstance, reason);
- if (r != null) {
- cleanUpPendingRemoveWindows(r, finishing);
- WindowManager wm = r.activity.getWindowManager();
- View v = r.activity.mDecor;
- if (v != null) {
- if (r.activity.mVisibleFromServer) {
- mNumVisibleActivities--;
- }
- IBinder wtoken = v.getWindowToken();
- if (r.activity.mWindowAdded) {
- if (r.mPreserveWindow) {
- // Hold off on removing this until the new activity's
- // window is being added.
- r.mPendingRemoveWindow = r.window;
- r.mPendingRemoveWindowManager = wm;
- // We can only keep the part of the view hierarchy that we control,
- // everything else must be removed, because it might not be able to
- // behave properly when activity is relaunching.
- r.window.clearContentView();
- } else {
- wm.removeViewImmediate(v);
- }
- }
- if (wtoken != null && r.mPendingRemoveWindow == null) {
- WindowManagerGlobal.getInstance().closeAll(wtoken,
- r.activity.getClass().getName(), "Activity");
- } else if (r.mPendingRemoveWindow != null) {
- // We're preserving only one window, others should be closed so app views
- // will be detached before the final tear down. It should be done now because
- // some components (e.g. WebView) rely on detach callbacks to perform receiver
- // unregister and other cleanup.
- WindowManagerGlobal.getInstance().closeAllExceptView(token, v,
- r.activity.getClass().getName(), "Activity");
+ r = performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
+ cleanUpPendingRemoveWindows(r, finishing);
+ WindowManager wm = r.activity.getWindowManager();
+ View v = r.activity.mDecor;
+ if (v != null) {
+ if (r.activity.mVisibleFromServer) {
+ mNumVisibleActivities--;
+ }
+ IBinder wtoken = v.getWindowToken();
+ if (r.activity.mWindowAdded) {
+ if (r.mPreserveWindow) {
+ // Hold off on removing this until the new activity's
+ // window is being added.
+ r.mPendingRemoveWindow = r.window;
+ r.mPendingRemoveWindowManager = wm;
+ // We can only keep the part of the view hierarchy that we control,
+ // everything else must be removed, because it might not be able to
+ // behave properly when activity is relaunching.
+ r.window.clearContentView();
+ } else {
+ wm.removeViewImmediate(v);
}
- r.activity.mDecor = null;
- }
- if (r.mPendingRemoveWindow == null) {
- // If we are delaying the removal of the activity window, then
- // we can't clean up all windows here. Note that we can't do
- // so later either, which means any windows that aren't closed
- // by the app will leak. Well we try to warning them a lot
- // about leaking windows, because that is a bug, so if they are
- // using this recreate facility then they get to live with leaks.
- WindowManagerGlobal.getInstance().closeAll(token,
- r.activity.getClass().getName(), "Activity");
}
-
- // Mocked out contexts won't be participating in the normal
- // process lifecycle, but if we're running with a proper
- // ApplicationContext we need to have it tear down things
- // cleanly.
- Context c = r.activity.getBaseContext();
- if (c instanceof ContextImpl) {
- ((ContextImpl) c).scheduleFinalCleanup(
+ if (wtoken != null && r.mPendingRemoveWindow == null) {
+ WindowManagerGlobal.getInstance().closeAll(wtoken,
+ r.activity.getClass().getName(), "Activity");
+ } else if (r.mPendingRemoveWindow != null) {
+ // We're preserving only one window, others should be closed so app views
+ // will be detached before the final tear down. It should be done now because
+ // some components (e.g. WebView) rely on detach callbacks to perform receiver
+ // unregister and other cleanup.
+ WindowManagerGlobal.getInstance().closeAllExceptView(r.token, v,
r.activity.getClass().getName(), "Activity");
}
+ r.activity.mDecor = null;
+ }
+ if (r.mPendingRemoveWindow == null) {
+ // If we are delaying the removal of the activity window, then
+ // we can't clean up all windows here. Note that we can't do
+ // so later either, which means any windows that aren't closed
+ // by the app will leak. Well we try to warning them a lot
+ // about leaking windows, because that is a bug, so if they are
+ // using this recreate facility then they get to live with leaks.
+ WindowManagerGlobal.getInstance().closeAll(r.token,
+ r.activity.getClass().getName(), "Activity");
+ }
+
+ // Mocked out contexts won't be participating in the normal
+ // process lifecycle, but if we're running with a proper
+ // ApplicationContext we need to have it tear down things
+ // cleanly.
+ Context c = r.activity.getBaseContext();
+ if (c instanceof ContextImpl) {
+ ((ContextImpl) c).scheduleFinalCleanup(
+ r.activity.getClass().getName(), "Activity");
}
if (finishing) {
try {
- ActivityTaskManager.getService().activityDestroyed(token);
+ ActivityTaskManager.getService().activityDestroyed(r.token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -5456,7 +5421,7 @@ public final class ActivityThread extends ClientTransactionHandler {
callActivityOnStop(r, true /* saveState */, reason);
}
- handleDestroyActivity(r.token, false, configChanges, true, reason);
+ handleDestroyActivity(r, false, configChanges, true, reason);
r.activity = null;
r.window = null;
@@ -5484,12 +5449,10 @@ public final class ActivityThread extends ClientTransactionHandler {
}
@Override
- public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) {
+ public void reportRelaunch(ActivityClientRecord r, PendingTransactionActions pendingActions) {
try {
- ActivityTaskManager.getService().activityRelaunched(token);
- final ActivityClientRecord r = mActivities.get(token);
- if (pendingActions.shouldReportRelaunchToWindowManager() && r != null
- && r.window != null) {
+ ActivityTaskManager.getService().activityRelaunched(r.token);
+ if (pendingActions.shouldReportRelaunchToWindowManager() && r.window != null) {
r.window.reportActivityRelaunched();
}
} catch (RemoteException e) {
@@ -5648,13 +5611,7 @@ public final class ActivityThread extends ClientTransactionHandler {
*/
private Configuration performActivityConfigurationChanged(Activity activity,
Configuration newConfig, Configuration amOverrideConfig, int displayId) {
- if (activity == null) {
- throw new IllegalArgumentException("No activity provided.");
- }
final IBinder activityToken = activity.getActivityToken();
- if (activityToken == null) {
- throw new IllegalArgumentException("Activity token not set. Is the activity attached?");
- }
final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
boolean shouldReportChange = false;
@@ -5954,20 +5911,8 @@ public final class ActivityThread extends ClientTransactionHandler {
* processing any configurations older than {@code overrideConfig}.
*/
@Override
- public void updatePendingActivityConfiguration(IBinder activityToken,
+ public void updatePendingActivityConfiguration(ActivityClientRecord r,
Configuration overrideConfig) {
- final ActivityClientRecord r;
- synchronized (mResourcesManager) {
- r = mActivities.get(activityToken);
- }
-
- if (r == null) {
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Not found target activity to update its pending config.");
- }
- return;
- }
-
synchronized (r) {
if (r.mPendingOverrideConfig != null
&& !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
@@ -5987,21 +5932,14 @@ public final class ActivityThread extends ClientTransactionHandler {
* if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with
* a newer config than {@code overrideConfig}.
*
- * @param activityToken Target activity token.
+ * @param r Target activity record.
* @param overrideConfig Activity override config.
* @param displayId Id of the display where activity was moved to, -1 if there was no move and
* value didn't change.
*/
@Override
- public void handleActivityConfigurationChanged(IBinder activityToken,
+ public void handleActivityConfigurationChanged(ActivityClientRecord r,
@NonNull Configuration overrideConfig, int displayId) {
- ActivityClientRecord r = mActivities.get(activityToken);
- // Check input params.
- if (r == null || r.activity == null) {
- if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r);
- return;
- }
-
synchronized (r) {
if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
if (DEBUG_CONFIGURATION) {
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 2df756e80fde..ac50676ff46b 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -15,6 +15,8 @@
*/
package android.app;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.PendingTransactionActions;
@@ -89,37 +91,38 @@ public abstract class ClientTransactionHandler {
public abstract Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed();
/** Destroy the activity. */
- public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
- boolean getNonConfigInstance, String reason);
+ public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing,
+ int configChanges, boolean getNonConfigInstance, String reason);
/** Pause the activity. */
- public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges, PendingTransactionActions pendingActions, String reason);
+ public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished,
+ boolean userLeaving, int configChanges, PendingTransactionActions pendingActions,
+ String reason);
/**
* Resume the activity.
- * @param token Target activity token.
+ * @param r Target activity record.
* @param finalStateRequest Flag indicating if this call is handling final lifecycle state
* request for a transaction.
* @param isForward Flag indicating if next transition is forward.
* @param reason Reason for performing this operation.
*/
- public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
- boolean isForward, String reason);
+ public abstract void handleResumeActivity(@NonNull ActivityClientRecord r,
+ boolean finalStateRequest, boolean isForward, String reason);
/**
* Notify the activity about top resumed state change.
- * @param token Target activity token.
+ * @param r Target activity record.
* @param isTopResumedActivity Current state of the activity, {@code true} if it's the
* topmost resumed activity in the system, {@code false} otherwise.
* @param reason Reason for performing this operation.
*/
- public abstract void handleTopResumedActivityChanged(IBinder token,
+ public abstract void handleTopResumedActivityChanged(@NonNull ActivityClientRecord r,
boolean isTopResumedActivity, String reason);
/**
* Stop the activity.
- * @param token Target activity token.
+ * @param r Target activity record.
* @param configChanges Activity configuration changes.
* @param pendingActions Pending actions to be used on this or later stages of activity
* transaction.
@@ -127,38 +130,40 @@ public abstract class ClientTransactionHandler {
* request for a transaction.
* @param reason Reason for performing this operation.
*/
- public abstract void handleStopActivity(IBinder token, int configChanges,
+ public abstract void handleStopActivity(@NonNull ActivityClientRecord r, int configChanges,
PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);
/** Report that activity was stopped to server. */
public abstract void reportStop(PendingTransactionActions pendingActions);
/** Restart the activity after it was stopped. */
- public abstract void performRestartActivity(IBinder token, boolean start);
+ public abstract void performRestartActivity(@NonNull ActivityClientRecord r, boolean start);
/** Set pending activity configuration in case it will be updated by other transaction item. */
- public abstract void updatePendingActivityConfiguration(IBinder activityToken,
+ public abstract void updatePendingActivityConfiguration(@NonNull ActivityClientRecord r,
Configuration overrideConfig);
/** Deliver activity (override) configuration change. */
- public abstract void handleActivityConfigurationChanged(IBinder activityToken,
+ public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
Configuration overrideConfig, int displayId);
/** Deliver result from another activity. */
- public abstract void handleSendResult(IBinder token, List<ResultInfo> results, String reason);
+ public abstract void handleSendResult(
+ @NonNull ActivityClientRecord r, List<ResultInfo> results, String reason);
/** Deliver new intent. */
- public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents);
+ public abstract void handleNewIntent(
+ @NonNull ActivityClientRecord r, List<ReferrerIntent> intents);
/** Request that an activity enter picture-in-picture. */
- public abstract void handlePictureInPictureRequested(IBinder token);
+ public abstract void handlePictureInPictureRequested(@NonNull ActivityClientRecord r);
/** Perform activity launch. */
- public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r,
+ public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent);
/** Perform activity start. */
- public abstract void handleStartActivity(IBinder token,
+ public abstract void handleStartActivity(@NonNull ActivityClientRecord r,
PendingTransactionActions pendingActions);
/** Get package info. */
@@ -176,7 +181,7 @@ public abstract class ClientTransactionHandler {
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.
*/
- public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);
+ public abstract ActivityClientRecord getActivityClient(IBinder token);
/**
* Prepare activity relaunch to update internal bookkeeping. This is used to track multiple
@@ -191,7 +196,7 @@ public abstract class ClientTransactionHandler {
* @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during
* relaunch, or {@code null} if relaunch cancelled.
*/
- public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token,
+ public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, MergedConfiguration config, boolean preserveWindow);
@@ -200,14 +205,15 @@ public abstract class ClientTransactionHandler {
* @param r Activity client record prepared for relaunch.
* @param pendingActions Pending actions to be used on later stages of activity transaction.
* */
- public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r,
+ public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r,
PendingTransactionActions pendingActions);
/**
* Report that relaunch request was handled.
- * @param token Target activity token.
+ * @param r Target activity record.
* @param pendingActions Pending actions initialized on earlier stages of activity transaction.
* Used to check if we should report relaunch to WM.
* */
- public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions);
+ public abstract void reportRelaunch(@NonNull ActivityClientRecord r,
+ PendingTransactionActions pendingActions);
}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 7cdf85e0a6b8..d61c5d5ccd3d 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -49,6 +49,7 @@ public class LocalActivityManager {
private static final String TAG = "LocalActivityManager";
private static final boolean localLOGV = false;
+ // TODO(b/127877792): try to remove this and use {@code ActivityClientRecord} instead.
// Internal token for an Activity being managed by LocalActivityManager.
private static class LocalActivityRecord extends Binder {
LocalActivityRecord(String _id, Intent _intent) {
@@ -136,7 +137,7 @@ public class LocalActivityManager {
// startActivity() has not yet been called, so nothing to do.
return;
}
-
+
if (r.curState == INITIALIZING) {
// Get the lastNonConfigurationInstance for the activity
HashMap<String, Object> lastNonConfigurationInstances =
@@ -177,12 +178,13 @@ public class LocalActivityManager {
pendingActions = null;
}
- mActivityThread.handleStartActivity(r, pendingActions);
+ mActivityThread.handleStartActivity(clientRecord, pendingActions);
r.curState = STARTED;
if (desiredState == RESUMED) {
if (localLOGV) Log.v(TAG, r.id + ": resuming");
- mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING");
+ mActivityThread.performResumeActivity(clientRecord, true,
+ "moveToState-INITIALIZING");
r.curState = RESUMED;
}
@@ -194,18 +196,21 @@ public class LocalActivityManager {
// group's state catches up.
return;
}
-
+
+ final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+
switch (r.curState) {
case CREATED:
if (desiredState == STARTED) {
if (localLOGV) Log.v(TAG, r.id + ": restarting");
- mActivityThread.performRestartActivity(r, true /* start */);
+ mActivityThread.performRestartActivity(clientRecord, true /* start */);
r.curState = STARTED;
}
if (desiredState == RESUMED) {
if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming");
- mActivityThread.performRestartActivity(r, true /* start */);
- mActivityThread.performResumeActivity(r, true, "moveToState-CREATED");
+ mActivityThread.performRestartActivity(clientRecord, true /* start */);
+ mActivityThread.performResumeActivity(clientRecord, true,
+ "moveToState-CREATED");
r.curState = RESUMED;
}
return;
@@ -214,7 +219,8 @@ public class LocalActivityManager {
if (desiredState == RESUMED) {
// Need to resume it...
if (localLOGV) Log.v(TAG, r.id + ": resuming");
- mActivityThread.performResumeActivity(r, true, "moveToState-STARTED");
+ mActivityThread.performResumeActivity(clientRecord, true,
+ "moveToState-STARTED");
r.instanceState = null;
r.curState = RESUMED;
}
@@ -352,7 +358,8 @@ public class LocalActivityManager {
ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
if (localLOGV) Log.v(TAG, r.id + ": new intent");
- mActivityThread.handleNewIntent(r, intents);
+ final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+ mActivityThread.handleNewIntent(clientRecord, intents);
r.intent = intent;
moveToState(r, mCurState);
if (mSingleMode) {
@@ -399,7 +406,8 @@ public class LocalActivityManager {
performPause(r, finish);
}
if (localLOGV) Log.v(TAG, r.id + ": destroying");
- mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */,
+ final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+ mActivityThread.performDestroyActivity(clientRecord, finish, 0 /* configChanges */,
false /* getNonConfigInstance */, "LocalActivityManager::performDestroy");
r.activity = null;
r.window = null;
@@ -664,7 +672,8 @@ public class LocalActivityManager {
for (int i=0; i<N; i++) {
LocalActivityRecord r = mActivityArray.get(i);
if (localLOGV) Log.v(TAG, r.id + ": destroying");
- mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */,
+ final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+ mActivityThread.performDestroyActivity(clientRecord, finishing, 0 /* configChanges */,
false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy");
}
mActivities.clear();
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index 8b52242a6b6c..8a4bee98ca87 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -20,6 +20,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.content.res.Configuration;
import android.os.IBinder;
@@ -32,23 +33,24 @@ import java.util.Objects;
* Activity configuration changed callback.
* @hide
*/
-public class ActivityConfigurationChangeItem extends ClientTransactionItem {
+public class ActivityConfigurationChangeItem extends ActivityTransactionItem {
private Configuration mConfiguration;
@Override
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+ final ActivityClientRecord r = getActivityClientRecord(client, token);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(token, mConfiguration);
+ client.updatePendingActivityConfiguration(r, mConfiguration);
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
// TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
- client.handleActivityConfigurationChanged(token, mConfiguration, INVALID_DISPLAY);
+ client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -93,7 +95,7 @@ public class ActivityConfigurationChangeItem extends ClientTransactionItem {
mConfiguration = in.readTypedObject(Configuration.CREATOR);
}
- public static final @android.annotation.NonNull Creator<ActivityConfigurationChangeItem> CREATOR =
+ public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR =
new Creator<ActivityConfigurationChangeItem>() {
public ActivityConfigurationChangeItem createFromParcel(Parcel in) {
return new ActivityConfigurationChangeItem(in);
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index c9193a9578e7..cadb6606b1be 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -25,7 +25,7 @@ import java.lang.annotation.RetentionPolicy;
* Request for lifecycle state that an activity should reach.
* @hide
*/
-public abstract class ActivityLifecycleItem extends ClientTransactionItem {
+public abstract class ActivityLifecycleItem extends ActivityTransactionItem {
@IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = {
UNDEFINED,
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
index 9844de7b6e88..87ea3f8db39c 100644
--- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -18,7 +18,8 @@ package android.app.servertransaction;
import static android.app.ActivityThread.DEBUG_ORDER;
-import android.app.ActivityThread;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.ResultInfo;
import android.os.IBinder;
@@ -36,7 +37,7 @@ import java.util.Objects;
* Activity relaunch callback.
* @hide
*/
-public class ActivityRelaunchItem extends ClientTransactionItem {
+public class ActivityRelaunchItem extends ActivityTransactionItem {
private static final String TAG = "ActivityRelaunchItem";
@@ -50,7 +51,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem {
* A record that was properly configured for relaunch. Execution will be cancelled if not
* initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}.
*/
- private ActivityThread.ActivityClientRecord mActivityClientRecord;
+ private ActivityClientRecord mActivityClientRecord;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
@@ -59,7 +60,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem {
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
if (mActivityClientRecord == null) {
if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
@@ -73,7 +74,8 @@ public class ActivityRelaunchItem extends ClientTransactionItem {
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
- client.reportRelaunch(token, pendingActions);
+ final ActivityClientRecord r = getActivityClientRecord(client, token);
+ client.reportRelaunch(r, pendingActions);
}
// ObjectPoolItem implementation
@@ -130,16 +132,16 @@ public class ActivityRelaunchItem extends ClientTransactionItem {
mPreserveWindow = in.readBoolean();
}
- public static final @android.annotation.NonNull Creator<ActivityRelaunchItem> CREATOR =
+ public static final @NonNull Creator<ActivityRelaunchItem> CREATOR =
new Creator<ActivityRelaunchItem>() {
- public ActivityRelaunchItem createFromParcel(Parcel in) {
- return new ActivityRelaunchItem(in);
- }
-
- public ActivityRelaunchItem[] newArray(int size) {
- return new ActivityRelaunchItem[size];
- }
- };
+ public ActivityRelaunchItem createFromParcel(Parcel in) {
+ return new ActivityRelaunchItem(in);
+ }
+
+ public ActivityRelaunchItem[] newArray(int size) {
+ return new ActivityRelaunchItem[size];
+ }
+ };
@Override
public boolean equals(Object o) {
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
index 4e743caccad6..47096a8257e9 100644
--- a/core/java/android/app/servertransaction/ActivityResultItem.java
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -18,10 +18,11 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.ResultInfo;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
@@ -33,7 +34,7 @@ import java.util.Objects;
* Activity result delivery callback.
* @hide
*/
-public class ActivityResultItem extends ClientTransactionItem {
+public class ActivityResultItem extends ActivityTransactionItem {
@UnsupportedAppUsage
private List<ResultInfo> mResultInfoList;
@@ -45,10 +46,10 @@ public class ActivityResultItem extends ClientTransactionItem {
}*/
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
- client.handleSendResult(token, mResultInfoList, "ACTIVITY_RESULT");
+ client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -88,7 +89,7 @@ public class ActivityResultItem extends ClientTransactionItem {
mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR);
}
- public static final @android.annotation.NonNull Parcelable.Creator<ActivityResultItem> CREATOR =
+ public static final @NonNull Parcelable.Creator<ActivityResultItem> CREATOR =
new Parcelable.Creator<ActivityResultItem>() {
public ActivityResultItem createFromParcel(Parcel in) {
return new ActivityResultItem(in);
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
new file mode 100644
index 000000000000..f7d7e9d20ab9
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.servertransaction;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * An activity-targeting callback message to a client that can be scheduled and executed.
+ * It also provides nullity-free version of
+ * {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)} for child class
+ * to inherit.
+ *
+ * @see ClientTransaction
+ * @see ClientTransactionItem
+ * @see com.android.server.wm.ClientLifecycleManager
+ * @hide
+ */
+public abstract class ActivityTransactionItem extends ClientTransactionItem {
+ @Override
+ public final void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = getActivityClientRecord(client, token);
+
+ execute(client, r, pendingActions);
+ }
+
+ /**
+ * Like {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)},
+ * but take non-null {@link ActivityClientRecord} as a parameter.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public abstract void execute(@NonNull ClientTransactionHandler client,
+ @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions);
+
+ @NonNull ActivityClientRecord getActivityClientRecord(
+ @NonNull ClientTransactionHandler client, IBinder token) {
+ final ActivityClientRecord r = client.getActivityClient(token);
+ if (r == null) {
+ throw new IllegalArgumentException("Activity client record must not be null to execute "
+ + "transaction item");
+ }
+ if (client.getActivity(token) == null) {
+ throw new IllegalArgumentException("Activity must not be null to execute "
+ + "transaction item");
+ }
+ return r;
+ }
+}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index 3ee761477efd..1611369497e9 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -18,6 +18,8 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
@@ -38,10 +40,10 @@ public class DestroyActivityItem extends ActivityLifecycleItem {
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
- client.handleDestroyActivity(token, mFinished, mConfigChanges,
+ client.handleDestroyActivity(r, mFinished, mConfigChanges,
false /* getNonConfigInstance */, "DestroyActivityItem");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -92,7 +94,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem {
mConfigChanges = in.readInt();
}
- public static final @android.annotation.NonNull Creator<DestroyActivityItem> CREATOR =
+ public static final @NonNull Creator<DestroyActivityItem> CREATOR =
new Creator<DestroyActivityItem>() {
public DestroyActivityItem createFromParcel(Parcel in) {
return new DestroyActivityItem(in);
diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
index b2a1276fa178..b7e81a56afad 100644
--- a/core/java/android/app/servertransaction/EnterPipRequestedItem.java
+++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
@@ -16,20 +16,20 @@
package android.app.servertransaction;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
-import android.os.IBinder;
import android.os.Parcel;
/**
* Request an activity to enter picture-in-picture mode.
* @hide
*/
-public final class EnterPipRequestedItem extends ClientTransactionItem {
+public final class EnterPipRequestedItem extends ActivityTransactionItem {
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
- client.handlePictureInPictureRequested(token);
+ client.handlePictureInPictureRequested(r);
}
// ObjectPoolItem implementation
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 2e7b6262c785..77457af77340 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -18,6 +18,7 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.ProfilerInfo;
@@ -163,7 +164,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
in.readTypedObject(FixedRotationAdjustments.CREATOR));
}
- public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR =
+ public static final @NonNull Creator<LaunchActivityItem> CREATOR =
new Creator<LaunchActivityItem>() {
public LaunchActivityItem createFromParcel(Parcel in) {
return new LaunchActivityItem(in);
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 9a457a3aad40..32de53f189b0 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -19,6 +19,7 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.content.res.Configuration;
import android.os.IBinder;
@@ -31,23 +32,24 @@ import java.util.Objects;
* Activity move to a different display message.
* @hide
*/
-public class MoveToDisplayItem extends ClientTransactionItem {
+public class MoveToDisplayItem extends ActivityTransactionItem {
private int mTargetDisplayId;
private Configuration mConfiguration;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
+ final ActivityClientRecord r = getActivityClientRecord(client, token);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(token, mConfiguration);
+ client.updatePendingActivityConfiguration(r, mConfiguration);
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
- client.handleActivityConfigurationChanged(token, mConfiguration, mTargetDisplayId);
+ client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -96,7 +98,8 @@ public class MoveToDisplayItem extends ClientTransactionItem {
mConfiguration = in.readTypedObject(Configuration.CREATOR);
}
- public static final @android.annotation.NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<MoveToDisplayItem>() {
+ public static final @NonNull Creator<MoveToDisplayItem> CREATOR =
+ new Creator<MoveToDisplayItem>() {
public MoveToDisplayItem createFromParcel(Parcel in) {
return new MoveToDisplayItem(in);
}
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index 6a4996da38ca..b4e2a7bfa10f 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -19,9 +19,10 @@ package android.app.servertransaction;
import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
@@ -35,7 +36,7 @@ import java.util.Objects;
* New intent message.
* @hide
*/
-public class NewIntentItem extends ClientTransactionItem {
+public class NewIntentItem extends ActivityTransactionItem {
@UnsupportedAppUsage
private List<ReferrerIntent> mIntents;
@@ -47,10 +48,10 @@ public class NewIntentItem extends ClientTransactionItem {
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
- client.handleNewIntent(token, mIntents);
+ client.handleNewIntent(r, mIntents);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -94,7 +95,7 @@ public class NewIntentItem extends ClientTransactionItem {
mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
}
- public static final @android.annotation.NonNull Parcelable.Creator<NewIntentItem> CREATOR =
+ public static final @NonNull Parcelable.Creator<NewIntentItem> CREATOR =
new Parcelable.Creator<NewIntentItem>() {
public NewIntentItem createFromParcel(Parcel in) {
return new NewIntentItem(in);
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index f65c843ee76f..cb154e9585e6 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -18,8 +18,9 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import android.app.ActivityManager;
+import android.annotation.NonNull;
import android.app.ActivityTaskManager;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
@@ -40,10 +41,10 @@ public class PauseActivityItem extends ActivityLifecycleItem {
private boolean mDontReport;
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
+ client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions,
"PAUSE_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -130,7 +131,7 @@ public class PauseActivityItem extends ActivityLifecycleItem {
mDontReport = in.readBoolean();
}
- public static final @android.annotation.NonNull Creator<PauseActivityItem> CREATOR =
+ public static final @NonNull Creator<PauseActivityItem> CREATOR =
new Creator<PauseActivityItem>() {
public PauseActivityItem createFromParcel(Parcel in) {
return new PauseActivityItem(in);
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index 905076b08e69..d2a156c37c90 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -18,8 +18,10 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
@@ -46,10 +48,10 @@ public class ResumeActivityItem extends ActivityLifecycleItem {
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
- client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
+ client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -128,7 +130,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem {
mIsForward = in.readBoolean();
}
- public static final @android.annotation.NonNull Creator<ResumeActivityItem> CREATOR =
+ public static final @NonNull Creator<ResumeActivityItem> CREATOR =
new Creator<ResumeActivityItem>() {
public ResumeActivityItem createFromParcel(Parcel in) {
return new ResumeActivityItem(in);
diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java
index 4fbe02b9cf76..ae0bd24218fb 100644
--- a/core/java/android/app/servertransaction/StartActivityItem.java
+++ b/core/java/android/app/servertransaction/StartActivityItem.java
@@ -18,8 +18,9 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Trace;
@@ -32,10 +33,10 @@ public class StartActivityItem extends ActivityLifecycleItem {
private static final String TAG = "StartActivityItem";
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem");
- client.handleStartActivity(token, pendingActions);
+ client.handleStartActivity(r, pendingActions);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -79,7 +80,7 @@ public class StartActivityItem extends ActivityLifecycleItem {
// Empty
}
- public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR =
+ public static final @NonNull Creator<StartActivityItem> CREATOR =
new Creator<StartActivityItem>() {
public StartActivityItem createFromParcel(Parcel in) {
return new StartActivityItem(in);
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index 8668bd49c8f5..7708104da16a 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -18,6 +18,8 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
@@ -34,10 +36,10 @@ public class StopActivityItem extends ActivityLifecycleItem {
private int mConfigChanges;
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
- client.handleStopActivity(token, mConfigChanges, pendingActions,
+ client.handleStopActivity(r, mConfigChanges, pendingActions,
true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -93,7 +95,7 @@ public class StopActivityItem extends ActivityLifecycleItem {
mConfigChanges = in.readInt();
}
- public static final @android.annotation.NonNull Creator<StopActivityItem> CREATOR =
+ public static final @NonNull Creator<StopActivityItem> CREATOR =
new Creator<StopActivityItem>() {
public StopActivityItem createFromParcel(Parcel in) {
return new StopActivityItem(in);
diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
index c7e4c3641631..345c1dd336ab 100644
--- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
+++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
@@ -17,7 +17,9 @@ package android.app.servertransaction;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import android.annotation.NonNull;
import android.app.ActivityTaskManager;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.os.Parcel;
@@ -28,15 +30,15 @@ import android.os.Trace;
* Top resumed activity changed callback.
* @hide
*/
-public class TopResumedActivityChangeItem extends ClientTransactionItem {
+public class TopResumedActivityChangeItem extends ActivityTransactionItem {
private boolean mOnTop;
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
+ public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem");
- client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem");
+ client.handleTopResumedActivityChanged(r, mOnTop, "topResumedActivityChangeItem");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -97,16 +99,16 @@ public class TopResumedActivityChangeItem extends ClientTransactionItem {
mOnTop = in.readBoolean();
}
- public static final @android.annotation.NonNull Creator<TopResumedActivityChangeItem> CREATOR =
+ public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR =
new Creator<TopResumedActivityChangeItem>() {
- public TopResumedActivityChangeItem createFromParcel(Parcel in) {
- return new TopResumedActivityChangeItem(in);
- }
-
- public TopResumedActivityChangeItem[] newArray(int size) {
- return new TopResumedActivityChangeItem[size];
- }
- };
+ public TopResumedActivityChangeItem createFromParcel(Parcel in) {
+ return new TopResumedActivityChangeItem(in);
+ }
+
+ public TopResumedActivityChangeItem[] newArray(int size) {
+ return new TopResumedActivityChangeItem[size];
+ }
+ };
@Override
public boolean equals(Object o) {
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 17fcda587322..3dcf2cb5f13e 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -218,29 +218,29 @@ public class TransactionExecutor {
null /* customIntent */);
break;
case ON_START:
- mTransactionHandler.handleStartActivity(r.token, mPendingActions);
+ mTransactionHandler.handleStartActivity(r, mPendingActions);
break;
case ON_RESUME:
- mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
+ mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
break;
case ON_PAUSE:
- mTransactionHandler.handlePauseActivity(r.token, false /* finished */,
+ mTransactionHandler.handlePauseActivity(r, false /* finished */,
false /* userLeaving */, 0 /* configChanges */, mPendingActions,
"LIFECYCLER_PAUSE_ACTIVITY");
break;
case ON_STOP:
- mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */,
+ mTransactionHandler.handleStopActivity(r, 0 /* configChanges */,
mPendingActions, false /* finalStateRequest */,
"LIFECYCLER_STOP_ACTIVITY");
break;
case ON_DESTROY:
- mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
+ mTransactionHandler.handleDestroyActivity(r, false /* finishing */,
0 /* configChanges */, false /* getNonConfigInstance */,
"performLifecycleSequence. cycling to:" + path.get(size - 1));
break;
case ON_RESTART:
- mTransactionHandler.performRestartActivity(r.token, false /* start */);
+ mTransactionHandler.performRestartActivity(r, false /* start */);
break;
default:
throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 000e870369db..896a53486311 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -25,14 +25,14 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.testng.Assert.assertFalse;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
+import android.app.ActivityThread.ActivityClientRecord;
import android.app.IApplicationThread;
import android.app.PictureInPictureParams;
import android.app.ResourcesManager;
@@ -114,11 +114,12 @@ public class ActivityThreadTest {
final ActivityThread activityThread = activity.getActivityThread();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
activityThread.executeTransaction(newResumeTransaction(activity));
- assertNull(activityThread.performResumeActivity(activity.getActivityToken(),
- true /* finalStateRequest */, "test"));
+ final ActivityClientRecord r = getActivityClientRecord(activity);
+ assertFalse(activityThread.performResumeActivity(r, true /* finalStateRequest */,
+ "test"));
- assertNull(activityThread.performResumeActivity(activity.getActivityToken(),
- false /* finalStateRequest */, "test"));
+ assertFalse(activityThread.performResumeActivity(r, false /* finalStateRequest */,
+ "test"));
});
}
@@ -244,20 +245,18 @@ public class ActivityThreadTest {
newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
newerConfig.seq = seq + 2;
- activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
- newerConfig);
+ final ActivityClientRecord r = getActivityClientRecord(activity);
+ activityThread.updatePendingActivityConfiguration(r, newerConfig);
final Configuration olderConfig = new Configuration();
olderConfig.orientation = orientation;
olderConfig.seq = seq + 1;
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
- olderConfig, INVALID_DISPLAY);
+ activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY);
assertEquals(numOfConfig, activity.mNumOfConfigChanges);
assertEquals(olderConfig.orientation, activity.mConfig.orientation);
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
- newerConfig, INVALID_DISPLAY);
+ activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY);
assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
assertEquals(newerConfig.orientation, activity.mConfig.orientation);
});
@@ -274,7 +273,7 @@ public class ActivityThreadTest {
config.seq = BASE_SEQ;
config.orientation = ORIENTATION_PORTRAIT;
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+ activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity),
config, INVALID_DISPLAY);
});
@@ -335,8 +334,8 @@ public class ActivityThreadTest {
config.seq = BASE_SEQ;
config.orientation = ORIENTATION_PORTRAIT;
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
- config, INVALID_DISPLAY);
+ final ActivityClientRecord r = getActivityClientRecord(activity);
+ activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
});
final int numOfConfig = activity.mNumOfConfigChanges;
@@ -513,9 +512,10 @@ public class ActivityThreadTest {
startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_ENTER, true);
final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
final ActivityThread activityThread = activity.getActivityThread();
+ final ActivityClientRecord r = getActivityClientRecord(activity);
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ activityThread.handlePictureInPictureRequested(r);
});
assertTrue(activity.pipRequested());
@@ -528,9 +528,10 @@ public class ActivityThreadTest {
startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_SKIP, true);
final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
final ActivityThread activityThread = activity.getActivityThread();
+ final ActivityClientRecord r = getActivityClientRecord(activity);
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ activityThread.handlePictureInPictureRequested(r);
});
assertTrue(activity.pipRequested());
@@ -541,9 +542,10 @@ public class ActivityThreadTest {
public void testHandlePictureInPictureRequested_notOverridden() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
final ActivityThread activityThread = activity.getActivityThread();
+ final ActivityClientRecord r = getActivityClientRecord(activity);
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ activityThread.handlePictureInPictureRequested(r);
});
assertTrue(activity.pipRequested());
@@ -552,8 +554,9 @@ public class ActivityThreadTest {
}
/**
- * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
- * to try to push activity configuration to the activity for the given sequence number.
+ * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord,
+ * Configuration, int)} to try to push activity configuration to the activity for the given
+ * sequence number.
* <p>
* It uses orientation to push the configuration and it tries a different orientation if the
* first attempt doesn't make through, to rule out the possibility that the previous
@@ -566,13 +569,13 @@ public class ActivityThreadTest {
*/
private int applyConfigurationChange(TestActivity activity, int seq) {
final ActivityThread activityThread = activity.getActivityThread();
+ final ActivityClientRecord r = getActivityClientRecord(activity);
final int numOfConfig = activity.mNumOfConfigChanges;
Configuration config = new Configuration();
config.orientation = ORIENTATION_PORTRAIT;
config.seq = seq;
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
- INVALID_DISPLAY);
+ activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
if (activity.mNumOfConfigChanges > numOfConfig) {
return config.seq;
@@ -581,12 +584,17 @@ public class ActivityThreadTest {
config = new Configuration();
config.orientation = ORIENTATION_LANDSCAPE;
config.seq = seq + 1;
- activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
- INVALID_DISPLAY);
+ activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
return config.seq;
}
+ private static ActivityClientRecord getActivityClientRecord(Activity activity) {
+ final ActivityThread thread = activity.getActivityThread();
+ final IBinder token = activity.getActivityToken();
+ return thread.getActivityClient(token);
+ }
+
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
null, 0, new MergedConfiguration(), false /* preserveWindow */);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 3c32c71cf961..6a0105cf7ff0 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -32,11 +32,12 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Activity;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
@@ -225,6 +226,7 @@ public class TransactionExecutorTests {
when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
IBinder token = mock(IBinder.class);
+ when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
token /* activityToken */);
@@ -236,9 +238,9 @@ public class TransactionExecutorTests {
mExecutor.execute(transaction);
InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest);
- inOrder.verify(callback1, times(1)).execute(eq(mTransactionHandler), eq(token), any());
- inOrder.verify(callback2, times(1)).execute(eq(mTransactionHandler), eq(token), any());
- inOrder.verify(stateRequest, times(1)).execute(eq(mTransactionHandler), eq(token), any());
+ inOrder.verify(callback1).execute(eq(mTransactionHandler), eq(token), any());
+ inOrder.verify(callback2).execute(eq(mTransactionHandler), eq(token), any());
+ inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
}
@Test
@@ -273,7 +275,7 @@ public class TransactionExecutorTests {
// The launch transaction should not be executed because its token is in the
// to-be-destroyed container.
- verify(launchItem, times(0)).execute(any(), any(), any());
+ verify(launchItem, never()).execute(any(), any(), any());
// After the destroy transaction has been executed, the token should be removed.
mExecutor.execute(destroyTransaction);
@@ -282,6 +284,8 @@ public class TransactionExecutorTests {
@Test
public void testActivityResultRequiredStateResolution() {
+ when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
+
PostExecItem postExecItem = new PostExecItem(ON_RESUME);
IBinder token = mock(IBinder.class);
@@ -292,12 +296,12 @@ public class TransactionExecutorTests {
// Verify resolution that should get to onPause
mClientRecord.setState(ON_RESUME);
mExecutor.executeCallbacks(transaction);
- verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
+ verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
// Verify resolution that should get to onStart
mClientRecord.setState(ON_STOP);
mExecutor.executeCallbacks(transaction);
- verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
+ verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
}
@Test
@@ -433,6 +437,38 @@ public class TransactionExecutorTests {
mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testActivityItemNullRecordThrowsException() {
+ final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
+ when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
+ final IBinder token = mock(IBinder.class);
+ final ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
+ token /* activityToken */);
+ transaction.addCallback(activityItem);
+ when(mTransactionHandler.getActivityClient(token)).thenReturn(null);
+
+ mExecutor.executeCallbacks(transaction);
+ }
+
+ @Test
+ public void testActivityItemExecute() {
+ final IBinder token = mock(IBinder.class);
+ final ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
+ token /* activityToken */);
+ final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
+ when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
+ transaction.addCallback(activityItem);
+ final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+ transaction.setLifecycleStateRequest(stateRequest);
+ when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
+
+ mExecutor.execute(transaction);
+
+ final InOrder inOrder = inOrder(activityItem, stateRequest);
+ inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any());
+ inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
+ }
+
private static int[] shuffledArray(int[] inputArray) {
final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList());
Collections.shuffle(list);
@@ -489,13 +525,13 @@ public class TransactionExecutorTests {
public static final Parcelable.Creator<StubItem> CREATOR =
new Parcelable.Creator<StubItem>() {
- public StubItem createFromParcel(Parcel in) {
- return new StubItem(in);
- }
-
- public StubItem[] newArray(int size) {
- return new StubItem[size];
- }
- };
+ public StubItem createFromParcel(Parcel in) {
+ return new StubItem(in);
+ }
+
+ public StubItem[] newArray(int size) {
+ return new StubItem[size];
+ }
+ };
}
}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 1cdc75aa1f40..3f2d0f134443 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -176,27 +176,27 @@ public class ActivityThreadClientTest {
}
private void startActivity(ActivityClientRecord r) {
- mThread.handleStartActivity(r.token, null /* pendingActions */);
+ mThread.handleStartActivity(r, null /* pendingActions */);
}
private void resumeActivity(ActivityClientRecord r) {
- mThread.handleResumeActivity(r.token, true /* finalStateRequest */,
+ mThread.handleResumeActivity(r, true /* finalStateRequest */,
true /* isForward */, "test");
}
private void pauseActivity(ActivityClientRecord r) {
- mThread.handlePauseActivity(r.token, false /* finished */,
+ mThread.handlePauseActivity(r, false /* finished */,
false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */,
"test");
}
private void stopActivity(ActivityClientRecord r) {
- mThread.handleStopActivity(r.token, 0 /* configChanges */,
+ mThread.handleStopActivity(r, 0 /* configChanges */,
new PendingTransactionActions(), false /* finalStateRequest */, "test");
}
private void destroyActivity(ActivityClientRecord r) {
- mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */,
+ mThread.handleDestroyActivity(r, true /* finishing */, 0 /* configChanges */,
false /* getNonConfigInstance */, "test");
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 403f225032e9..8204b36bc551 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -251,7 +251,6 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.SystemServiceManager;
import com.android.server.UiThread;
import com.android.server.Watchdog;