ActivityOptions副屏启动
android12-release
1、ActivityOptions
帮助程序类,用于构建可与
Context.startActivity(Intent, Bundle)
和相关方法一起使用的选项。
frameworks/base/core/java/android/app/ActivityOptions.java
// 使用ActivityOptions指定显示屏幕
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(1); //这里display0是第一块屏;display1是第二块屏
Intent secondIntent = new Intent();
ComponentName cn= new ComponentName("com.android.demo","com.android.demo.SecondActivity");
secondIntent .setComponent(cn);
//该句很重要,不添加则无法推送到副屏,为Intent增加标志 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK
secondIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(secondIntent, options.toBundle());
查看 ActivityOptions#toBundle()
:b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
其中mLaunchDisplayId
就是设置的显示屏幕
/**
* Returns the created options as a Bundle, which can be passed to
* {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
* Context.startActivity(Intent, Bundle)} and related methods.
* Note that the returned Bundle is still owned by the ActivityOptions
* object; you must not modify it, but can supply it to the startActivity
* methods that take an options Bundle.
*/
public Bundle toBundle() {
Bundle b = new Bundle();
if (mPackageName != null) {
b.putString(KEY_PACKAGE_NAME, mPackageName);
}
if (mLaunchBounds != null) {
b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
}
if (mAnimationType != ANIM_UNDEFINED) {
b.putInt(KEY_ANIM_TYPE, mAnimationType);
}
if (mUsageTimeReport != null) {
b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
}
switch (mAnimationType) {
case ANIM_CUSTOM:
b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
!= null ? mAnimationStartedListener.asBinder() : null);
break;
case ANIM_CUSTOM_IN_PLACE:
b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
break;
case ANIM_SCALE_UP:
case ANIM_CLIP_REVEAL:
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
b.putInt(KEY_ANIM_WIDTH, mWidth);
b.putInt(KEY_ANIM_HEIGHT, mHeight);
break;
case ANIM_THUMBNAIL_SCALE_UP:
case ANIM_THUMBNAIL_SCALE_DOWN:
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
// Once we parcel the thumbnail for transfering over to the system, create a copy of
// the bitmap to a hardware bitmap and pass through the HardwareBuffer
if (mThumbnail != null) {
final Bitmap hwBitmap = mThumbnail.copy(Config.HARDWARE, false /* isMutable */);
if (hwBitmap != null) {
b.putParcelable(KEY_ANIM_THUMBNAIL, hwBitmap.getHardwareBuffer());
} else {
Slog.w(TAG, "Failed to copy thumbnail");
}
}
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
b.putInt(KEY_ANIM_WIDTH, mWidth);
b.putInt(KEY_ANIM_HEIGHT, mHeight);
b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
!= null ? mAnimationStartedListener.asBinder() : null);
break;
case ANIM_SCENE_TRANSITION:
if (mTransitionReceiver != null) {
b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
}
b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
b.putParcelable(KEY_RESULT_DATA, mResultData);
b.putInt(KEY_RESULT_CODE, mResultCode);
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
if (mLockTaskMode) {
b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
}
if (mLaunchDisplayId != INVALID_DISPLAY) {
b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
}
if (mCallerDisplayId != INVALID_DISPLAY) {
b.putInt(KEY_CALLER_DISPLAY_ID, mCallerDisplayId);
}
if (mLaunchTaskDisplayArea != null) {
b.putParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN, mLaunchTaskDisplayArea);
}
if (mLaunchRootTask != null) {
b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
}
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
}
if (mLaunchActivityType != ACTIVITY_TYPE_UNDEFINED) {
b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
}
if (mLaunchTaskId != -1) {
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
}
if (mPendingIntentLaunchFlags != 0) {
b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
}
if (mTaskAlwaysOnTop) {
b.putBoolean(KEY_TASK_ALWAYS_ON_TOP, mTaskAlwaysOnTop);
}
if (mTaskOverlay) {
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
}
if (mTaskOverlayCanResume) {
b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
}
if (mAvoidMoveToFront) {
b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
}
if (mFreezeRecentTasksReordering) {
b.putBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, mFreezeRecentTasksReordering);
}
if (mDisallowEnterPictureInPictureWhileLaunching) {
b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
mDisallowEnterPictureInPictureWhileLaunching);
}
if (mApplyActivityFlagsForBubbles) {
b.putBoolean(KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES, mApplyActivityFlagsForBubbles);
}
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
}
if (mAnimationFinishedListener != null) {
b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
}
if (mSpecsFuture != null) {
b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
}
if (mSourceInfo != null) {
b.putParcelable(KEY_SOURCE_INFO, mSourceInfo);
}
if (mRotationAnimationHint != -1) {
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
}
if (mAppVerificationBundle != null) {
b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
}
if (mRemoteAnimationAdapter != null) {
b.putParcelable(KEY_REMOTE_ANIMATION_ADAPTER, mRemoteAnimationAdapter);
}
if (mLaunchCookie != null) {
b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie);
}
if (mRemoteTransition != null) {
b.putBinder(KEY_REMOTE_TRANSITION, mRemoteTransition.asBinder());
}
if (mOverrideTaskTransition) {
b.putBoolean(KEY_OVERRIDE_TASK_TRANSITION, mOverrideTaskTransition);
}
if (mSplashScreenThemeResName != null && !mSplashScreenThemeResName.isEmpty()) {
b.putString(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResName);
}
if (mRemoveWithTaskOrganizer) {
b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
}
if (mLaunchedFromBubble) {
b.putBoolean(KEY_LAUNCHED_FROM_BUBBLE, mLaunchedFromBubble);
}
if (mTransientLaunch) {
b.putBoolean(KEY_TRANSIENT_LAUNCH, mTransientLaunch);
}
if (mSplashScreenStyle != 0) {
b.putInt(KEY_SPLASH_SCREEN_STYLE, mSplashScreenStyle);
}
return b;
}
2、ActivityStarter转化为SafeActivityOptions
应用启动流程查看 AMS:startActivity桌面启动应用;其中ActivityStarter.java#setActivityOptions(bOptions)
设置
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
ActivityStarter setActivityOptions(SafeActivityOptions options) {
mRequest.activityOptions = options;
return this;
}
ActivityStarter setActivityOptions(Bundle bOptions) {
return setActivityOptions(SafeActivityOptions.fromBundle(bOptions));
}
frameworks/base/services/core/java/com/android/server/wm/SafeActivityOptions.java
public static SafeActivityOptions fromBundle(Bundle bOptions) {
return bOptions != null
? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions))
: null;
}
2.1 Request.activityOptions
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
ActivityStarter setActivityOptions(SafeActivityOptions options) {
mRequest.activityOptions = options;
return this;
}
2.2 ActivityRecord.mOptions
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession != null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
Builder setActivityOptions(ActivityOptions options) {
mOptions = options;
return this;
}
2.3 mTargetRootTask
根据
displayId
找到目标DisplayContent、TaskDisplayArea、Task
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
if (mTargetRootTask == null) {
mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
private Task getLaunchRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
// We are reusing a task, keep the root task!
if (mReuseTask != null) {
return mReuseTask.getRootTask();
}
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, mSourceRootTask, onTop,
mLaunchParams, launchFlags, mRequest.realCallingPid, mRequest.realCallingUid);
}
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
/**
* Returns the right root task to use for launching factoring in all the input parameters.
*
* @param r The activity we are trying to launch. Can be null.
* @param options The activity options used to the launch. Can be null.
* @param candidateTask The possible task the activity might be launched in. Can be null.
* @param sourceTask The task requesting to start activity. Can be null.
* @param launchParams The resolved launch params to use.
* @param launchFlags The launch flags for this launch.
* @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
* @return The root task to use for the launch or INVALID_TASK_ID.
*/
Task getLaunchRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags,
int realCallingPid, int realCallingUid) {
int taskId = INVALID_TASK_ID;
int displayId = INVALID_DISPLAY;
TaskDisplayArea taskDisplayArea = null;
// We give preference to the launch preference in activity options.
if (options != null) {
taskId = options.getLaunchTaskId();
displayId = options.getLaunchDisplayId();
final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
taskDisplayArea = daToken != null
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
final Task rootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
if (rootTask != null) {
return rootTask;
}
}
// First preference for root task goes to the task Id set in the activity options. Use
// the root task associated with that if possible.
if (taskId != INVALID_TASK_ID) {
// Temporarily set the task id to invalid in case in re-entry.
options.setLaunchTaskId(INVALID_TASK_ID);
final Task task = anyTaskForId(taskId,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
options.setLaunchTaskId(taskId);
if (task != null) {
return task.getRootTask();
}
}
final int activityType = resolveActivityType(r, options, candidateTask);
Task rootTask = null;
// Next preference for root task goes to the taskDisplayArea candidate.
if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) {
taskDisplayArea = launchParams.mPreferredTaskDisplayArea;
}
if (taskDisplayArea == null && displayId != INVALID_DISPLAY) {
final DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
}
}
if (taskDisplayArea != null) {
final int tdaDisplayId = taskDisplayArea.getDisplayId();
final boolean canLaunchOnDisplayFromStartRequest =
realCallingPid != 0 && realCallingUid > 0 && r != null
&& mTaskSupervisor.canPlaceEntityOnDisplay(tdaDisplayId,
realCallingPid, realCallingUid, r.info);
if (canLaunchOnDisplayFromStartRequest || canLaunchOnDisplay(r, tdaDisplayId)) {
if (r != null) {
final Task result = getValidLaunchRootTaskInTaskDisplayArea(
taskDisplayArea, r, candidateTask, options, launchParams);
if (result != null) {
return result;
}
}
// Falling back to default task container
taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea();
rootTask = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
if (rootTask != null) {
return rootTask;
}
}
}
// Give preference to the root task and display of the input task and activity if they
// match the mode we want to launch into.
TaskDisplayArea container = null;
if (candidateTask != null) {
rootTask = candidateTask.getRootTask();
}
if (rootTask == null && r != null) {
rootTask = r.getRootTask();
}
int windowingMode = launchParams != null ? launchParams.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
if (rootTask != null) {
container = rootTask.getDisplayArea();
if (container != null && canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
windowingMode = container.resolveWindowingMode(r, options, candidateTask,
activityType);
}
// Always allow organized tasks that created by organizer since the activity type
// of an organized task is decided by the activity type of its top child, which
// could be incompatible with the given windowing mode and activity type.
if (rootTask.isCompatible(windowingMode, activityType)
|| rootTask.mCreatedByOrganizer) {
return rootTask;
}
}
}
if (container == null
|| !canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
container = getDefaultTaskDisplayArea();
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
windowingMode = container.resolveWindowingMode(r, options, candidateTask,
activityType);
}
}
return container.getOrCreateRootTask(r, options, candidateTask, sourceTask, launchParams,
launchFlags, activityType, onTop);
}
3、应用相关Context
3.1 Application中Context
Application 创建
ActivityThread.java#handleBindApplication -> LoadedApk.java#makeApplication
;所以Application中Context
为ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
,其中DispalyId
没有设置
frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
final java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
// Rewrite the R 'constants' for all library apks.
SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
false, false);
for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) {
continue;
}
rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// The network security config needs to be aware of multiple
// applications in the same process to handle discrepancies
NetworkSecurityConfigProvider.handleNewApplication(appContext);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ " package " + mPackageName + ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return app;
}
frameworks/base/core/java/android/app/Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
3.2 Activity中Context
Activity中Context
在activity.attach()
设置,所以Application中Context
为ContextImpl appContext = createBaseContextForActivity(r);
,即在ContextImpl.createActivityContext()
设置DispalyId
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
appContext.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config =
new Configuration(mConfigurationController.getCompatConfiguration());
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
// Activity resources must be initialized with the same loaders as the
// application context.
appContext.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
appContext.setOuterContext(activity);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken, r.shareableActivityToken);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
if (r.mActivityOptions != null) {
activity.mPendingOptions = r.mActivityOptions;
r.mActivityOptions = null;
}
activity.mLaunchedFromBubble = r.mLaunchedFromBubble;
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
mLastReportedWindowingMode.put(activity.getActivityToken(),
config.windowConfiguration.getWindowingMode());
}
r.setState(ON_CREATE);
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
mActivities.put(r.token, r);
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
// The rotation adjustments must be applied before creating the activity, so the activity
// can get the adjusted display info during creation.
if (r.mPendingFixedRotationAdjustments != null) {
// The adjustments should have been set by handleLaunchActivity, so the last one is the
// override for activity resources.
if (mActiveRotationAdjustments != null && !mActiveRotationAdjustments.isEmpty()) {
mResourcesManager.overrideTokenDisplayAdjustments(r.token,
mActiveRotationAdjustments.get(
mActiveRotationAdjustments.size() - 1).second);
}
r.mPendingFixedRotationAdjustments = null;
}
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getResources());
appContext = (ContextImpl) appContext.createDisplayContext(display);
break;
}
}
}
return appContext;
}