diff options
9 files changed, 65 insertions, 29 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index a87b91d87f1c..3bffa890122a 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -348,8 +348,10 @@ public final class WindowContainerTransaction implements Parcelable { * @param currentParent of the tasks to perform the operation no. * {@code null} will perform the operation on the display. * @param newParent for the tasks. {@code null} will perform the operation on the display. - * @param windowingModes of the tasks to reparent. - * @param activityTypes of the tasks to reparent. + * @param windowingModes of the tasks to reparent. {@code null} ignore this attribute when + * perform the operation. + * @param activityTypes of the tasks to reparent. {@code null} ignore this attribute when + * perform the operation. * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to * the bottom. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java index 9b614875119b..afc706ee9c8e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java @@ -15,6 +15,11 @@ */ package com.android.wm.shell.common.split; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import android.annotation.IntDef; /** Helper utility class of methods and constants that are available to be imported in Launcher. */ @@ -44,4 +49,10 @@ public class SplitScreenConstants { }) public @interface SplitPosition { } + + public static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; + public static final int[] CONTROLLED_WINDOWING_MODES = + {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; + public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE = + {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW}; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index 2bfa5db502ce..e7ec15e70c11 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -16,6 +16,9 @@ package com.android.wm.shell.splitscreen; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; + import android.content.Context; import android.view.SurfaceSession; import android.window.WindowContainerToken; @@ -74,10 +77,10 @@ class MainStage extends StageTaskListener { if (mRootTaskInfo == null) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.reparentTasks( - rootToken, - null /* newParent */, - CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, - CONTROLLED_ACTIVITY_TYPES, - toTop); + rootToken, + null /* newParent */, + null /* windowingModes */, + null /* activityTypes */, + toTop); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java index f92a0d3901b9..8639b36faf4c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java @@ -47,8 +47,8 @@ class SideStage extends StageTaskListener { wct.reparentTasks( mRootTaskInfo.token, null /* newParent */, - CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, - CONTROLLED_ACTIVITY_TYPES, + null /* windowingModes */, + null /* activityTypes */, toTop); return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index c8ee010e60e0..47bfaa64c831 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -26,6 +26,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; @@ -64,6 +66,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; +import com.android.internal.util.ArrayUtils; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -227,6 +230,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED; } + public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) { + return taskInfo.supportsMultiWindow + && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()); + } + public @SplitPosition int getSplitPosition(int taskId) { return mStageCoordinator.getSplitPosition(taskId); } @@ -463,11 +472,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return Objects.equals(launchingActivity, pairedActivity); } - if (mFocusingTaskInfo != null - // TODO (b/238032411): have an API to determine whether an activity is valid for - // split screen or not. - && mFocusingTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN - && mFocusingTaskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { + if (mFocusingTaskInfo != null && isValidToEnterSplitScreen(mFocusingTaskInfo)) { return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 70d728d90b6a..e19c572c4850 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -87,6 +87,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; +import android.widget.Toast; import android.window.DisplayAreaInfo; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -98,6 +99,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.InstanceId; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -1921,10 +1923,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onNoLongerSupportMultiWindow() { if (mMainStage.isActive()) { + final Toast splitUnsupportedToast = Toast.makeText(mContext, + R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT); final boolean isMainStage = mMainStageListener == this; if (!ENABLE_SHELL_TRANSITIONS) { StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); + splitUnsupportedToast.show(); return; } @@ -1933,6 +1938,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, prepareExitSplitScreen(stageType, wct); mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); + splitUnsupportedToast.show(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index cb9e1a39ec52..d17ff7aff667 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -17,12 +17,12 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import android.annotation.CallSuper; @@ -40,6 +40,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; +import com.android.internal.util.ArrayUtils; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SurfaceUtils; @@ -62,12 +63,6 @@ import java.util.function.Predicate; class StageTaskListener implements ShellTaskOrganizer.TaskListener { private static final String TAG = StageTaskListener.class.getSimpleName(); - protected static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; - protected static final int[] CONTROLLED_WINDOWING_MODES = - {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; - protected static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE = - {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW}; - /** Callback interface for listening to changes in a split-screen stage. */ public interface StageListenerCallbacks { void onRootTaskAppeared(); @@ -212,12 +207,15 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } mRootTaskInfo = taskInfo; } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { - if (!taskInfo.supportsMultiWindow) { - // Leave split screen if the task no longer supports multi window. + if (!taskInfo.supportsMultiWindow + || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + || !ArrayUtils.contains(CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, + taskInfo.getWindowingMode())) { + // Leave split screen if the task no longer supports multi window or have + // uncontrolled task. mCallbacks.onNoLongerSupportMultiWindow(); return; } - mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, taskInfo.isVisible); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index e9c1acbf7ca0..e3f568732b9d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -18,6 +18,9 @@ package com.android.systemui.shared.recents.model; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; + import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.app.TaskInfo; @@ -31,6 +34,8 @@ import android.view.ViewDebug; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.util.ArrayUtils; + import java.io.PrintWriter; import java.util.Objects; @@ -242,8 +247,10 @@ public class Task { ActivityManager.TaskDescription td = taskInfo.taskDescription; return new Task(taskKey, td != null ? td.getPrimaryColor() : 0, - td != null ? td.getBackgroundColor() : 0, - taskInfo.supportsMultiWindow, isLocked, td, taskInfo.topActivity); + td != null ? td.getBackgroundColor() : 0, taskInfo.supportsMultiWindow + && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) + && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()), + isLocked, td, taskInfo.topActivity); } public Task(TaskKey key) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 4bbb1b1fb745..6bb5eceec84e 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1235,8 +1235,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + " task=" + task); return false; } - if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType()) - || !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { + if (!ArrayUtils.isEmpty(hop.getActivityTypes()) + && !ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) { + return false; + } + if (!ArrayUtils.isEmpty(hop.getWindowingModes()) + && !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { return false; } if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) { |