publicvoidstartActivityForResult(Intent intent, int requestCode){ if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { // If this start is requesting a result, we can avoid making // the activity visible until the result is received. Setting // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the // activity hidden during this time, to avoid flickering. // This can only be done when a result is requested because // that guarantees we will get information back when the // activity is finished, no matter what happens to it. mStartedActivity = true; } } else { mParent.startActivityFromChild(this, intent, requestCode); } }
ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) { int index = indexOfTokenLocked(resultTo); if (DEBUG_RESULTS) Slog.v( TAG, "Sending result to " + resultTo + " (index " + index + ")"); if (index >= 0) { sourceRecord = (ActivityRecord)mHistory.get(index); if (requestCode >= 0 && !sourceRecord.finishing) { resultRecord = sourceRecord; } } }
int launchFlags = intent.getFlags();
if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { return START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; resultWho = sourceRecord.resultWho; requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { resultRecord.removeResultsLocked( sourceRecord, resultWho, requestCode); } } ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified);
finalintstartActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, Uri[] grantedUriPermissions, int grantedMode, boolean onlyIfNeeded, boolean doResume){ final Intent intent = r.intent; finalint callingUid = r.launchedFromUid; int launchFlags = intent.getFlags(); // If the caller has asked not to resume at this point, we make note // of this in the record so that we can skip it when trying to find // the top running activity. if (!doResume) { r.delayedResume = true; } ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
boolean addingToTask = false; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(intent, r.info) : findActivityLocked(intent, r.info); if (taskTop != null) { } } }
if (r.packageName != null) { // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { if (top.app != null && top.app.thread != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task); // For paranoia, make sure we have correctly // resumed the top activity. if (doResume) { resumeTopActivityLocked(null); } if (onlyIfNeeded) { // We don't need to start a new activity, and // the client said not to do anything if that // is the case, so this is it! return START_RETURN_INTENT_TO_CALLER; } top.deliverNewIntentLocked(callingUid, r.intent); return START_DELIVERED_TO_TOP; } } } }
// Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // todo: should do better management of integers. mService.mCurTask++; if (mService.mCurTask <= 0) { mService.mCurTask = 1; } r.task = new TaskRecord(mService.mCurTask, r.info, intent, (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); newTask = true; if (mMainStack) { mService.addRecentTaskLocked(r.task); } } elseif (sourceRecord != null) { } else { }
int addPos = -1; if (!newTask) { // If starting in an existing task, find where that is... boolean startIt = true; for (int i = NH-1; i >= 0; i--) { ActivityRecord p = (ActivityRecord)mHistory.get(i); if (p.finishing) { continue; } if (p.task == r.task) { // Here it is! Now, if this is not yet visible to the // user, then just add it without starting; it will // get started when the user navigates back to it. addPos = i+1; if (!startIt) { mHistory.add(addPos, r); r.inHistory = true; r.task.numActivities++; mService.mWindowManager.addAppToken(addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen); if (VALIDATE_TOKENS) { mService.mWindowManager.validateAppTokens(mHistory); } return; } break; } if (p.fullscreen) { startIt = false; } } }
if (doResume) { resumeTopActivityLocked(null); } }
finalbooleanresumeTopActivityLocked(ActivityRecord prev){ // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding. finalboolean userLeaving = mUserLeaving; mUserLeaving = false;
if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { return mService.startHomeActivityLocked(); } }
next.delayedResume = false;
// We need to start pausing the current activity so the top one // can be resumed... if (mResumedActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing"); startPausingLocked(userLeaving, false); returntrue; }
privatefinalvoidhandlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges){ ActivityClientRecord r = mActivities.get(token); if (r != null) { //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r); if (userLeaving) { performUserLeavingActivity(r); }
r.activity.mConfigChangeFlags |= configChanges; Bundle state = performPauseActivity(token, finished, true);
// Make sure any pending writes are now committed. QueuedWork.waitToFinish(); // Tell the activity manager we have paused. try { ActivityManagerNative.getDefault().activityPaused(token, state); } catch (RemoteException ex) { } } }
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished, boolean saveState){ if (r.paused) { if (r.activity.mFinished) { returnnull; } } Bundle state = null; if (finished) { r.activity.mFinished = true; } try { // Next have the activity save its current state and managed dialogs... if (!r.activity.mFinished && saveState) { state = new Bundle(); mInstrumentation.callActivityOnSaveInstanceState(r.activity, state); r.state = state; } // Now we are idle. r.activity.mCalled = false; mInstrumentation.callActivityOnPause(r.activity); EventLog.writeEvent(LOG_ON_PAUSE_CALLED, r.activity.getComponentName().getClassName()); if (!r.activity.mCalled) { thrownew SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPause()"); }
finalbooleanresumeTopActivityLocked(ActivityRecord prev){ // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding. finalboolean userLeaving = mUserLeaving; mUserLeaving = false;
if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { return mService.startHomeActivityLocked(); } }
next.delayedResume = false;
// The activity may be waiting for stop, but that is no longer // appropriate for it. mStoppingActivities.remove(next); mWaitingVisibleActivities.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything // until that is done. if (mPausingActivity != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity); returnfalse; }
if (next.app != null && next.app.thread != null) {
} else { // Whoops, need to restart this activity! if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { mService.mWindowManager.setAppStartingWindow( next, next.packageName, next.theme, next.nonLocalizedLabel, next.labelRes, next.icon, null, true); } if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next); } startSpecificActivityLocked(next, true, true); }
// Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, "Attach application locked removing on hold: " + app); mProcessesOnHold.remove(app);
// See if the top visible activity is waiting to run in this process... ActivityRecord hr = mMainStack.topRunningActivityLocked(null); if (hr != null && normalMode) { if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid && processName.equals(hr.processName)) { try { if (mMainStack.realStartActivityLocked(hr, app, true, true)) { didSomething = true; } } catch (Exception e) { } } else { } }