diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index c9b8501816690..72408b67de410 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -544,10 +544,8 @@ public class ActivityStartController { if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) { - if (!dumped) { - dumped = true; - dumpLastHomeActivityStartResult(pw, prefix); - } + dumped = true; + dumpLastHomeActivityStartResult(pw, prefix); pw.print(prefix); pw.println("mLastHomeActivityStartRecord:"); mLastHomeActivityStartRecord.dump(pw, prefix + " ", true /* dumpAll */); @@ -565,6 +563,7 @@ public class ActivityStartController { dumpLastHomeActivityStartResult(pw, prefix); } pw.print(prefix); + pw.println("mLastStarter:"); mLastStarter.dump(pw, prefix + " "); if (dumpPackagePresent) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 1cfa8a38a18f4..714aa5f404fbc 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -614,6 +614,9 @@ class ActivityStarter { mVoiceInteractor = starter.mVoiceInteractor; mIntentDelivered = starter.mIntentDelivered; + mLastStartActivityResult = starter.mLastStartActivityResult; + mLastStartActivityTimeMs = starter.mLastStartActivityTimeMs; + mLastStartReason = starter.mLastStartReason; mRequest.set(starter.mRequest); } @@ -1599,7 +1602,6 @@ class ActivityStarter { TaskFragment inTaskFragment, boolean restrictedBgActivity, NeededUriGrants intentGrants) { int result = START_CANCELED; - boolean startResultSuccessful = false; final Task startedActivityRootTask; // Create a transition now to record the original intent of actions taken within @@ -1615,75 +1617,18 @@ class ActivityStarter { newTransition.setRemoteTransition(remoteTransition); } transitionController.collect(r); - final boolean isTransient = r.getOptions() != null && r.getOptions().getTransientLaunch(); try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity, intentGrants); - startResultSuccessful = ActivityManager.isStartResultSuccessful(result); - final boolean taskAlwaysOnTop = options != null && options.getTaskAlwaysOnTop(); - // Apply setAlwaysOnTop when starting an Activity is successful regardless of creating - // a new Activity or recycling the existing Activity. - if (taskAlwaysOnTop && startResultSuccessful) { - final Task targetRootTask = - mTargetRootTask != null ? mTargetRootTask : mTargetTask.getRootTask(); - targetRootTask.setAlwaysOnTop(true); - } } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); - startedActivityRootTask = handleStartResult(r, result); + startedActivityRootTask = handleStartResult(r, options, result, newTransition, + remoteTransition); mService.continueWindowLayout(); - mSupervisor.mUserLeaving = false; - - // Transition housekeeping - if (!startResultSuccessful) { - if (newTransition != null) { - newTransition.abort(); - } - } else { - if (!mAvoidMoveToFront && mDoResume - && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade( - r.launchedFromUid)) { - // If the UID launching the activity has a visible window on top of the - // notification shade and it's launching an activity that's going to be at the - // front, we should move the shade out of the way so the user can see it. - // We want to avoid the case where the activity is launched on top of a - // background task which is not moved to the front. - StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal(); - if (statusBar != null) { - // This results in a async call since the interface is one-way - statusBar.collapsePanels(); - } - } - final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT; - if (started) { - // The activity is started new rather than just brought forward, so record - // it as an existence change. - transitionController.collectExistenceChange(r); - } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { - // We just delivered to top, so there isn't an actual transition here - newTransition.abort(); - newTransition = null; - } - if (isTransient) { - // `r` isn't guaranteed to be the actual relevant activity, so we must wait - // until after we launched to identify the relevant activity. - transitionController.setTransientLaunch(mLastStartActivityRecord, - mPriorAboveTask); - } - if (newTransition != null) { - transitionController.requestStartTransition(newTransition, - mTargetTask == null ? r.getTask() : mTargetTask, - remoteTransition, null /* displayChange */); - } else if (started) { - // Make the collecting transition wait until this request is ready. - transitionController.setReady(r, false); - } - } } - postStartActivityProcessing(r, result, startedActivityRootTask); return result; @@ -1695,40 +1640,89 @@ class ActivityStarter { * * @return the root task where the successful started activity resides. */ - private @Nullable Task handleStartResult(@NonNull ActivityRecord started, int result) { + private @Nullable Task handleStartResult(@NonNull ActivityRecord started, + ActivityOptions options, int result, Transition newTransition, + RemoteTransition remoteTransition) { + mSupervisor.mUserLeaving = false; final Task currentRootTask = started.getRootTask(); - Task startedActivityRootTask = currentRootTask != null ? currentRootTask : mTargetRootTask; + final Task startedActivityRootTask = + currentRootTask != null ? currentRootTask : mTargetRootTask; - if (ActivityManager.isStartResultSuccessful(result)) { - if (startedActivityRootTask != null) { - // If there is no state change (e.g. a resumed activity is reparented to top of - // another display) to trigger a visibility/configuration checking, we have to - // update the configuration for changing to different display. - final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity(); - if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) { - mRootWindowContainer.ensureVisibilityAndConfig( - currentTop, currentTop.getDisplayId(), - true /* markFrozenIfConfigChanged */, false /* deferResume */); - } + if (!ActivityManager.isStartResultSuccessful(result) || startedActivityRootTask == null) { + // If we are not able to proceed, disassociate the activity from the task. Leaving an + // activity in an incomplete state can lead to issues, such as performing operations + // without a window container. + if (mStartActivity.getTask() != null) { + mStartActivity.finishIfPossible("startActivity", true /* oomAdj */); + } else if (mStartActivity.getParent() != null) { + mStartActivity.getParent().removeChild(mStartActivity); } - return startedActivityRootTask; + + // Root task should also be detached from display and be removed if it's empty. + if (startedActivityRootTask != null && startedActivityRootTask.isAttached() + && !startedActivityRootTask.hasActivity() + && !startedActivityRootTask.isActivityTypeHome()) { + startedActivityRootTask.removeIfPossible("handleStartResult"); + } + if (newTransition != null) { + newTransition.abort(); + } + return null; } - // If we are not able to proceed, disassociate the activity from the task. Leaving an - // activity in an incomplete state can lead to issues, such as performing operations - // without a window container. - if (mStartActivity.getTask() != null) { - mStartActivity.finishIfPossible("startActivity", true /* oomAdj */); - } else if (mStartActivity.getParent() != null) { - mStartActivity.getParent().removeChild(mStartActivity); + // Apply setAlwaysOnTop when starting an activity is successful regardless of creating + // a new Activity or reusing the existing activity. + if (options != null && options.getTaskAlwaysOnTop()) { + startedActivityRootTask.setAlwaysOnTop(true); } - // Root task should also be detached from display and be removed if it's empty. - if (startedActivityRootTask != null && startedActivityRootTask.isAttached() - && !startedActivityRootTask.hasActivity() - && !startedActivityRootTask.isActivityTypeHome()) { - startedActivityRootTask.removeIfPossible("handleStartResult"); - startedActivityRootTask = null; + // If there is no state change (e.g. a resumed activity is reparented to top of + // another display) to trigger a visibility/configuration checking, we have to + // update the configuration for changing to different display. + final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity(); + if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) { + mRootWindowContainer.ensureVisibilityAndConfig( + currentTop, currentTop.getDisplayId(), + true /* markFrozenIfConfigChanged */, false /* deferResume */); + } + + if (!mAvoidMoveToFront && mDoResume && mRootWindowContainer + .hasVisibleWindowAboveButDoesNotOwnNotificationShade(started.launchedFromUid)) { + // If the UID launching the activity has a visible window on top of the notification + // shade and it's launching an activity that's going to be at the front, we should move + // the shade out of the way so the user can see it. We want to avoid the case where the + // activity is launched on top of a background task which is not moved to the front. + final StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal(); + if (statusBar != null) { + // This results in a async call since the interface is one-way. + statusBar.collapsePanels(); + } + } + + // Transition housekeeping. + final TransitionController transitionController = started.mTransitionController; + final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT; + if (isStarted) { + // The activity is started new rather than just brought forward, so record it as an + // existence change. + transitionController.collectExistenceChange(started); + } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { + // We just delivered to top, so there isn't an actual transition here. + newTransition.abort(); + newTransition = null; + } + if (options != null && options.getTransientLaunch()) { + // `started` isn't guaranteed to be the actual relevant activity, so we must wait + // until after we launched to identify the relevant activity. + transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask); + } + if (newTransition != null) { + transitionController.requestStartTransition(newTransition, + mTargetTask == null ? started.getTask() : mTargetTask, + remoteTransition, null /* displayChange */); + } else if (isStarted) { + // Make the collecting transition wait until this request is ready. + transitionController.setReady(started, false); } return startedActivityRootTask; } @@ -3170,7 +3164,6 @@ class ActivityStarter { } void dump(PrintWriter pw, String prefix) { - prefix = prefix + " "; pw.print(prefix); pw.print("mCurrentUser="); pw.println(mRootWindowContainer.mCurrentUser); @@ -3216,7 +3209,7 @@ class ActivityStarter { pw.print(" mDoResume="); pw.print(mDoResume); pw.print(" mAddingToTask="); - pw.println(mAddingToTask); + pw.print(mAddingToTask); pw.print(" mInTaskFragment="); pw.println(mInTaskFragment); }