diff options
26 files changed, 563 insertions, 316 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 7256e5cf1cf9..d6560a785e87 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4052,10 +4052,11 @@ package android.app { method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); + method public void setLaunchActivityType(int); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int); - method public void setLaunchStackId(int); method public void setLaunchTaskId(int); + method public void setLaunchWindowingMode(int); method public void setTaskOverlay(boolean, boolean); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); @@ -6244,6 +6245,7 @@ package android.app { field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0 field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5 field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1 + field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4 field public static final int WINDOWING_MODE_PINNED = 2; // 0x2 field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3 field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4 diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index a8665037f8d3..78d05f5123c8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -770,21 +770,6 @@ public class ActivityManager { } /** - * Returns true if animation specs should be constructed for app transition that moves - * the task to the specified stack. - * @hide - */ - public static boolean useAnimationSpecForAppTransition(int stackId) { - // TODO: INVALID_STACK_ID is also animated because we don't persist stack id's across - // reboots. - return stackId == FREEFORM_WORKSPACE_STACK_ID - || stackId == FULLSCREEN_WORKSPACE_STACK_ID - || stackId == ASSISTANT_STACK_ID - || stackId == DOCKED_STACK_ID - || stackId == INVALID_STACK_ID; - } - - /** * Returns true if activities from stasks in the given {@param stackId} are allowed to * enter picture-in-picture. * @hide @@ -885,6 +870,18 @@ public class ActivityManager { return windowingMode; } + /** Returns the stack id for the input windowing mode. + * @hide */ + // TODO: To be removed once we are not using stack id for stuff... + public static int getStackIdForWindowingMode(int windowingMode) { + switch (windowingMode) { + case WINDOWING_MODE_PINNED: return PINNED_STACK_ID; + case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID; + case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID; + default: return INVALID_STACK_ID; + } + } + /** Returns the activity type that should be used for this input stack id. * @hide */ // TODO: To be removed once we are not using stack id for stuff... @@ -905,6 +902,18 @@ public class ActivityManager { } return activityType; } + + /** Returns the stack id for the input activity type. + * @hide */ + // TODO: To be removed once we are not using stack id for stuff... + public static int getStackIdForActivityType(int activityType) { + switch (activityType) { + case ACTIVITY_TYPE_HOME: return HOME_STACK_ID; + case ACTIVITY_TYPE_RECENTS: return RECENTS_STACK_ID; + case ACTIVITY_TYPE_ASSISTANT: return ASSISTANT_STACK_ID; + default: return INVALID_STACK_ID; + } + } } /** diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 0bffc9e6cee5..a68c3a5c29a6 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -18,6 +18,8 @@ package android.app; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; import android.annotation.Nullable; @@ -164,10 +166,16 @@ public class ActivityOptions { private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId"; /** - * The stack id the activity should be launched into. + * The windowing mode the activity should be launched into. * @hide */ - private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId"; + private static final String KEY_LAUNCH_WINDOWING_MODE = "android.activity.windowingMode"; + + /** + * The activity type the activity should be launched as. + * @hide + */ + private static final String KEY_LAUNCH_ACTIVITY_TYPE = "android.activity.activityType"; /** * The task id the activity should be launched into. @@ -272,7 +280,10 @@ public class ActivityOptions { private int mExitCoordinatorIndex; private PendingIntent mUsageTimeReport; private int mLaunchDisplayId = INVALID_DISPLAY; - private int mLaunchStackId = INVALID_STACK_ID; + @WindowConfiguration.WindowingMode + private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED; + @WindowConfiguration.ActivityType + private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED; private int mLaunchTaskId = -1; private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; private boolean mDisallowEnterPictureInPictureWhileLaunching; @@ -860,7 +871,8 @@ public class ActivityOptions { break; } mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY); - mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); + mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED); + mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED); mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1); mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false); mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false); @@ -1070,14 +1082,34 @@ public class ActivityOptions { } /** @hide */ - public int getLaunchStackId() { - return mLaunchStackId; + public int getLaunchWindowingMode() { + return mLaunchWindowingMode; + } + + /** + * Sets the windowing mode the activity should launch into. If the input windowing mode is + * {@link android.app.WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} and the device + * isn't currently in split-screen windowing mode, then the activity will be launched in + * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN} windowing mode. For clarity + * on this you can use + * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY} + * + * @hide + */ + @TestApi + public void setLaunchWindowingMode(int windowingMode) { + mLaunchWindowingMode = windowingMode; + } + + /** @hide */ + public int getLaunchActivityType() { + return mLaunchActivityType; } /** @hide */ @TestApi - public void setLaunchStackId(int launchStackId) { - mLaunchStackId = launchStackId; + public void setLaunchActivityType(int activityType) { + mLaunchActivityType = activityType; } /** @@ -1291,7 +1323,8 @@ public class ActivityOptions { break; } b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId); - b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); + b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode); + b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType); b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay); b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume); diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 07eb5de15d9f..0cb38046826f 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -63,8 +63,21 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in * split-screen mode. + * NOTE: Containers launched with the windowing mode with APIs like + * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in + * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing + * mode + * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY */ public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; + /** + * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage + * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container + * will launch into fullscreen or split-screen secondary depending on if the device is currently + * in fullscreen mode or split-screen mode. + */ + public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = + WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; /** Can be freely resized within its parent container. */ public static final int WINDOWING_MODE_FREEFORM = 5; @@ -75,6 +88,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu WINDOWING_MODE_PINNED, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, WINDOWING_MODE_FREEFORM, }) public @interface WindowingMode {} diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index bc85fadb5ad9..7903d6fdc614 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -16,9 +16,10 @@ package android.widget; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.annotation.ColorInt; import android.annotation.DimenRes; -import android.app.ActivityManager.StackId; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; @@ -324,11 +325,11 @@ public class RemoteViews implements Parcelable, Filter { public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { - return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID); + return onClickHandler(view, pendingIntent, fillInIntent, WINDOWING_MODE_UNDEFINED); } public boolean onClickHandler(View view, PendingIntent pendingIntent, - Intent fillInIntent, int launchStackId) { + Intent fillInIntent, int windowingMode) { try { // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? Context context = view.getContext(); @@ -339,8 +340,8 @@ public class RemoteViews implements Parcelable, Filter { opts = ActivityOptions.makeBasic(); } - if (launchStackId != StackId.INVALID_STACK_ID) { - opts.setLaunchStackId(launchStackId); + if (windowingMode != WINDOWING_MODE_UNDEFINED) { + opts.setLaunchWindowingMode(windowingMode); } context.startIntentSender( pendingIntent.getIntentSender(), fillInIntent, diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index aecf95fc677f..c4e870135a6d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -565,8 +565,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Launch the task ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID, - null /* resultListener */); + mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */); } /** @@ -639,8 +638,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Launch the task ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID, - null /* resultListener */); + mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */); } public void showNextAffiliatedTask() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java index 3db106e7200f..862a1eee8c39 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java @@ -16,6 +16,9 @@ package com.android.systemui.recents.events.activity; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.graphics.Rect; import com.android.systemui.recents.events.EventBus; @@ -30,15 +33,23 @@ public class LaunchTaskEvent extends EventBus.Event { public final TaskView taskView; public final Task task; public final Rect targetTaskBounds; - public final int targetTaskStack; + public final int targetWindowingMode; + public final int targetActivityType; public final boolean screenPinningRequested; - public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack, + public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, boolean screenPinningRequested) { + this(taskView, task, targetTaskBounds, screenPinningRequested, + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED); + } + + public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, + boolean screenPinningRequested, int windowingMode, int activityType) { this.taskView = taskView; this.task = task; this.targetTaskBounds = targetTaskBounds; - this.targetTaskStack = targetTaskStack; + this.targetWindowingMode = windowingMode; + this.targetActivityType = activityType; this.screenPinningRequested = screenPinningRequested; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 717778228989..366a908f15bd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -23,6 +23,10 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; import android.annotation.NonNull; @@ -576,7 +580,7 @@ public class SystemServicesProxy { try { final ActivityOptions options = ActivityOptions.makeBasic(); options.setDockCreateMode(createMode); - options.setLaunchStackId(DOCKED_STACK_ID); + options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); mIam.startActivityFromRecents(taskId, options.toBundle()); return true; } catch (Exception e) { @@ -1120,9 +1124,16 @@ public class SystemServicesProxy { opts != null ? opts.toBundle() : null, UserHandle.CURRENT)); } + public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, + ActivityOptions options, + @Nullable final StartActivityFromRecentsResultListener resultListener) { + startActivityFromRecents(context, taskKey, taskName, options, + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener); + } + /** Starts an activity from recents. */ public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, - ActivityOptions options, int stackId, + ActivityOptions options, int windowingMode, int activityType, @Nullable final StartActivityFromRecentsResultListener resultListener) { if (mIam == null) { return; @@ -1133,12 +1144,14 @@ public class SystemServicesProxy { if (options == null) { options = ActivityOptions.makeBasic(); } - options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID); - } else if (stackId != INVALID_STACK_ID) { + options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + } else if (windowingMode != WINDOWING_MODE_UNDEFINED + || activityType != ACTIVITY_TYPE_UNDEFINED) { if (options == null) { options = ActivityOptions.makeBasic(); } - options.setLaunchStackId(stackId); + options.setLaunchWindowingMode(windowingMode); + options.setLaunchActivityType(activityType); } final ActivityOptions finalOptions = options; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index b2675d7ac858..4d3321638e8e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -21,6 +21,15 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.Nullable; import android.app.ActivityManager.StackId; @@ -107,7 +116,7 @@ public class RecentsTransitionHelper { */ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, - final boolean screenPinningRequested, final int destinationStack) { + final boolean screenPinningRequested, final int windowingMode, final int activityType) { final ActivityOptions.OnAnimationStartedListener animStartedListener; final AppTransitionAnimationSpecsFuture transitionFuture; @@ -116,8 +125,8 @@ public class RecentsTransitionHelper { // Fetch window rect here already in order not to be blocked on lock contention in WM // when the future calls it. final Rect windowRect = Recents.getSystemServices().getWindowRect(); - transitionFuture = getAppTransitionFuture( - () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect)); + transitionFuture = getAppTransitionFuture(() -> composeAnimationSpecs( + task, stackView, windowingMode, activityType, windowRect)); animStartedListener = new OnAnimationStartedListener() { private boolean mHandled; @@ -180,7 +189,8 @@ public class RecentsTransitionHelper { if (taskView == null) { // If there is no task view, then we do not need to worry about animating out occluding // task views, and we can launch immediately - startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack); + startTaskActivity(stack, task, taskView, opts, transitionFuture, + windowingMode, activityType); } else { LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView, screenPinningRequested); @@ -189,13 +199,14 @@ public class RecentsTransitionHelper { @Override public void run() { startTaskActivity(stack, task, taskView, opts, transitionFuture, - destinationStack); + windowingMode, activityType); } }); EventBus.getDefault().send(launchStartedEvent); } else { EventBus.getDefault().send(launchStartedEvent); - startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack); + startTaskActivity(stack, task, taskView, opts, transitionFuture, + windowingMode, activityType); } } Recents.getSystemServices().sendCloseSystemWindows( @@ -224,13 +235,13 @@ public class RecentsTransitionHelper { * * @param taskView this is the {@link TaskView} that we are launching from. This can be null if * we are toggling recents and the launch-to task is now offscreen. - * @param destinationStack id of the stack to put the task into. */ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView, ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture, - int destinationStack) { + int windowingMode, int activityType) { SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack, + ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode, + activityType, succeeded -> { if (succeeded) { // Keep track of the index of the task launch @@ -310,11 +321,9 @@ public class RecentsTransitionHelper { * Composes the animation specs for all the tasks in the target stack. */ private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task, - final TaskStackView stackView, final int destinationStack, Rect windowRect) { - // Ensure we have a valid target stack id - final int targetStackId = destinationStack != INVALID_STACK_ID ? - destinationStack : task.key.stackId; - if (!StackId.useAnimationSpecForAppTransition(targetStackId)) { + final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) { + if (activityType == ACTIVITY_TYPE_RECENTS || activityType == ACTIVITY_TYPE_HOME + || windowingMode == WINDOWING_MODE_PINNED) { return null; } @@ -329,9 +338,12 @@ public class RecentsTransitionHelper { List<AppTransitionAnimationSpec> specs = new ArrayList<>(); // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to - // check for INVALID_STACK_ID - if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID || targetStackId == DOCKED_STACK_ID - || targetStackId == ASSISTANT_STACK_ID || targetStackId == INVALID_STACK_ID) { + // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED) + if (windowingMode == WINDOWING_MODE_FULLSCREEN + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + || activityType == ACTIVITY_TYPE_ASSISTANT + || windowingMode == WINDOWING_MODE_UNDEFINED) { if (taskView == null) { specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect)); } else { @@ -353,7 +365,7 @@ public class RecentsTransitionHelper { int taskCount = tasks.size(); for (int i = taskCount - 1; i >= 0; i--) { Task t = tasks.get(i); - if (t.isFreeformTask() || targetStackId == FREEFORM_WORKSPACE_STACK_ID) { + if (t.isFreeformTask() || windowingMode == WINDOWING_MODE_FREEFORM) { TaskView tv = stackView.getChildViewForTask(t); if (tv == null) { // TODO: Create a different animation task rect for this case (though it should diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index c44cd7287625..fd1b806abf24 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -338,8 +338,7 @@ public class RecentsView extends FrameLayout { Task task = mTaskStackView.getFocusedTask(); if (task != null) { TaskView taskView = mTaskStackView.getChildViewForTask(task); - EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, - INVALID_STACK_ID, false)); + EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false)); if (logEvent != 0) { MetricsLogger.action(getContext(), logEvent, @@ -363,32 +362,13 @@ public class RecentsView extends FrameLayout { Task task = getStack().getLaunchTarget(); if (task != null) { TaskView taskView = mTaskStackView.getChildViewForTask(task); - EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, - INVALID_STACK_ID, false)); + EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false)); return true; } } return false; } - /** Launches a given task. */ - public boolean launchTask(Task task, Rect taskBounds, int destinationStack) { - if (mTaskStackView != null) { - // Iterate the stack views and try and find the given task. - List<TaskView> taskViews = mTaskStackView.getTaskViews(); - int taskViewCount = taskViews.size(); - for (int j = 0; j < taskViewCount; j++) { - TaskView tv = taskViews.get(j); - if (tv.getTask() == task) { - EventBus.getDefault().send(new LaunchTaskEvent(tv, task, taskBounds, - destinationStack, false)); - return true; - } - } - } - return false; - } - /** * Hides the task stack and shows the empty view. */ @@ -570,7 +550,8 @@ public class RecentsView extends FrameLayout { public final void onBusEvent(LaunchTaskEvent event) { mLastTaskLaunchedWasFreeform = event.task.isFreeformTask(); mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView, - event.taskView, event.screenPinningRequested, event.targetTaskStack); + event.taskView, event.screenPinningRequested, event.targetWindowingMode, + event.targetActivityType); if (Recents.getConfiguration().isLowRamDevice) { hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, false /* translate */); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 8899e307bb16..74e9ef2b3efb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -1487,7 +1487,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task frontTask = tasks.get(tasks.size() - 1); if (frontTask != null && frontTask.isFreeformTask()) { EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask), - frontTask, null, INVALID_STACK_ID, false)); + frontTask, null, false)); return true; } } @@ -2369,12 +2369,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void run() { EventBus.getDefault().send(new LaunchTaskEvent( getChildViewForTask(task), task, null, - INVALID_STACK_ID, false /* screenPinningRequested */)); + false /* screenPinningRequested */)); } }); } else { - EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task), - task, null, INVALID_STACK_ID, false /* screenPinningRequested */)); + EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task), task, null, + false /* screenPinningRequested */)); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index ceeebd96a3e1..c64f6dfcea4a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -674,8 +674,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks mActionButtonView.setTranslationZ(0f); screenPinningRequested = true; } - EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID, - screenPinningRequested)); + EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, screenPinningRequested)); MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT, mTask.key.getComponent().toString()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index ae922fcc218e..198ecae2d1a9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -16,6 +16,11 @@ package com.android.systemui.recents.views; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; @@ -57,10 +62,6 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; - /* The task bar view */ public class TaskViewHeader extends FrameLayout implements View.OnClickListener, View.OnLongClickListener { @@ -172,7 +173,7 @@ public class TaskViewHeader extends FrameLayout int mTaskBarViewLightTextColor; int mTaskBarViewDarkTextColor; int mDisabledTaskBarBackgroundColor; - int mMoveTaskTargetStackId = INVALID_STACK_ID; + int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED; // Header background private HighlightColorDrawable mBackground; @@ -485,12 +486,12 @@ public class TaskViewHeader extends FrameLayout // current task if (mMoveTaskButton != null) { if (t.isFreeformTask()) { - mMoveTaskTargetStackId = FULLSCREEN_WORKSPACE_STACK_ID; + mTaskWindowingMode = WINDOWING_MODE_FULLSCREEN; mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightFullscreenIcon : mDarkFullscreenIcon); } else { - mMoveTaskTargetStackId = FREEFORM_WORKSPACE_STACK_ID; + mTaskWindowingMode = WINDOWING_MODE_FREEFORM; mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightFreeformIcon : mDarkFreeformIcon); @@ -621,8 +622,8 @@ public class TaskViewHeader extends FrameLayout Constants.Metrics.DismissSourceHeaderButton); } else if (v == mMoveTaskButton) { TaskView tv = Utilities.findParent(this, TaskView.class); - EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null, - mMoveTaskTargetStackId, false)); + EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null, false, + mTaskWindowingMode, ACTIVITY_TYPE_UNDEFINED)); } else if (v == mAppInfoView) { EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask)); } else if (v == mAppIconView) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java index 7e08d5605f40..9d2d71e28e5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java @@ -15,6 +15,12 @@ */ package com.android.systemui.statusbar.car; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.app.ActivityManager.StackId; import android.content.Context; import android.content.Intent; @@ -117,7 +123,8 @@ class CarNavigationBarController { // Set up the persistent docked task if needed. if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask() && stackId != StackId.HOME_STACK_ID) { - mStatusBar.startActivityOnStack(mPersistentTaskIntent, StackId.DOCKED_STACK_ID); + mStatusBar.startActivityOnStack(mPersistentTaskIntent, + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); } } @@ -375,13 +382,15 @@ class CarNavigationBarController { // rather than the "preferred/last run" app. intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex); - int stackId = StackId.FULLSCREEN_WORKSPACE_STACK_ID; + int windowingMode = WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; + int activityType = ACTIVITY_TYPE_UNDEFINED; if (intent.getCategories().contains(Intent.CATEGORY_HOME)) { - stackId = StackId.HOME_STACK_ID; + windowingMode = WINDOWING_MODE_UNDEFINED; + activityType = ACTIVITY_TYPE_HOME; } setCurrentFacet(index); - mStatusBar.startActivityOnStack(intent, stackId); + mStatusBar.startActivityOnStack(intent, windowingMode, activityType); } /** @@ -391,6 +400,7 @@ class CarNavigationBarController { */ private void onFacetLongClicked(Intent intent, int index) { setCurrentFacet(index); - mStatusBar.startActivityOnStack(intent, StackId.FULLSCREEN_WORKSPACE_STACK_ID); + mStatusBar.startActivityOnStack(intent, + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 680f693a83f8..10fc496fcfd2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -378,9 +378,10 @@ public class CarStatusBar extends StatusBar implements return result; } - public int startActivityOnStack(Intent intent, int stackId) { - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchStackId(stackId); + public int startActivityOnStack(Intent intent, int windowingMode, int activityType) { + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(windowingMode); + options.setLaunchActivityType(activityType); return startActivityWithOptions(intent, options.toBundle()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index efc8d8b97114..4ee4330d5fa8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -20,6 +20,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.windowStateToString; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; @@ -37,7 +38,6 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityManager.StackId; import android.app.ActivityOptions; import android.app.INotificationManager; import android.app.KeyguardManager; @@ -5932,7 +5932,7 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean superOnClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { return super.onClickHandler(view, pendingIntent, fillInIntent, - StackId.FULLSCREEN_WORKSPACE_STACK_ID); + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); } private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) { @@ -7149,10 +7149,10 @@ public class StatusBar extends SystemUI implements DemoMode, } protected Bundle getActivityOptions() { - // Anything launched from the notification shade should always go into the - // fullscreen stack. - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID); + // Anything launched from the notification shade should always go into the secondary + // split-screen windowing mode. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); return options.toBundle(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6c8239916418..0dd0aded3b97 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10043,7 +10043,7 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "getTaskDescription()"); final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID); + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { return tr.lastTaskDescription; } @@ -10156,7 +10156,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void setTaskResizeable(int taskId, int resizeableMode) { synchronized (this) { final TaskRecord task = mStackSupervisor.anyTaskForIdLocked( - taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID); + taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found"); return; @@ -10219,7 +10219,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID); + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found"); return rect; @@ -10251,7 +10251,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID); + MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found"); return; @@ -10270,7 +10270,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID); + MATCH_TASK_IN_STACKS_ONLY); if (task == null) { Slog.w(TAG, "cancelTaskThumbnailTransition: taskId=" + taskId + " not found"); return; @@ -10290,7 +10290,7 @@ public class ActivityManagerService extends IActivityManager.Stub final TaskRecord task; synchronized (this) { task = mStackSupervisor.anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID); + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (task == null) { Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found"); return null; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 6901d2de6f00..0aca9ea6d748 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -75,6 +75,8 @@ import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; @@ -115,7 +117,8 @@ final class ActivityManagerShellCommand extends ShellCommand { private boolean mStreaming; // Streaming the profiling output to a file. private String mAgent; // Agent to attach on startup. private int mDisplayId; - private int mStackId; + private int mWindowingMode; + private int mActivityType; private int mTaskId; private boolean mIsTaskOverlay; @@ -271,7 +274,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mStreaming = false; mUserId = defUser; mDisplayId = INVALID_DISPLAY; - mStackId = INVALID_STACK_ID; + mWindowingMode = WINDOWING_MODE_UNDEFINED; + mActivityType = ACTIVITY_TYPE_UNDEFINED; mTaskId = INVALID_TASK_ID; mIsTaskOverlay = false; @@ -308,8 +312,10 @@ final class ActivityManagerShellCommand extends ShellCommand { mReceiverPermission = getNextArgRequired(); } else if (opt.equals("--display")) { mDisplayId = Integer.parseInt(getNextArgRequired()); - } else if (opt.equals("--stack")) { - mStackId = Integer.parseInt(getNextArgRequired()); + } else if (opt.equals("--windowingMode")) { + mWindowingMode = Integer.parseInt(getNextArgRequired()); + } else if (opt.equals("--activityType")) { + mActivityType = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--task")) { mTaskId = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--task-overlay")) { @@ -396,9 +402,17 @@ final class ActivityManagerShellCommand extends ShellCommand { options = ActivityOptions.makeBasic(); options.setLaunchDisplayId(mDisplayId); } - if (mStackId != INVALID_STACK_ID) { - options = ActivityOptions.makeBasic(); - options.setLaunchStackId(mStackId); + if (mWindowingMode != WINDOWING_MODE_UNDEFINED) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchWindowingMode(mWindowingMode); + } + if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchActivityType(mActivityType); } if (mTaskId != INVALID_TASK_ID) { options = ActivityOptions.makeBasic(); @@ -2685,7 +2699,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --track-allocation: enable tracking of object allocations"); pw.println(" --user <USER_ID> | current: Specify which user to run as; if not"); pw.println(" specified then run as the current user."); - pw.println(" --stack <STACK_ID>: Specify into which stack should the activity be put."); + pw.println(" --windowingMode <WINDOWING_MODE>: The windowing mode to launch the activity into."); + pw.println(" --activityType <ACTIVITY_TYPE>: The activity type to launch the activity as."); pw.println(" start-service [--user <USER_ID> | current] <INTENT>"); pw.println(" Start a Service. Options are:"); pw.println(" --user <USER_ID> | current: Specify which user to run as; if not"); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 0ccb45f74ec2..7acabd277701 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -17,7 +17,6 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; -import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; @@ -36,7 +35,6 @@ import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.activityTypeToString; import static android.content.Intent.ACTION_MAIN; @@ -89,10 +87,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -1038,7 +1034,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) { activityType = ACTIVITY_TYPE_RECENTS; - } else if (options != null && options.getLaunchStackId() == ASSISTANT_STACK_ID + } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT && canLaunchAssistActivity(launchedFromPackage)) { activityType = ACTIVITY_TYPE_ASSISTANT; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c8a2a230a7e1..ffe5fd48706a 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID; @@ -31,13 +32,20 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; +import static android.app.ActivityManager.StackId.getStackIdForActivityType; +import static android.app.ActivityManager.StackId.getStackIdForWindowingMode; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; @@ -83,6 +91,7 @@ import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.am.ActivityStack.STACK_INVISIBLE; import static com.android.server.am.ActivityStack.STACK_VISIBLE; +import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; @@ -94,6 +103,7 @@ import static java.lang.Integer.MAX_VALUE; import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -707,24 +717,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } TaskRecord anyTaskForIdLocked(int id) { - return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, - INVALID_STACK_ID); + return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE); + } + + TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) { + return anyTaskForIdLocked(id, matchMode, null); } /** * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise. * @param id Id of the task we would like returned. * @param matchMode The mode to match the given task id in. - * @param stackId The stack to restore the task to (default launch stack will be used if - * stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}). Only - * valid if the matchMode is - * {@link #MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE}. + * @param aOptions The activity options to use for restoration. Can be null. */ - TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode, int stackId) { + TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode, + @Nullable ActivityOptions aOptions) { // If there is a stack id set, ensure that we are attempting to actually restore a task - if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && - stackId != INVALID_STACK_ID) { - throw new IllegalArgumentException("Should not specify stackId for non-restore lookup"); + // TODO: Don't really know if this is needed... + if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) { + throw new IllegalArgumentException("Should not specify activity options for non-restore" + + " lookup"); } int numDisplays = mActivityDisplays.size(); @@ -762,7 +774,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE - if (!restoreRecentTaskLocked(task, stackId)) { + if (!restoreRecentTaskLocked(task, aOptions)) { if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Couldn't restore task id=" + id + " found in recents"); return null; @@ -857,8 +869,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on. int candidateTaskId = nextTaskIdForUser(currentTaskId, userId); while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId) - || anyTaskForIdLocked(candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, - INVALID_STACK_ID) != null) { + || anyTaskForIdLocked( + candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { candidateTaskId = nextTaskIdForUser(candidateTaskId, userId); if (candidateTaskId == currentTaskId) { // Something wrong! @@ -2084,38 +2096,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // we'll just indicate that this task returns to the home task. task.setTaskToReturnTo(ACTIVITY_TYPE_HOME); } - ActivityStack currentStack = task.getStack(); + final ActivityStack currentStack = task.getStack(); if (currentStack == null) { Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task=" + task + " to front. Stack is null"); return; } - if (task.isResizeable() && options != null) { - int stackId = options.getLaunchStackId(); - if (canUseActivityOptionsLaunchBounds(options, stackId)) { - final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); - task.updateOverrideConfiguration(bounds); - if (stackId == INVALID_STACK_ID) { - stackId = task.getLaunchStackId(); - } - if (stackId != currentStack.mStackId) { - task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, - DEFER_RESUME, "findTaskToMoveToFrontLocked"); - stackId = currentStack.mStackId; - // moveTaskToStackUncheckedLocked() should already placed the task on top, - // still need moveTaskToFrontLocked() below for any transition settings. - } - if (StackId.resizeStackWithLaunchBounds(stackId)) { - resizeStackLocked(stackId, bounds, - null /* tempTaskBounds */, null /* tempTaskInsetBounds */, - !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); - } else { - // WM resizeTask must be done after the task is moved to the correct stack, - // because Task's setBounds() also updates dim layer's bounds, but that has - // dependency on the stack. - task.resizeWindowContainer(); - } + if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) { + final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); + task.updateOverrideConfiguration(bounds); + + int stackId = getLaunchStackId(null, options, task); + + if (stackId != currentStack.mStackId) { + task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, + DEFER_RESUME, "findTaskToMoveToFrontLocked"); + stackId = currentStack.mStackId; + // moveTaskToStackUncheckedLocked() should already placed the task on top, + // still need moveTaskToFrontLocked() below for any transition settings. + } + if (StackId.resizeStackWithLaunchBounds(stackId)) { + resizeStackLocked(stackId, bounds, + null /* tempTaskBounds */, null /* tempTaskInsetBounds */, + !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); + } else { + // WM resizeTask must be done after the task is moved to the correct stack, + // because Task's setBounds() also updates dim layer's bounds, but that has + // dependency on the stack. + task.resizeWindowContainer(); } } @@ -2126,17 +2135,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (DEBUG_STACK) Slog.d(TAG_STACK, "findTaskToMoveToFront: moved to front of stack=" + currentStack); - handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY, + handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, currentStack.mStackId, forceNonResizeable); } - boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) { + boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) { // We use the launch bounds in the activity options is the device supports freeform // window management or is launching into the pinned stack. - if (options.getLaunchBounds() == null) { + if (options == null || options.getLaunchBounds() == null) { return false; } - return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID) + return (mService.mSupportsPictureInPicture + && options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED) || mService.mSupportsFreeformWindowManagement; } @@ -2161,6 +2171,179 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop); } + private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable TaskRecord task) { + + // 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. + if (!mService.mSupportsMultiWindow && windowingMode != WINDOWING_MODE_FULLSCREEN) { + windowingMode = WINDOWING_MODE_FULLSCREEN; + } + + if (!mService.mSupportsSplitScreenMultiWindow + && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) { + windowingMode = WINDOWING_MODE_FULLSCREEN; + } + + if (windowingMode == WINDOWING_MODE_FREEFORM + && !mService.mSupportsFreeformWindowManagement) { + windowingMode = WINDOWING_MODE_FULLSCREEN; + } + + return windowingMode; + } + + private int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable TaskRecord task) { + // First preference if the activity type in the activity options if set. + int activityType = (options != null) + ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED; + + if (activityType != ACTIVITY_TYPE_UNDEFINED) { + return activityType; + } + + // If activity type is unset, then next preference is the task, then the activity record. + if (task != null) { + activityType = task.getActivityType(); + } + if (activityType == ACTIVITY_TYPE_UNDEFINED && r != null) { + activityType = r.getActivityType(); + } + return activityType; + } + + int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable TaskRecord candidateTask) { + return getLaunchStackId(r, options, candidateTask, INVALID_DISPLAY); + } + + /** + * Returns the right stack 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. + * + * @return The stack to use for the launch or INVALID_STACK_ID. + */ + int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + @Nullable TaskRecord candidateTask, int candidateDisplayId) { + int taskId = INVALID_TASK_ID; + int displayId = INVALID_DISPLAY; + //Rect bounds = null; + + // We give preference to the launch preference in activity options. + if (options != null) { + taskId = options.getLaunchTaskId(); + displayId = options.getLaunchDisplayId(); + // TODO: Need to work this into the equation... + //bounds = options.getLaunchBounds(); + } + + // First preference for stack goes to the task Id set in the activity options. Use the stack + // 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 TaskRecord task = anyTaskForIdLocked(taskId, + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options); + options.setLaunchTaskId(taskId); + if (task != null) { + return task.getStack().mStackId; + } + } + + final int windowingMode = resolveWindowingMode(r, options, candidateTask); + final int activityType = resolveActivityType(r, options, candidateTask); + ActivityStack stack = null; + + // Next preference for stack goes to the display Id set in the activity options or the + // candidate display. + if (displayId == INVALID_DISPLAY) { + displayId = candidateDisplayId; + } + if (displayId != INVALID_DISPLAY) { + if (r != null) { + // TODO: This should also take in the windowing mode and activity type into account. + stack = getValidLaunchStackOnDisplay(displayId, r); + if (stack != null) { + return stack.mStackId; + } + } + final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); + if (display != null) { + for (int i = display.mStacks.size() - 1; i >= 0; --i) { + stack = display.mStacks.get(i); + if (stack.getWindowingMode() == windowingMode + && stack.getActivityType() == activityType) { + return stack.mStackId; + } + } + // TODO: We should create the stack we want on the display at this point. + } + } + + // Give preference to the stack and display of the input task and activity if they match the + // mode we want to launch into. + if (candidateTask != null) { + stack = candidateTask.getStack(); + } + if (stack == null && r != null) { + stack = r.getStack(); + } + if (stack != null) { + if (stack.getWindowingMode() == windowingMode + && stack.getActivityType() == activityType) { + return stack.mStackId; + } + ActivityDisplay display = stack.getDisplay(); + + if (display != null) { + for (int i = display.mStacks.size() - 1; i >= 0; --i) { + stack = display.mStacks.get(i); + if (stack.getWindowingMode() == windowingMode + && stack.getActivityType() == activityType) { + return stack.mStackId; + } + } + } + } + + // Give preference to the type of activity we are trying to launch followed by the windowing + // mode. + int stackId = getStackIdForActivityType(activityType); + if (stackId != INVALID_STACK_ID) { + return stackId; + } + stackId = getStackIdForWindowingMode(windowingMode); + if (stackId != INVALID_STACK_ID) { + return stackId; + } + + // Whatever...return some default for now. + if (candidateTask != null && candidateTask.mBounds != null + && mService.mSupportsFreeformWindowManagement) { + return FREEFORM_WORKSPACE_STACK_ID; + } + return FULLSCREEN_WORKSPACE_STACK_ID; + } + /** * Get a topmost stack on the display, that is a valid launch stack for specified activity. * If there is no such stack, new dynamic stack can be created. @@ -2178,7 +2361,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Return the topmost valid stack on the display. for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = activityDisplay.mStacks.get(i); - if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, displayId, r)) { + if (isValidLaunchStackId(stack.mStackId, displayId, r)) { return stack; } } @@ -2186,7 +2369,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // If there is no valid stack on the external display - check if new dynamic stack will do. if (displayId != Display.DEFAULT_DISPLAY) { final int newDynamicStackId = getNextStackId(); - if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, displayId, r)) { + if (isValidLaunchStackId(newDynamicStackId, displayId, r)) { return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/); } } @@ -2195,6 +2378,32 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } + boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) { + switch (stackId) { + case INVALID_STACK_ID: + case HOME_STACK_ID: + return false; + case FULLSCREEN_WORKSPACE_STACK_ID: + return true; + case FREEFORM_WORKSPACE_STACK_ID: + return r.supportsFreeform(); + case DOCKED_STACK_ID: + return r.supportsSplitScreen(); + case PINNED_STACK_ID: + return r.supportsPictureInPicture(); + case RECENTS_STACK_ID: + return r.isActivityTypeRecents(); + case ASSISTANT_STACK_ID: + return r.isActivityTypeAssistant(); + default: + if (StackId.isDynamicStack(stackId)) { + return r.canBeLaunchedOnDisplay(displayId); + } + Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId); + return false; + } + } + ArrayList<ActivityStack> getStacks() { ArrayList<ActivityStack> allStacks = new ArrayList<>(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { @@ -2345,8 +2554,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D continueUpdateBounds(RECENTS_STACK_ID); for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) { final int taskId = mResizingTasksDuringAnimation.valueAt(i); - final TaskRecord task = - anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID); + final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY); if (task != null) { task.setTaskDockedResizing(false); } @@ -2641,8 +2849,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents, boolean pauseImmediately) { - final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, - INVALID_STACK_ID); + final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { tr.removeTaskActivitiesLocked(pauseImmediately); cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents); @@ -2741,23 +2948,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** * Restores a recent task to a stack * @param task The recent task to be restored. - * @param stackId The stack to restore the task to (default launch stack will be used - * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID} - * or is not a static stack). + * @param aOptions The activity options to use for restoration. * @return true if the task has been restored successfully. */ - boolean restoreRecentTaskLocked(TaskRecord task, int stackId) { - if (!StackId.isStaticStack(stackId)) { - // If stack is not static (or stack id is invalid) - use the default one. - // This means that tasks that were on external displays will be restored on the - // primary display. - stackId = task.getLaunchStackId(); - } else if (stackId == DOCKED_STACK_ID && !task.supportsSplitScreen()) { - // Preferred stack is the docked stack, but the task can't go in the docked stack. - // Put it in the fullscreen stack. - stackId = FULLSCREEN_WORKSPACE_STACK_ID; - } - + boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) { + final int stackId = getLaunchStackId(null, aOptions, task); final ActivityStack currentStack = task.getStack(); if (currentStack != null) { // Task has already been restored once. See if we need to do anything more @@ -2770,15 +2965,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING); } - final ActivityStack stack = - getStack(stackId, CREATE_IF_NEEDED, !ON_TOP); - - if (stack == null) { - // What does this mean??? Not sure how we would get here... - if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, - "Unable to find/create stack to restore recent task=" + task); - return false; - } + final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP); stack.addTask(task, false /* toTop */, "restoreRecentTask"); // TODO: move call for creation here and other place into Stack.addTask() @@ -4015,21 +4202,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return list; } - void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, + void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, int preferredDisplayId, int actualStackId) { - handleNonResizableTaskIfNeeded(task, preferredStackId, preferredDisplayId, actualStackId, - false /* forceNonResizable */); + handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, + actualStackId, false /* forceNonResizable */); } - void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, + void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, int preferredDisplayId, int actualStackId, boolean forceNonResizable) { final boolean isSecondaryDisplayPreferred = - (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY) - || StackId.isDynamicStack(preferredStackId); + (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); final ActivityStack actualStack = getStack(actualStackId); final boolean inSplitScreenMode = actualStack != null && actualStack.inSplitScreenWindowingMode(); - if (((!inSplitScreenMode && preferredStackId != DOCKED_STACK_ID) + if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) { return; } @@ -4424,18 +4610,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final String callingPackage; final Intent intent; final int userId; + int activityType = ACTIVITY_TYPE_UNDEFINED; + int windowingMode = WINDOWING_MODE_UNDEFINED; final ActivityOptions activityOptions = (bOptions != null) ? new ActivityOptions(bOptions) : null; - final int launchStackId = (activityOptions != null) - ? activityOptions.getLaunchStackId() : INVALID_STACK_ID; - if (StackId.isHomeOrRecentsStack(launchStackId)) { + if (activityOptions != null) { + activityType = activityOptions.getLaunchActivityType(); + windowingMode = activityOptions.getLaunchWindowingMode(); + } + if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { throw new IllegalArgumentException("startActivityFromRecentsInner: Task " + taskId + " can't be launch in the home/recents stack."); } mWindowManager.deferSurfaceLayout(); try { - if (launchStackId == DOCKED_STACK_ID) { + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { mWindowManager.setDockedStackCreateState( activityOptions.getDockCreateMode(), null /* initialBounds */); @@ -4447,7 +4637,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, - launchStackId); + activityOptions); if (task == null) { continueUpdateBounds(RECENTS_STACK_ID); mWindowManager.executeAppTransition(); @@ -4458,14 +4648,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Since we don't have an actual source record here, we assume that the currently // focused activity was the source. final ActivityStack focusedStack = getFocusedStack(); - final ActivityRecord sourceRecord = - focusedStack != null ? focusedStack.topActivity() : null; + final ActivityRecord sourceRecord = focusedStack != null + ? focusedStack.topActivity() : null; + final int stackId = getLaunchStackId(null, activityOptions, task); - if (launchStackId != INVALID_STACK_ID) { - if (task.getStackId() != launchStackId) { - task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, - DEFER_RESUME, "startActivityFromRecents"); - } + if (stackId != INVALID_STACK_ID && task.getStackId() != stackId) { + task.reparent(stackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, + "startActivityFromRecents"); } // If the user must confirm credentials (e.g. when first launching a work app and the @@ -4484,7 +4673,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // If we are launching the task in the docked stack, put it into resizing mode so // the window renders full-screen with the background filling the void. Also only // call this at the end to make sure that tasks exists on the window manager side. - if (launchStackId == DOCKED_STACK_ID) { + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { setResizingDuringAnimation(task); } @@ -4502,7 +4691,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D userId = task.userId; int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null, null, null, 0, 0, bOptions, userId, task, "startActivityFromRecents"); - if (launchStackId == DOCKED_STACK_ID) { + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { setResizingDuringAnimation(task); } return result; diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 16abcfb620d9..d94e866b312b 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -39,6 +39,8 @@ import static android.app.ActivityManager.StackId.isDynamicStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -1024,10 +1026,12 @@ class ActivityStarter { ActivityRecord reusedActivity = getReusableIntentActivity(); - final int preferredLaunchStackId = - (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID; - final int preferredLaunchDisplayId = - (mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY; + int preferredWindowingMode = WINDOWING_MODE_UNDEFINED; + int preferredLaunchDisplayId = DEFAULT_DISPLAY; + if (mOptions != null) { + preferredWindowingMode = mOptions.getLaunchWindowingMode(); + preferredLaunchDisplayId = mOptions.getLaunchDisplayId(); + } if (reusedActivity != null) { // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but @@ -1158,7 +1162,7 @@ class ActivityStarter { // Don't use mStartActivity.task to show the toast. We're not starting a new activity // but reusing 'top'. Fields in mStartActivity may not be fully initialized. - mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId, + mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode, preferredLaunchDisplayId, topStack.mStackId); return START_DELIVERED_TO_TOP; @@ -1173,8 +1177,7 @@ class ActivityStarter { if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) { newTask = true; - result = setTaskFromReuseOrCreateNewTask( - taskToAffiliate, preferredLaunchStackId, topStack); + result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack); } else if (mSourceRecord != null) { result = setTaskFromSourceRecord(); } else if (mInTask != null) { @@ -1241,7 +1244,7 @@ class ActivityStarter { } mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); - mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId, + mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode, preferredLaunchDisplayId, mTargetStack.mStackId); return START_SUCCESS; @@ -1654,8 +1657,8 @@ class ActivityStarter { mTargetStack.moveToFront("intentActivityFound"); } - mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID, - DEFAULT_DISPLAY, mTargetStack.mStackId); + mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), + WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId); // If the caller has requested that the target task be reset, then do so. if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { @@ -1675,8 +1678,7 @@ class ActivityStarter { // Task will be launched over the home stack, so return home. task.setTaskToReturnTo(ACTIVITY_TYPE_HOME); return; - } else if (focusedStack != null && focusedStack != task.getStack() && - focusedStack.isActivityTypeAssistant()) { + } else if (focusedStack != task.getStack() && focusedStack.isActivityTypeAssistant()) { // Task was launched over the assistant stack, so return there task.setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT); return; @@ -1779,7 +1781,7 @@ class ActivityStarter { } private int setTaskFromReuseOrCreateNewTask( - TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) { + TaskRecord taskToAffiliate, ActivityStack topStack) { mTargetStack = computeStackFocus( mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions); @@ -1821,8 +1823,10 @@ class ActivityStarter { // If stack id is specified in activity options, usually it means that activity is // launched not from currently focused stack (e.g. from SysUI or from shell) - in // that case we check the target stack. + // TODO: Not sure I understand the value or use of the commented out code and the + // comment above. See if this causes any issues and why... updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags, - preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack); + /*preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : */topStack); } if (mDoResume) { mTargetStack.moveToFront("reuseOrNewTask"); @@ -1964,7 +1968,8 @@ class ActivityStarter { if (mLaunchBounds != null) { mInTask.updateOverrideConfiguration(mLaunchBounds); - int stackId = mInTask.getLaunchStackId(); + // TODO: Shouldn't we already know what stack to use by the time we get here? + int stackId = mSupervisor.getLaunchStackId(null, null, mInTask); if (stackId != mInTask.getStackId()) { mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, "inTaskToFront"); @@ -2102,9 +2107,10 @@ class ActivityStarter { } } // If there is no suitable dynamic stack then we figure out which static stack to use. - final int stackId = task != null ? task.getLaunchStackId() : - bounds != null ? FREEFORM_WORKSPACE_STACK_ID : - FULLSCREEN_WORKSPACE_STACK_ID; + final int stackId = task != null ? mSupervisor.getLaunchStackId(r, aOptions, task) + // TODO: This should go in mSupervisor.getLaunchStackId method... + : bounds != null && mService.mSupportsFreeformWindowManagement + ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID; stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP); } if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r=" @@ -2165,18 +2171,16 @@ class ActivityStarter { return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP); } - final int launchDisplayId = - (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY; - - final int launchStackId = - (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID; - - if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) { - throw new IllegalArgumentException( - "Stack and display id can't be set at the same time."); + int launchDisplayId = INVALID_DISPLAY; + int launchStackId = INVALID_STACK_ID; + if (aOptions != null) { + launchDisplayId = aOptions.getLaunchDisplayId(); + final int vrDisplayId = mUsingVr2dDisplay ? mSourceDisplayId : INVALID_DISPLAY; + launchStackId = mSupervisor.getLaunchStackId(r, aOptions, task, vrDisplayId); } - if (isValidLaunchStackId(launchStackId, launchDisplayId, r)) { + // TODO: Will no longer be needed once we are on longer using static stack ids. + if (mSupervisor.isValidLaunchStackId(launchStackId, launchDisplayId, r)) { return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP); } if (launchStackId == DOCKED_STACK_ID) { @@ -2184,12 +2188,14 @@ class ActivityStarter { // for this activity, so we put the activity in the fullscreen stack. return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP); } + // TODO: Can probably be removed since ASS.getLaunchStackId() does display resolution. if (launchDisplayId != INVALID_DISPLAY) { // Stack id has higher priority than display id. return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r); } // If we are using Vr2d display, find the virtual display stack. + // TODO: Can be removed. if (mUsingVr2dDisplay) { ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r); if (DEBUG_STACK) { @@ -2240,39 +2246,11 @@ class ActivityStarter { } } - boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) { - switch (stackId) { - case INVALID_STACK_ID: - case HOME_STACK_ID: - return false; - case FULLSCREEN_WORKSPACE_STACK_ID: - return true; - case FREEFORM_WORKSPACE_STACK_ID: - return r.supportsFreeform(); - case DOCKED_STACK_ID: - return r.supportsSplitScreen(); - case PINNED_STACK_ID: - return r.supportsPictureInPicture(); - case RECENTS_STACK_ID: - return r.isActivityTypeRecents(); - case ASSISTANT_STACK_ID: - return r.isActivityTypeAssistant(); - default: - if (StackId.isDynamicStack(stackId)) { - return r.canBeLaunchedOnDisplay(displayId); - } - Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId); - return false; - } - } - - Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) { + private Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) { Rect newBounds = null; - if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) { - if (mSupervisor.canUseActivityOptionsLaunchBounds( - options, options.getLaunchStackId())) { - newBounds = TaskRecord.validateBounds(options.getLaunchBounds()); - } + if (mSupervisor.canUseActivityOptionsLaunchBounds(options) + && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) { + newBounds = TaskRecord.validateBounds(options.getLaunchBounds()); } return newBounds; } diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index 241e58391144..72b5de88e50f 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -25,6 +25,7 @@ import static android.app.StatusBarManager.DISABLE_HOME; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.StatusBarManager.DISABLE_RECENT; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.STATUS_BAR_SERVICE; import static android.os.UserHandle.USER_ALL; @@ -431,8 +432,8 @@ public class LockTaskController { mSupervisor.resumeFocusedStackTopActivityLocked(); mWindowManager.executeAppTransition(); } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { - mSupervisor.handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY, - task.getStackId(), true /* forceNonResizable */); + mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, + DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */); } } diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 74c4826f583b..f6e20cd2e1b4 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -472,8 +472,7 @@ public class TaskPersister { final int taskId = task.taskId; if (mStackSupervisor.anyTaskForIdLocked(taskId, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, - INVALID_STACK_ID) != null) { + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { // Should not happen. Slog.wtf(TAG, "Existing task with taskId " + taskId + "found"); } else if (userId != task.userId) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 48da6555e75c..28b71d9c978d 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -26,6 +26,7 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; +import static android.app.ActivityManager.StackId.getWindowingModeForStackId; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -507,8 +508,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi updateOverrideConfiguration(bounds); if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) { // re-restore the task so it can have the proper stack association. - mService.mStackSupervisor.restoreRecentTaskLocked(this, - FREEFORM_WORKSPACE_STACK_ID); + mService.mStackSupervisor.restoreRecentTaskLocked(this, null); } return true; } @@ -729,7 +729,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } // TODO: Handle incorrect request to move before the actual move, not after. - supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, DEFAULT_DISPLAY, stackId); + supervisor.handleNonResizableTaskIfNeeded(this, getWindowingModeForStackId(preferredStackId, + supervisor.getStack(DOCKED_STACK_ID) != null), DEFAULT_DISPLAY, stackId); boolean successful = (preferredStackId == stackId); if (successful && stackId == DOCKED_STACK_ID) { @@ -2079,27 +2080,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } } - /** - * Returns the correct stack to use based on task type and currently set bounds, - * regardless of the focused stack and current stack association of the task. - * The task will be moved (and stack focus changed) later if necessary. - */ - int getLaunchStackId() { - if (isActivityTypeRecents()) { - return RECENTS_STACK_ID; - } - if (isActivityTypeHome()) { - return HOME_STACK_ID; - } - if (isActivityTypeAssistant()) { - return ASSISTANT_STACK_ID; - } - if (mBounds != null) { - return FREEFORM_WORKSPACE_STACK_ID; - } - return FULLSCREEN_WORKSPACE_STACK_ID; - } - /** Returns the bounds that should be used to launch this task. */ private Rect getLaunchBounds() { if (mStack == null) { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 661dd4fc828c..cd1843b37ae2 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -17,7 +17,10 @@ package com.android.server.am; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -60,7 +63,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { public void testRestoringInvalidTask() throws Exception { final ActivityManagerService service = createActivityManagerService(); TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/, - MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/); + MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null); assertNull(task); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 3788cf331600..b040a6324dbb 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.START_ASSISTANT_HIDDEN_SESSION; import static android.app.ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION; import static android.app.ActivityManager.START_VOICE_HIDDEN_SESSION; import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import android.app.ActivityManager; import android.app.ActivityManager.StackId; @@ -222,8 +223,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } intent = new Intent(intent); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchStackId(StackId.ASSISTANT_STACK_ID); + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchActivityType(ACTIVITY_TYPE_ASSISTANT); return mAm.startAssistantActivity(mComponent.getPackageName(), callingPid, callingUid, intent, resolvedType, options.toBundle(), mUser); } catch (RemoteException e) { |