Merge "Handle the uncontrolled task in split-screen" into tm-qpr-dev

This commit is contained in:
Jeff Chang
2022-07-11 05:47:58 +00:00
committed by Android (Google) Code Review
9 changed files with 65 additions and 29 deletions

View File

@@ -348,8 +348,10 @@ public final class WindowContainerTransaction implements Parcelable {
* @param currentParent of the tasks to perform the operation no. * @param currentParent of the tasks to perform the operation no.
* {@code null} will perform the operation on the display. * {@code null} will perform the operation on the display.
* @param newParent for the tasks. {@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 windowingModes of the tasks to reparent. {@code null} ignore this attribute when
* @param activityTypes of the tasks to reparent. * 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 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
* the bottom. * the bottom.
*/ */

View File

@@ -15,6 +15,11 @@
*/ */
package com.android.wm.shell.common.split; 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; import android.annotation.IntDef;
/** Helper utility class of methods and constants that are available to be imported in Launcher. */ /** 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 @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};
} }

View File

@@ -16,6 +16,9 @@
package com.android.wm.shell.splitscreen; 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.content.Context;
import android.view.SurfaceSession; import android.view.SurfaceSession;
import android.window.WindowContainerToken; import android.window.WindowContainerToken;
@@ -74,10 +77,10 @@ class MainStage extends StageTaskListener {
if (mRootTaskInfo == null) return; if (mRootTaskInfo == null) return;
final WindowContainerToken rootToken = mRootTaskInfo.token; final WindowContainerToken rootToken = mRootTaskInfo.token;
wct.reparentTasks( wct.reparentTasks(
rootToken, rootToken,
null /* newParent */, null /* newParent */,
CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, null /* windowingModes */,
CONTROLLED_ACTIVITY_TYPES, null /* activityTypes */,
toTop); toTop);
} }
} }

View File

@@ -47,8 +47,8 @@ class SideStage extends StageTaskListener {
wct.reparentTasks( wct.reparentTasks(
mRootTaskInfo.token, mRootTaskInfo.token,
null /* newParent */, null /* newParent */,
CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, null /* windowingModes */,
CONTROLLED_ACTIVITY_TYPES, null /* activityTypes */,
toTop); toTop);
return true; return true;
} }

View File

@@ -26,6 +26,8 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; 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_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_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; 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.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
@@ -227,6 +230,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
&& mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED; && 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) { public @SplitPosition int getSplitPosition(int taskId) {
return mStageCoordinator.getSplitPosition(taskId); return mStageCoordinator.getSplitPosition(taskId);
} }
@@ -463,11 +472,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return Objects.equals(launchingActivity, pairedActivity); return Objects.equals(launchingActivity, pairedActivity);
} }
if (mFocusingTaskInfo != null if (mFocusingTaskInfo != null && isValidToEnterSplitScreen(mFocusingTaskInfo)) {
// 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) {
return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity); return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity);
} }

View File

@@ -87,6 +87,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.SurfaceSession; import android.view.SurfaceSession;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Toast;
import android.window.DisplayAreaInfo; import android.window.DisplayAreaInfo;
import android.window.RemoteTransition; import android.window.RemoteTransition;
import android.window.TransitionInfo; import android.window.TransitionInfo;
@@ -98,6 +99,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayImeController;
@@ -1921,10 +1923,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override @Override
public void onNoLongerSupportMultiWindow() { public void onNoLongerSupportMultiWindow() {
if (mMainStage.isActive()) { 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; final boolean isMainStage = mMainStageListener == this;
if (!ENABLE_SHELL_TRANSITIONS) { if (!ENABLE_SHELL_TRANSITIONS) {
StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage, StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
splitUnsupportedToast.show();
return; return;
} }
@@ -1933,6 +1938,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
prepareExitSplitScreen(stageType, wct); prepareExitSplitScreen(stageType, wct);
mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType, mSplitTransitions.startDismissTransition(wct,StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
splitUnsupportedToast.show();
} }
} }

View File

@@ -17,12 +17,12 @@
package com.android.wm.shell.splitscreen; package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID; 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_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 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 static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.annotation.CallSuper; import android.annotation.CallSuper;
@@ -40,6 +40,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SurfaceUtils; import com.android.wm.shell.common.SurfaceUtils;
@@ -62,12 +63,6 @@ import java.util.function.Predicate;
class StageTaskListener implements ShellTaskOrganizer.TaskListener { class StageTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = StageTaskListener.class.getSimpleName(); 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. */ /** Callback interface for listening to changes in a split-screen stage. */
public interface StageListenerCallbacks { public interface StageListenerCallbacks {
void onRootTaskAppeared(); void onRootTaskAppeared();
@@ -212,12 +207,15 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
} }
mRootTaskInfo = taskInfo; mRootTaskInfo = taskInfo;
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
if (!taskInfo.supportsMultiWindow) { if (!taskInfo.supportsMultiWindow
// Leave split screen if the task no longer supports multi window. || !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(); mCallbacks.onNoLongerSupportMultiWindow();
return; return;
} }
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
taskInfo.isVisible); taskInfo.isVisible);

View File

@@ -18,6 +18,9 @@ package com.android.systemui.shared.recents.model;
import static android.view.Display.DEFAULT_DISPLAY; 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;
import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskDescription;
import android.app.TaskInfo; import android.app.TaskInfo;
@@ -31,6 +34,8 @@ import android.view.ViewDebug;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Objects; import java.util.Objects;
@@ -242,8 +247,10 @@ public class Task {
ActivityManager.TaskDescription td = taskInfo.taskDescription; ActivityManager.TaskDescription td = taskInfo.taskDescription;
return new Task(taskKey, return new Task(taskKey,
td != null ? td.getPrimaryColor() : 0, td != null ? td.getPrimaryColor() : 0,
td != null ? td.getBackgroundColor() : 0, td != null ? td.getBackgroundColor() : 0, taskInfo.supportsMultiWindow
taskInfo.supportsMultiWindow, isLocked, td, taskInfo.topActivity); && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
&& ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()),
isLocked, td, taskInfo.topActivity);
} }
public Task(TaskKey key) { public Task(TaskKey key) {

View File

@@ -1235,8 +1235,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ " task=" + task); + " task=" + task);
return false; return false;
} }
if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType()) if (!ArrayUtils.isEmpty(hop.getActivityTypes())
|| !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { && !ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) {
return false;
}
if (!ArrayUtils.isEmpty(hop.getWindowingModes())
&& !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) {
return false; return false;
} }
if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) { if (isLockTaskModeViolation(finalNewParent, task, isInLockTaskMode)) {