}
try {
w.activityResuming(identHash);
} catch (RemoteException e) {
<<<<<<< HEAD
=======
}
}
}
mWatchers.finishBroadcast();
}
/**
* Ensure that the top activity in the stack is resumed.
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
*/
private final boolean resumeTopActivityLocked(HistoryRecord prev) {
// Find the first activity that is not finishing.
HistoryRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
return startHomeActivityLocked();
}
next.delayedResume = false;
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return false;
}
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
if ((mSleeping || mShuttingDown)
&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return 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);
return 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);
return true;
}
if (prev != null && prev != next) {
if (!prev.waitingVisible && next != null && !next.nowVisible) {
prev.waitingVisible = true;
mWaitingVisibleActivities.add(prev);
if (DEBUG_SWITCH) Slog.v(
TAG, "Resuming top, waiting visible to hide: " + prev);
} else {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
// We only do this if the previous is finishing, which should mean
// it is on top of the one being resumed so hiding it quickly
// is good. Otherwise, we want to do the normal route of allowing
// the resumed activity to be shown so we can decide if the
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
mWindowManager.setAppVisibility(prev, false);
if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
+ prev + ", waitingVisible="
+ (prev != null ? prev.waitingVisible : null)
+ ", nowVisible=" + next.nowVisible);
} else {
if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
+ prev + ", waitingVisible="
+ (prev != null ? prev.waitingVisible : null)
+ ", nowVisible=" + next.nowVisible);
}
}
}
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare close transition: prev=" + prev);
if (mNoAnimActivities.contains(prev)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
} else {
mWindowManager.prepareAppTransition(prev.task == next.task
? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
: WindowManagerPolicy.TRANSIT_TASK_CLOSE);
}
mWindowManager.setAppWillBeHidden(prev);
mWindowManager.setAppVisibility(prev, false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: prev=" + prev);
if (mNoAnimActivities.contains(next)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
} else {
mWindowManager.prepareAppTransition(prev.task == next.task
? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
: WindowManagerPolicy.TRANSIT_TASK_OPEN);
}
}
if (false) {
mWindowManager.setAppWillBeHidden(prev);
mWindowManager.setAppVisibility(prev, false);
}
} else if (mHistory.size() > 1) {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
} else {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
}
}
if (next.app != null && next.app.thread != null) {
if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
// This activity is now becoming visible.
mWindowManager.setAppVisibility(next, true);
HistoryRecord lastResumedActivity = mResumedActivity;
ActivityState lastState = next.state;
updateCpuStats();
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
updateLruProcessLocked(next.app, true, true);
updateLRUListLocked(next);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
boolean updated;
synchronized (this) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mConfiguration,
next.mayFreezeScreenLocked(next.app) ? next : null);
if (config != null) {
next.frozenBeforeDestroy = true;
}
updated = updateConfigurationLocked(config, next);
}
if (!updated) {
// The configuration update wasn't able to keep the existing
// instance of the activity, and instead started a new one.
// We should be all done, but let's just make sure our activity
// is still at the top and schedule another run if something
// weird happened.
HistoryRecord nextNext = topRunningActivityLocked(null);
if (DEBUG_SWITCH) Slog.i(TAG,
"Activity config changed during resume: " + next
+ ", new next: " + nextNext);
if (nextNext != next) {
// Do over!
mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
}
setFocusedActivityLocked(next);
ensureActivitiesVisibleLocked(null, 0);
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
return true;
}
try {
// Deliver all pending results.
ArrayList a = next.results;
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
if (DEBUG_RESULTS) Slog.v(
TAG, "Delivering results to " + next
+ ": " + a);
next.app.thread.scheduleSendResult(next, a);
}
}
if (next.newIntents != null) {
next.app.thread.scheduleNewIntent(next.newIntents, next);
}
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
next.app.thread.scheduleResumeActivity(next,
isNextTransitionForward());
pauseIfSleepingLocked();
} catch (Exception e) {
// Whoops, need to restart this activity!
next.state = lastState;
mResumedActivity = lastResumedActivity;
Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_ICON) {
mWindowManager.setAppStartingWindow(
next, next.packageName, next.theme,
next.nonLocalizedLabel,
next.labelRes, next.icon, null, true);
}
}
startSpecificActivityLocked(next, true, false);
return true;
}
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.visible = true;
completeResumeLocked(next);
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
"resume-exception");
return true;
}
// Didn't need to use the icicle, and it is now out of date.
next.icicle = null;
next.haveState = false;
next.stopped = false;
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_ICON) {
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);
}
return true;
}
private final void startActivityLocked(HistoryRecord r, boolean newTask,
boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
// If starting in an existing task, find where that is...
HistoryRecord next = null;
boolean startIt = true;
for (int i = NH-1; i >= 0; i--) {
HistoryRecord p = (HistoryRecord)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++;
mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
if (VALIDATE_TOKENS) {
mWindowManager.validateAppTokens(mHistory);
}
return;
}
break;
}
if (p.fullscreen) {
startIt = false;
}
next = p;
}
}
// Place a new activity at top of stack, so it is next to interact
// with the user.
if (addPos < 0) {
addPos = mHistory.size();
}
// If we are not placing the new activity frontmost, we do not want
// to deliver the onUserLeaving callback to the actual frontmost
// activity
if (addPos < NH) {
mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
}
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
r.inHistory = true;
r.frontOfTask = newTask;
r.task.numActivities++;
if (NH > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
// not currently running.
boolean showStartingIcon = newTask;
ProcessRecord proc = r.app;
if (proc == null) {
proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
}
if (proc == null || proc.thread == null) {
showStartingIcon = true;
}
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
mNoAnimActivities.add(r);
} else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
mNoAnimActivities.remove(r);
} else {
mWindowManager.prepareAppTransition(newTask
? WindowManagerPolicy.TRANSIT_TASK_OPEN
: WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
mNoAnimActivities.remove(r);
}
mWindowManager.addAppToken(
addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
// to reset it to make sure we apply affinities to move any
// existing activities from other tasks in to it.
// If the caller has requested that the target task be
// reset, then do so.
if ((r.intent.getFlags()
&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
}
if (SHOW_APP_STARTING_ICON && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
HistoryRecord prev = mResumedActivity;
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.task != r.task) prev = null;
// (2) The current activity is already displayed.
else if (prev.nowVisible) prev = null;
}
mWindowManager.setAppStartingWindow(
r, r.packageName, r.theme, r.nonLocalizedLabel,
r.labelRes, r.icon, prev, showStartingIcon);
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
}
if (VALIDATE_TOKENS) {
mWindowManager.validateAppTokens(mHistory);
}
if (doResume) {
resumeTopActivityLocked(null);
}
}
/**
* Perform clear operation as requested by
* {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
* stack to the given task, then look for
* an instance of that activity in the stack and, if found, finish all
* activities on top of it and return the instance.
*
* @param newR Description of the new activity being started.
* @return Returns the old activity that should be continue to be used,
* or null if none was found.
*/
private final HistoryRecord performClearTaskLocked(int taskId,
HistoryRecord newR, int launchFlags, boolean doClear) {
int i = mHistory.size();
// First find the requested task.
while (i > 0) {
i--;
HistoryRecord r = (HistoryRecord)mHistory.get(i);
if (r.task.taskId == taskId) {
i++;
break;
}
}
// Now clear it.
while (i > 0) {
i--;
HistoryRecord r = (HistoryRecord)mHistory.get(i);
if (r.finishing) {
continue;
}
if (r.task.taskId != taskId) {
return null;
}
if (r.realActivity.equals(newR.realActivity)) {
// Here it is! Now finish everything in front...
HistoryRecord ret = r;
if (doClear) {
while (i < (mHistory.size()-1)) {
i++;
r = (HistoryRecord)mHistory.get(i);
if (r.finishing) {
continue;
}
if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
null, "clear")) {
i--;
}
}
}
// Finally, if this is a normal launch mode (that is, not
// expecting onNewIntent()), then we will finish the current
// instance of the activity so a new fresh one can be started.
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
int index = indexOfTokenLocked(ret);
if (index >= 0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear");
}
return null;
}
}
return ret;
}
}
return null;
}
/**
* Find the activity in the history stack within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
*/
private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
int i = mHistory.size();
while (i > 0) {
i--;
HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
if (candidate.task.taskId != task) {
break;
}
if (candidate.realActivity.equals(r.realActivity)) {
return i;
}
}
return -1;
}
/**
* Reorder the history stack so that the activity at the given index is
* brought to the front.
*/
private final HistoryRecord moveActivityToFrontLocked(int where) {
HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
int top = mHistory.size();
HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
mHistory.add(top, newTop);
oldTop.frontOfTask = false;
newTop.frontOfTask = true;
return newTop;
}
/**
* Deliver a new Intent to an existing activity, so that its onNewIntent()
* method will be called at the proper time.
*/
private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
boolean sent = false;
if (r.state == ActivityState.RESUMED
&& r.app != null && r.app.thread != null) {
try {
ArrayList ar = new ArrayList();
ar.add(new Intent(intent));
r.app.thread.scheduleNewIntent(ar, r);
sent = true;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending new intent to " + r, e);
}
}
if (!sent) {
r.addNewIntentLocked(new Intent(intent));
}
}
private final void logStartActivity(int tag, HistoryRecord r,
TaskRecord task) {
EventLog.writeEvent(tag,
System.identityHashCode(r), task.taskId,
r.shortComponentName, r.intent.getAction(),
r.intent.getType(), r.intent.getDataString(),
r.intent.getFlags());
private final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified) {
Slog.i(TAG, "Starting activity: " + intent);
HistoryRecord sourceRecord = null;
HistoryRecord 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 = (HistoryRecord)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) {
if (mResumedActivity == null
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);
}
}
int err = START_SUCCESS;
if (intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
err = START_INTENT_NOT_RESOLVED;
}
if (err == START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = START_CLASS_NOT_FOUND;
}
ProcessRecord callerApp = null;
if (err == START_SUCCESS && caller != null) {
callerApp = getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = START_PERMISSION_DENIED;
}
}
if (err != START_SUCCESS) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
return err;
}
final int perm = checkComponentPermission(aInfo.permission, callingPid,
callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
if (perm != PackageManager.PERMISSION_GRANTED) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
String msg = "Permission Denial: starting " + intent.toString()
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires " + aInfo.permission;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (mController != null) {
boolean abort = false;
try {
// The Intent we give to the watcher has the extra data
// stripped off, since it can contain private information.
Intent watchIntent = intent.cloneFilter();
abort = !mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mController = null;
}
if (abort) {
if (resultRecord != null) {
sendActivityResultLocked(-1,
resultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
return START_SUCCESS;
}
}
HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
intent, resolvedType, aInfo, mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
|| mResumedActivity.info.applicationInfo.uid != callingUid) {
if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch();
pal.r = r;
pal.sourceRecord = sourceRecord;
pal.grantedUriPermissions = grantedUriPermissions;
pal.grantedMode = grantedMode;
pal.onlyIfNeeded = onlyIfNeeded;
mPendingActivityLaunches.add(pal);
return START_SWITCHES_CANCELED;
}
}
if (mDidAppSwitch) {
// This is the second allowed switch since we stopped switches,
// so now just generally allow switches. Use case: user presses
// home (switches disabled, switch to home, mDidAppSwitch now true);
// user taps a home icon (coming from home so allowed, we hit here
// and now allow anyone to switch again).
mAppSwitchesAllowedTime = 0;
} else {
mDidAppSwitch = true;
}
doPendingActivityLaunchesLocked(false);
return startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
}
private final void doPendingActivityLaunchesLocked(boolean doResume) {
final int N = mPendingActivityLaunches.size();
if (N <= 0) {
return;
}
for (int i=0; i mUserLeaving=" + mUserLeaving);
// 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;
}
HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if (onlyIfNeeded) {
HistoryRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
checkedCaller = topRunningNonDelayedActivityLocked(notTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.
onlyIfNeeded = false;
}
}
if (grantedUriPermissions != null && callingUid > 0) {
for (int i=0; i= 0) {
HistoryRecord top = moveActivityToFrontLocked(where);
logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
if (doResume) {
resumeTopActivityLocked(null);
}
return START_DELIVERED_TO_TOP;
}
}
// An existing activity is starting this new activity, so we want
// to keep the new one in the same task as the one that is starting
// it.
r.task = sourceRecord.task;
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
// This not being started from an existing activity, and not part
// of a new task... just put it in the top task, though these days
// this case should never happen.
final int N = mHistory.size();
HistoryRecord prev =
N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
r.task = prev != null
? prev.task
: new TaskRecord(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 guessed " + r.task);
}
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
}
logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
startActivityLocked(r, newTask, doResume);
return START_SUCCESS;
}
void reportActivityLaunchedLocked(boolean timeout, HistoryRecord r,
long thisTime, long totalTime) {
for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
WaitResult w = mWaitingActivityLaunched.get(i);
w.timeout = timeout;
if (r != null) {
w.who = new ComponentName(r.info.packageName, r.info.name);
}
w.thisTime = thisTime;
w.totalTime = totalTime;
}
notify();
}
void reportActivityVisibleLocked(HistoryRecord r) {
for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
WaitResult w = mWaitingActivityVisible.get(i);
w.timeout = false;
if (r != null) {
w.who = new ComponentName(r.info.packageName, r.info.name);
}
w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
w.thisTime = w.totalTime;
}
notify();
}
private final int startActivityMayWait(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, WaitResult outResult, Configuration config) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
// Collect information about the target of the Intent.
ActivityInfo aInfo;
try {
ResolveInfo rInfo =
ActivityThread.getPackageManager().resolveIntent(
intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY
| STOCK_PM_FLAGS);
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
}
if (aInfo != null) {
// Store the found target back into the intent, because now that
// we have it we never want to do this again. For example, if the
// user navigates back to this point in the history, we should
// always restart the exact same activity.
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't debug things in the system process
if (debug) {
if (!aInfo.processName.equals("system")) {
setDebugApp(aInfo.processName, true, false);
}
}
}
synchronized (this) {
int callingPid;
int callingUid;
if (caller == null) {
callingPid = Binder.getCallingPid();
callingUid = Binder.getCallingUid();
} else {
callingPid = callingUid = -1;
}
mConfigWillChange = config != null && mConfiguration.diff(config) != 0;
if (DEBUG_CONFIGURATION) Slog.v(TAG,
"Starting activity when config will change = " + mConfigWillChange);
final long origId = Binder.clearCallingIdentity();
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified);
if (mConfigWillChange) {
// If the caller also wants to switch to a new configuration,
// do so now. This allows a clean switch, as we are waiting
// for the current activity to pause (so we will not destroy
// it), and have not yet started the next activity.
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
mConfigWillChange = false;
if (DEBUG_CONFIGURATION) Slog.v(TAG,
"Updating to new configuration after starting activity.");
updateConfigurationLocked(config, null);
}
Binder.restoreCallingIdentity(origId);
if (outResult != null) {
outResult.result = res;
if (res == IActivityManager.START_SUCCESS) {
mWaitingActivityLaunched.add(outResult);
do {
try {
wait();
} catch (InterruptedException e) {
}
} while (!outResult.timeout && outResult.who == null);
} else if (res == IActivityManager.START_TASK_TO_FRONT) {
HistoryRecord r = this.topRunningActivityLocked(null);
if (r.nowVisible) {
outResult.timeout = false;
outResult.who = new ComponentName(r.info.packageName, r.info.name);
outResult.totalTime = 0;
outResult.thisTime = 0;
} else {
outResult.thisTime = SystemClock.uptimeMillis();
mWaitingActivityVisible.add(outResult);
do {
try {
wait();
} catch (InterruptedException e) {
}
} while (!outResult.timeout && outResult.who == null);
}
>>>>>>> b4ae2f1ba419212224d53db81c46ad242bebd17b
}
}
} |