Loading services/core/java/com/android/server/am/ActivityDisplay.java +134 −34 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import static com.android.server.am.proto.ActivityDisplayProto.CONFIGURATION_CON import static com.android.server.am.proto.ActivityDisplayProto.STACKS; import static com.android.server.am.proto.ActivityDisplayProto.ID; import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.util.IntArray; import android.util.Slog; Loading Loading @@ -205,6 +207,18 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return createStack(windowingMode, activityType, onTop); } /** * Returns an existing stack compatible with the input params or creates one * if a compatible stack doesn't exist. * @see #getOrCreateStack(int, int, boolean) */ <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType, boolean onTop) { final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); return getOrCreateStack(windowingMode, activityType, onTop); } /** * Creates a stack matching the input windowing mode and activity type on this display. * @param windowingMode The windowing mode the stack should be created in. If Loading Loading @@ -235,7 +249,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } final ActivityManagerService service = mSupervisor.mService; if (!mSupervisor.isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement, service.mSupportsPictureInPicture, activityType)) { throw new IllegalArgumentException("Can't create stack for unsupported windowingMode=" Loading @@ -252,33 +266,27 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } windowingMode = updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType); final int stackId = mSupervisor.getNextStackId(); final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop); if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Make sure recents stack exist when creating a dock stack as it normally need to be on // the other side of the docked stack and we make visibility decisions based on that. // TODO: Not sure if this is needed after we change to calculate visibility based on // stack z-order vs. id. getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop); } return stack; return createStackUnchecked(windowingMode, activityType, stackId, onTop); } @VisibleForTesting <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { switch (windowingMode) { case WINDOWING_MODE_PINNED: if (windowingMode == WINDOWING_MODE_PINNED) { return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop); default: return (T) new ActivityStack( } final T stack = (T) new ActivityStack( this, stackId, mSupervisor, windowingMode, activityType, onTop); if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Make sure recents stack exist when creating a dock stack as it normally needs to be // on the other side of the docked stack and we make visibility decisions based on that. // TODO: Not sure if this is needed after we change to calculate visibility based on // stack z-order vs. id. getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop); } return stack; } /** Loading Loading @@ -372,6 +380,105 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } /** * Returns true if the {@param windowingMode} is supported based on other parameters passed in. * @param windowingMode The windowing mode we are checking support for. * @param supportsMultiWindow If we should consider support for multi-window mode in general. * @param supportsSplitScreen If we should consider support for split-screen multi-window. * @param supportsFreeform If we should consider support for freeform multi-window. * @param supportsPip If we should consider support for picture-in-picture mutli-window. * @param activityType The activity type under consideration. * @return true if the windowing mode is supported. */ private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType) { if (windowingMode == WINDOWING_MODE_UNDEFINED || windowingMode == WINDOWING_MODE_FULLSCREEN) { return true; } if (!supportsMultiWindow) { return false; } if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType); } if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { return false; } if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { return false; } return true; } int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType) { // First preference if the windowing mode in the activity options if set. int windowingMode = (options != null) ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; // If windowing mode is unset, then next preference is the candidate task, then the // activity record. if (windowingMode == WINDOWING_MODE_UNDEFINED) { if (task != null) { windowingMode = task.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { windowingMode = r.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED) { // Use the display's windowing mode. windowingMode = getWindowingMode(); } } // Make sure the windowing mode we are trying to use makes sense for what is supported. final ActivityManagerService service = mSupervisor.mService; boolean supportsMultiWindow = service.mSupportsMultiWindow; boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow; boolean supportsFreeform = service.mSupportsFreeformWindowManagement; boolean supportsPip = service.mSupportsPictureInPicture; if (supportsMultiWindow) { if (task != null) { supportsMultiWindow = task.isResizeable(); supportsSplitScreen = task.supportsSplitScreenWindowingMode(); // TODO: Do we need to check for freeform and Pip support here? } else if (r != null) { supportsMultiWindow = r.isResizeable(); supportsSplitScreen = r.supportsSplitScreenWindowingMode(); supportsFreeform = r.supportsFreeform(); supportsPip = r.supportsPictureInPicture(); } } final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are // trying to launch in split-screen secondary. windowingMode = WINDOWING_MODE_FULLSCREEN; } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN && supportsSplitScreen) { windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } if (windowingMode != WINDOWING_MODE_UNDEFINED && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, supportsFreeform, supportsPip, activityType)) { return windowingMode; } // Return the display's windowing mode return getWindowingMode(); } /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */ int getTopVisibleStackActivityType(int excludeWindowingMode) { for (int i = mStacks.size() - 1; i >= 0; --i) { Loading Loading @@ -408,6 +515,14 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } /** We are in the process of exiting split-screen mode. */ void onExitingSplitScreenMode() { // Remove reference to the primary-split-screen stack so it no longer has any effect on the // display. For example, we want to be able to create fullscreen stack for standard activity // types when exiting split-screen mode. mSplitScreenPrimaryStack = null; } ActivityStack getSplitScreenPrimaryStack() { return mSplitScreenPrimaryStack; } Loading @@ -424,21 +539,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return mPinnedStack != null; } int updateWindowingModeForSplitScreenIfNeeded(int windowingMode, int activityType) { final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are // trying to launch in split-screen secondary. return WINDOWING_MODE_FULLSCREEN; } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType)) { return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } return windowingMode; } @Override public String toString() { return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; Loading services/core/java/com/android/server/am/ActivityManagerService.java +3 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; Loading Loading @@ -10318,7 +10319,8 @@ public class ActivityManagerService extends IActivityManager.Stub } // TODO(multi-display): Have the caller pass in the windowing mode and activity type. final ActivityStack stack = display.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /*onTop*/); WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, ON_TOP); return (stack != null) ? stack.mStackId : INVALID_STACK_ID; } } services/core/java/com/android/server/am/ActivityRecord.java +12 −4 Original line number Diff line number Diff line Loading @@ -165,6 +165,7 @@ import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.WindowManager.LayoutParams; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; Loading Loading @@ -232,7 +233,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo final String processName; // process where this component wants to run final String taskAffinity; // as per ActivityInfo.taskAffinity final boolean stateNotNeeded; // As per ActivityInfo.flags boolean fullscreen; // covers the full screen? boolean fullscreen; // The activity is opaque and fills the entire space of this task. // TODO: See if it possible to combine this with the fullscreen field. final boolean hasWallpaper; // Has a wallpaper window as a background. final boolean noDisplay; // activity is not displayed? private final boolean componentSpecified; // did caller specify an explicit component? final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? Loading Loading @@ -883,9 +886,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo Entry ent = AttributeCache.instance().get(packageName, realTheme, com.android.internal.R.styleable.Window, userId); fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array); noDisplay = ent != null && ent.array.getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); if (ent != null) { fullscreen = !ActivityInfo.isTranslucentOrFloating(ent.array); hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); } else { hasWallpaper = false; noDisplay = false; } setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord); Loading services/core/java/com/android/server/am/ActivityStack.java +59 −128 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/am/ActivityStackSupervisor.java +38 −131 Original line number Diff line number Diff line Loading @@ -110,7 +110,6 @@ import android.app.AppOpsManager; import android.app.ProfilerInfo; import android.app.ResultInfo; import android.app.WaitResult; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -223,13 +222,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // at the top of its container (e.g. stack). static final boolean ON_TOP = true; // Used to indicate that an objects (e.g. task) removal from its container // (e.g. stack) is due to it moving to another container. static final boolean MOVING = true; // Force the focus to change to the stack we are moving a task to.. static final boolean FORCE_FOCUS = true; // Don't execute any calls to resume. static final boolean DEFER_RESUME = true; Loading Loading @@ -405,6 +397,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * object each time. */ private final Rect tempRect = new Rect(); private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic(); // The default minimal size that will be used if the activity doesn't specify its minimal size. // It will be calculated when the default display gets added. Loading Loading @@ -2186,89 +2179,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } /** * Returns true if the {@param windowingMode} is supported based on other parameters passed in. * @param windowingMode The windowing mode we are checking support for. * @param supportsMultiWindow If we should consider support for multi-window mode in general. * @param supportsSplitScreen If we should consider support for split-screen multi-window. * @param supportsFreeform If we should consider support for freeform multi-window. * @param supportsPip If we should consider support for picture-in-picture mutli-window. * @param activityType The activity type under consideration. * @return true if the windowing mode is supported. */ boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType) { if (windowingMode == WINDOWING_MODE_UNDEFINED || windowingMode == WINDOWING_MODE_FULLSCREEN) { return true; } if (!supportsMultiWindow) { return false; } if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType); } if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { return false; } if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { return false; } return true; } private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType) { // First preference if the windowing mode in the activity options if set. int windowingMode = (options != null) ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; // If windowing mode is unset, then next preference is the candidate task, then the // activity record. if (windowingMode == WINDOWING_MODE_UNDEFINED) { if (task != null) { windowingMode = task.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { windowingMode = r.getWindowingMode(); } } // Make sure the windowing mode we are trying to use makes sense for what is supported. boolean supportsMultiWindow = mService.mSupportsMultiWindow; boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow; boolean supportsFreeform = mService.mSupportsFreeformWindowManagement; boolean supportsPip = mService.mSupportsPictureInPicture; if (supportsMultiWindow) { if (task != null) { supportsMultiWindow = task.isResizeable(); supportsSplitScreen = task.supportsSplitScreenWindowingMode(); // TODO: Do we need to check for freeform and Pip support here? } else if (r != null) { supportsMultiWindow = r.isResizeable(); supportsSplitScreen = r.supportsSplitScreenWindowingMode(); supportsFreeform = r.supportsFreeform(); supportsPip = r.supportsPictureInPicture(); } } if (windowingMode != WINDOWING_MODE_UNDEFINED && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, supportsFreeform, supportsPip, activityType)) { return windowingMode; } // Return root/systems windowing mode return getWindowingMode(); } int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task) { // Preference is given to the activity type for the activity then the task since the type Loading Loading @@ -2329,7 +2239,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final int activityType = resolveActivityType(r, options, candidateTask); int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); T stack = null; // Next preference for stack goes to the display Id set in the activity options or the Loading @@ -2347,7 +2256,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); if (display != null) { stack = display.getOrCreateStack(windowingMode, activityType, onTop); stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop); if (stack != null) { return stack; } Loading @@ -2365,10 +2274,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack = r.getStack(); } if (stack != null) { display = stack.getDisplay(); if (display != null) { final int windowingMode = display.resolveWindowingMode(r, options, candidateTask, activityType); if (stack.isCompatible(windowingMode, activityType)) { return stack; } display = stack.getDisplay(); } } if (display == null Loading @@ -2379,7 +2292,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D display = getDefaultDisplay(); } return display.getOrCreateStack(windowingMode, activityType, onTop); return display.getOrCreateStack(r, options, candidateTask, activityType, onTop); } /** Loading Loading @@ -2596,6 +2509,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId); if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Tell the display we are exiting split-screen mode. toDisplay.onExitingSplitScreenMode(); // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. Loading Loading @@ -2625,35 +2540,34 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ArrayList<TaskRecord> tasks = fromStack.getAllTasks(); if (!tasks.isEmpty()) { mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); final int size = tasks.size(); final ActivityStack fullscreenStack = toDisplay.getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop); for (int i = 0; i < size; ++i) { final TaskRecord task = tasks.get(i); final ActivityStack toStack = toDisplay.getOrCreateStack( null, mTmpOptions, task, task.getActivityType(), onTop); if (onTop) { final int returnToType = toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED); for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); final boolean isTopTask = i == (size - 1); if (inPinnedWindowingMode) { // Update the return-to to reflect where the pinned stack task was moved // from so that we retain the stack that was previously visible if the // pinned stack is recreated. See moveActivityToPinnedStackLocked(). // Update the return-to to reflect where the pinned stack task was // moved from so that we retain the stack that was previously // visible if the pinned stack is recreated. // See moveActivityToPinnedStackLocked(). task.setTaskToReturnTo(returnToType); } // Defer resume until all the tasks have been moved to the fullscreen stack task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, isTopTask /* animate */, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - onTop"); } } else { for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); // Position the tasks in the fullscreen stack in order at the bottom of the // stack. Also defer resume until all the tasks have been moved to the // fullscreen stack. task.reparent(fullscreenStack, i /* position */, task.reparent(toStack, ON_TOP, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - NOT_onTop"); Loading Loading @@ -3080,23 +2994,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D + " task=" + task); } // We don't allow moving a unresizeable task to the docked stack since the docked stack is // used for split-screen mode and will cause things like the docked divider to show up. We // instead leave the task in its current stack or move it to the fullscreen stack if it // isn't currently in a stack. // Leave the task in its current stack or a fullscreen stack if it isn't resizeable and the // preferred stack is in multi-window mode. if (inMultiWindowMode && !task.isResizeable()) { Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack." + " Moving to stackId=" + stackId + " instead."); // Temporarily disable resizeablility of the task as we don't want it to be resized if, // for example, a docked stack is created which will lead to the stack we are moving // from being resized and and its resizeable tasks being resized. try { task.mTemporarilyUnresizable = true; Slog.w(TAG, "Can not move unresizeable task=" + task + " to multi-window stack=" + stack + " Moving to a fullscreen stack instead."); if (prevStack != null) { return prevStack; } stack = stack.getDisplay().createStack( WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop); } finally { task.mTemporarilyUnresizable = false; } } return stack; } Loading Loading @@ -4287,9 +4194,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final boolean isSecondaryDisplayPreferred = (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); final boolean inSplitScreenMode = actualStack != null && actualStack.inSplitScreenWindowingMode(); && actualStack.getDisplay().hasSplitScreenPrimaryStack(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) { && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) { return; } Loading Loading
services/core/java/com/android/server/am/ActivityDisplay.java +134 −34 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import static com.android.server.am.proto.ActivityDisplayProto.CONFIGURATION_CON import static com.android.server.am.proto.ActivityDisplayProto.STACKS; import static com.android.server.am.proto.ActivityDisplayProto.ID; import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.util.IntArray; import android.util.Slog; Loading Loading @@ -205,6 +207,18 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return createStack(windowingMode, activityType, onTop); } /** * Returns an existing stack compatible with the input params or creates one * if a compatible stack doesn't exist. * @see #getOrCreateStack(int, int, boolean) */ <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType, boolean onTop) { final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); return getOrCreateStack(windowingMode, activityType, onTop); } /** * Creates a stack matching the input windowing mode and activity type on this display. * @param windowingMode The windowing mode the stack should be created in. If Loading Loading @@ -235,7 +249,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } final ActivityManagerService service = mSupervisor.mService; if (!mSupervisor.isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement, service.mSupportsPictureInPicture, activityType)) { throw new IllegalArgumentException("Can't create stack for unsupported windowingMode=" Loading @@ -252,33 +266,27 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } windowingMode = updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType); final int stackId = mSupervisor.getNextStackId(); final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop); if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Make sure recents stack exist when creating a dock stack as it normally need to be on // the other side of the docked stack and we make visibility decisions based on that. // TODO: Not sure if this is needed after we change to calculate visibility based on // stack z-order vs. id. getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop); } return stack; return createStackUnchecked(windowingMode, activityType, stackId, onTop); } @VisibleForTesting <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { switch (windowingMode) { case WINDOWING_MODE_PINNED: if (windowingMode == WINDOWING_MODE_PINNED) { return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop); default: return (T) new ActivityStack( } final T stack = (T) new ActivityStack( this, stackId, mSupervisor, windowingMode, activityType, onTop); if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Make sure recents stack exist when creating a dock stack as it normally needs to be // on the other side of the docked stack and we make visibility decisions based on that. // TODO: Not sure if this is needed after we change to calculate visibility based on // stack z-order vs. id. getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop); } return stack; } /** Loading Loading @@ -372,6 +380,105 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } /** * Returns true if the {@param windowingMode} is supported based on other parameters passed in. * @param windowingMode The windowing mode we are checking support for. * @param supportsMultiWindow If we should consider support for multi-window mode in general. * @param supportsSplitScreen If we should consider support for split-screen multi-window. * @param supportsFreeform If we should consider support for freeform multi-window. * @param supportsPip If we should consider support for picture-in-picture mutli-window. * @param activityType The activity type under consideration. * @return true if the windowing mode is supported. */ private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType) { if (windowingMode == WINDOWING_MODE_UNDEFINED || windowingMode == WINDOWING_MODE_FULLSCREEN) { return true; } if (!supportsMultiWindow) { return false; } if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType); } if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { return false; } if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { return false; } return true; } int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType) { // First preference if the windowing mode in the activity options if set. int windowingMode = (options != null) ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; // If windowing mode is unset, then next preference is the candidate task, then the // activity record. if (windowingMode == WINDOWING_MODE_UNDEFINED) { if (task != null) { windowingMode = task.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { windowingMode = r.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED) { // Use the display's windowing mode. windowingMode = getWindowingMode(); } } // Make sure the windowing mode we are trying to use makes sense for what is supported. final ActivityManagerService service = mSupervisor.mService; boolean supportsMultiWindow = service.mSupportsMultiWindow; boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow; boolean supportsFreeform = service.mSupportsFreeformWindowManagement; boolean supportsPip = service.mSupportsPictureInPicture; if (supportsMultiWindow) { if (task != null) { supportsMultiWindow = task.isResizeable(); supportsSplitScreen = task.supportsSplitScreenWindowingMode(); // TODO: Do we need to check for freeform and Pip support here? } else if (r != null) { supportsMultiWindow = r.isResizeable(); supportsSplitScreen = r.supportsSplitScreenWindowingMode(); supportsFreeform = r.supportsFreeform(); supportsPip = r.supportsPictureInPicture(); } } final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are // trying to launch in split-screen secondary. windowingMode = WINDOWING_MODE_FULLSCREEN; } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN && supportsSplitScreen) { windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } if (windowingMode != WINDOWING_MODE_UNDEFINED && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, supportsFreeform, supportsPip, activityType)) { return windowingMode; } // Return the display's windowing mode return getWindowingMode(); } /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */ int getTopVisibleStackActivityType(int excludeWindowingMode) { for (int i = mStacks.size() - 1; i >= 0; --i) { Loading Loading @@ -408,6 +515,14 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } /** We are in the process of exiting split-screen mode. */ void onExitingSplitScreenMode() { // Remove reference to the primary-split-screen stack so it no longer has any effect on the // display. For example, we want to be able to create fullscreen stack for standard activity // types when exiting split-screen mode. mSplitScreenPrimaryStack = null; } ActivityStack getSplitScreenPrimaryStack() { return mSplitScreenPrimaryStack; } Loading @@ -424,21 +539,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return mPinnedStack != null; } int updateWindowingModeForSplitScreenIfNeeded(int windowingMode, int activityType) { final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are // trying to launch in split-screen secondary. return WINDOWING_MODE_FULLSCREEN; } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType)) { return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } return windowingMode; } @Override public String toString() { return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; Loading
services/core/java/com/android/server/am/ActivityManagerService.java +3 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; Loading Loading @@ -10318,7 +10319,8 @@ public class ActivityManagerService extends IActivityManager.Stub } // TODO(multi-display): Have the caller pass in the windowing mode and activity type. final ActivityStack stack = display.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /*onTop*/); WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, ON_TOP); return (stack != null) ? stack.mStackId : INVALID_STACK_ID; } }
services/core/java/com/android/server/am/ActivityRecord.java +12 −4 Original line number Diff line number Diff line Loading @@ -165,6 +165,7 @@ import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.WindowManager.LayoutParams; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; Loading Loading @@ -232,7 +233,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo final String processName; // process where this component wants to run final String taskAffinity; // as per ActivityInfo.taskAffinity final boolean stateNotNeeded; // As per ActivityInfo.flags boolean fullscreen; // covers the full screen? boolean fullscreen; // The activity is opaque and fills the entire space of this task. // TODO: See if it possible to combine this with the fullscreen field. final boolean hasWallpaper; // Has a wallpaper window as a background. final boolean noDisplay; // activity is not displayed? private final boolean componentSpecified; // did caller specify an explicit component? final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? Loading Loading @@ -883,9 +886,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo Entry ent = AttributeCache.instance().get(packageName, realTheme, com.android.internal.R.styleable.Window, userId); fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array); noDisplay = ent != null && ent.array.getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); if (ent != null) { fullscreen = !ActivityInfo.isTranslucentOrFloating(ent.array); hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); } else { hasWallpaper = false; noDisplay = false; } setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord); Loading
services/core/java/com/android/server/am/ActivityStack.java +59 −128 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/am/ActivityStackSupervisor.java +38 −131 Original line number Diff line number Diff line Loading @@ -110,7 +110,6 @@ import android.app.AppOpsManager; import android.app.ProfilerInfo; import android.app.ResultInfo; import android.app.WaitResult; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -223,13 +222,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // at the top of its container (e.g. stack). static final boolean ON_TOP = true; // Used to indicate that an objects (e.g. task) removal from its container // (e.g. stack) is due to it moving to another container. static final boolean MOVING = true; // Force the focus to change to the stack we are moving a task to.. static final boolean FORCE_FOCUS = true; // Don't execute any calls to resume. static final boolean DEFER_RESUME = true; Loading Loading @@ -405,6 +397,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * object each time. */ private final Rect tempRect = new Rect(); private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic(); // The default minimal size that will be used if the activity doesn't specify its minimal size. // It will be calculated when the default display gets added. Loading Loading @@ -2186,89 +2179,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } /** * Returns true if the {@param windowingMode} is supported based on other parameters passed in. * @param windowingMode The windowing mode we are checking support for. * @param supportsMultiWindow If we should consider support for multi-window mode in general. * @param supportsSplitScreen If we should consider support for split-screen multi-window. * @param supportsFreeform If we should consider support for freeform multi-window. * @param supportsPip If we should consider support for picture-in-picture mutli-window. * @param activityType The activity type under consideration. * @return true if the windowing mode is supported. */ boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType) { if (windowingMode == WINDOWING_MODE_UNDEFINED || windowingMode == WINDOWING_MODE_FULLSCREEN) { return true; } if (!supportsMultiWindow) { return false; } if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode( windowingMode, activityType); } if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { return false; } if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { return false; } return true; } private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType) { // First preference if the windowing mode in the activity options if set. int windowingMode = (options != null) ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; // If windowing mode is unset, then next preference is the candidate task, then the // activity record. if (windowingMode == WINDOWING_MODE_UNDEFINED) { if (task != null) { windowingMode = task.getWindowingMode(); } if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { windowingMode = r.getWindowingMode(); } } // Make sure the windowing mode we are trying to use makes sense for what is supported. boolean supportsMultiWindow = mService.mSupportsMultiWindow; boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow; boolean supportsFreeform = mService.mSupportsFreeformWindowManagement; boolean supportsPip = mService.mSupportsPictureInPicture; if (supportsMultiWindow) { if (task != null) { supportsMultiWindow = task.isResizeable(); supportsSplitScreen = task.supportsSplitScreenWindowingMode(); // TODO: Do we need to check for freeform and Pip support here? } else if (r != null) { supportsMultiWindow = r.isResizeable(); supportsSplitScreen = r.supportsSplitScreenWindowingMode(); supportsFreeform = r.supportsFreeform(); supportsPip = r.supportsPictureInPicture(); } } if (windowingMode != WINDOWING_MODE_UNDEFINED && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, supportsFreeform, supportsPip, activityType)) { return windowingMode; } // Return root/systems windowing mode return getWindowingMode(); } int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task) { // Preference is given to the activity type for the activity then the task since the type Loading Loading @@ -2329,7 +2239,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final int activityType = resolveActivityType(r, options, candidateTask); int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); T stack = null; // Next preference for stack goes to the display Id set in the activity options or the Loading @@ -2347,7 +2256,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); if (display != null) { stack = display.getOrCreateStack(windowingMode, activityType, onTop); stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop); if (stack != null) { return stack; } Loading @@ -2365,10 +2274,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack = r.getStack(); } if (stack != null) { display = stack.getDisplay(); if (display != null) { final int windowingMode = display.resolveWindowingMode(r, options, candidateTask, activityType); if (stack.isCompatible(windowingMode, activityType)) { return stack; } display = stack.getDisplay(); } } if (display == null Loading @@ -2379,7 +2292,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D display = getDefaultDisplay(); } return display.getOrCreateStack(windowingMode, activityType, onTop); return display.getOrCreateStack(r, options, candidateTask, activityType, onTop); } /** Loading Loading @@ -2596,6 +2509,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId); if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // Tell the display we are exiting split-screen mode. toDisplay.onExitingSplitScreenMode(); // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. Loading Loading @@ -2625,35 +2540,34 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ArrayList<TaskRecord> tasks = fromStack.getAllTasks(); if (!tasks.isEmpty()) { mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); final int size = tasks.size(); final ActivityStack fullscreenStack = toDisplay.getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop); for (int i = 0; i < size; ++i) { final TaskRecord task = tasks.get(i); final ActivityStack toStack = toDisplay.getOrCreateStack( null, mTmpOptions, task, task.getActivityType(), onTop); if (onTop) { final int returnToType = toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED); for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); final boolean isTopTask = i == (size - 1); if (inPinnedWindowingMode) { // Update the return-to to reflect where the pinned stack task was moved // from so that we retain the stack that was previously visible if the // pinned stack is recreated. See moveActivityToPinnedStackLocked(). // Update the return-to to reflect where the pinned stack task was // moved from so that we retain the stack that was previously // visible if the pinned stack is recreated. // See moveActivityToPinnedStackLocked(). task.setTaskToReturnTo(returnToType); } // Defer resume until all the tasks have been moved to the fullscreen stack task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, isTopTask /* animate */, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - onTop"); } } else { for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); // Position the tasks in the fullscreen stack in order at the bottom of the // stack. Also defer resume until all the tasks have been moved to the // fullscreen stack. task.reparent(fullscreenStack, i /* position */, task.reparent(toStack, ON_TOP, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - NOT_onTop"); Loading Loading @@ -3080,23 +2994,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D + " task=" + task); } // We don't allow moving a unresizeable task to the docked stack since the docked stack is // used for split-screen mode and will cause things like the docked divider to show up. We // instead leave the task in its current stack or move it to the fullscreen stack if it // isn't currently in a stack. // Leave the task in its current stack or a fullscreen stack if it isn't resizeable and the // preferred stack is in multi-window mode. if (inMultiWindowMode && !task.isResizeable()) { Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack." + " Moving to stackId=" + stackId + " instead."); // Temporarily disable resizeablility of the task as we don't want it to be resized if, // for example, a docked stack is created which will lead to the stack we are moving // from being resized and and its resizeable tasks being resized. try { task.mTemporarilyUnresizable = true; Slog.w(TAG, "Can not move unresizeable task=" + task + " to multi-window stack=" + stack + " Moving to a fullscreen stack instead."); if (prevStack != null) { return prevStack; } stack = stack.getDisplay().createStack( WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop); } finally { task.mTemporarilyUnresizable = false; } } return stack; } Loading Loading @@ -4287,9 +4194,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final boolean isSecondaryDisplayPreferred = (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); final boolean inSplitScreenMode = actualStack != null && actualStack.inSplitScreenWindowingMode(); && actualStack.getDisplay().hasSplitScreenPrimaryStack(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) { && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) { return; } Loading