diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java index fe97e24fac416..982cc006e331c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java @@ -25,6 +25,7 @@ import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.io.PrintWriter; import java.util.Optional; @@ -38,7 +39,7 @@ public final class ShellCommandHandlerImpl { private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName(); private final Optional mLegacySplitScreenOptional; - private final Optional mSplitScreenOptional; + private final Optional mSplitScreenOptional; private final Optional mPipOptional; private final Optional mOneHandedOptional; private final Optional mHideDisplayCutout; @@ -50,7 +51,7 @@ public final class ShellCommandHandlerImpl { public static ShellCommandHandler create( ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional pipOptional, Optional oneHandedOptional, Optional hideDisplayCutout, @@ -64,7 +65,7 @@ public final class ShellCommandHandlerImpl { private ShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional pipOptional, Optional oneHandedOptional, Optional hideDisplayCutout, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index 0958a070c82df..925bf4bbb01c1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -25,6 +25,7 @@ import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -39,7 +40,7 @@ public class ShellInitImpl { private final DragAndDropController mDragAndDropController; private final ShellTaskOrganizer mShellTaskOrganizer; private final Optional mLegacySplitScreenOptional; - private final Optional mSplitScreenOptional; + private final Optional mSplitScreenOptional; private final Optional mAppPairsOptional; private final FullscreenTaskListener mFullscreenTaskListener; private final ShellExecutor mMainExecutor; @@ -51,7 +52,7 @@ public class ShellInitImpl { DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional appPairsOptional, FullscreenTaskListener fullscreenTaskListener, Transitions transitions, @@ -71,7 +72,7 @@ public class ShellInitImpl { DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional appPairsOptional, FullscreenTaskListener fullscreenTaskListener, Transitions transitions, @@ -97,7 +98,7 @@ public class ShellInitImpl { mShellTaskOrganizer.registerOrganizer(); mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered); - mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered); + mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered); // Bind the splitscreen impl to the drag drop controller mDragAndDropController.initialize(mSplitScreenOptional); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index c8938ad40aba9..17709438baba0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -53,6 +53,7 @@ import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.Optional; @@ -66,7 +67,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private final Context mContext; private final DisplayController mDisplayController; - private SplitScreen mSplitScreen; + private SplitScreenController mSplitScreen; private final SparseArray mDisplayDropTargets = new SparseArray<>(); private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); @@ -76,7 +77,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mDisplayController = displayController; } - public void initialize(Optional splitscreen) { + public void initialize(Optional splitscreen) { mSplitScreen = splitscreen.orElse(null); mDisplayController.addDisplayWindowListener(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index 35dcdd5923a80..6f5f2eb5723c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -64,7 +64,9 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreen.StagePosition; +import com.android.wm.shell.splitscreen.SplitScreen.StageType; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -81,18 +83,18 @@ public class DragAndDropPolicy { private final Context mContext; private final ActivityTaskManager mActivityTaskManager; private final Starter mStarter; - private final SplitScreen mSplitScreen; + private final SplitScreenController mSplitScreen; private final ArrayList mTargets = new ArrayList<>(); private DragSession mSession; - public DragAndDropPolicy(Context context, SplitScreen splitScreen) { + public DragAndDropPolicy(Context context, SplitScreenController splitScreen) { this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context)); } @VisibleForTesting DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager, - SplitScreen splitScreen, Starter starter) { + SplitScreenController splitScreen, Starter starter) { mContext = context; mActivityTaskManager = activityTaskManager; mSplitScreen = splitScreen; @@ -200,8 +202,8 @@ public class DragAndDropPolicy { final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible(); final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT; - @SplitScreen.StageType int stage = STAGE_TYPE_UNDEFINED; - @SplitScreen.StagePosition int position = STAGE_POSITION_UNDEFINED; + @StageType int stage = STAGE_TYPE_UNDEFINED; + @StagePosition int position = STAGE_POSITION_UNDEFINED; if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) { // Update launch options for the split side we are targeting. position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT; @@ -213,7 +215,28 @@ public class DragAndDropPolicy { final ClipDescription description = data.getDescription(); final Intent dragData = mSession.dragData; - mStarter.startClipDescription(description, dragData, stage, position); + startClipDescription(description, dragData, stage, position); + } + + private void startClipDescription(ClipDescription description, Intent intent, + @StageType int stage, @StagePosition int position) { + final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); + final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); + final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) + ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle(); + + if (isTask) { + final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); + mStarter.startTask(taskId, stage, position, opts); + } else if (isShortcut) { + final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID); + final UserHandle user = intent.getParcelableExtra(EXTRA_USER); + mStarter.startShortcut(packageName, id, stage, position, opts, user); + } else { + mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position, + opts); + } } /** @@ -267,34 +290,13 @@ public class DragAndDropPolicy { /** * Interface for actually committing the task launches. */ - @VisibleForTesting public interface Starter { - default void startClipDescription(ClipDescription description, Intent intent, - @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position) { - final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); - final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); - final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) - ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle(); - - if (isTask) { - final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); - startTask(taskId, stage, position, opts); - } else if (isShortcut) { - final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID); - final UserHandle user = intent.getParcelableExtra(EXTRA_USER); - startShortcut(packageName, id, stage, position, opts, user); - } else { - startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position, opts); - } - } - void startTask(int taskId, @SplitScreen.StageType int stage, - @SplitScreen.StagePosition int position, @Nullable Bundle options); - void startShortcut(String packageName, String shortcutId, - @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position, - @Nullable Bundle options, UserHandle user); - void startIntent(PendingIntent intent, @SplitScreen.StageType int stage, - @SplitScreen.StagePosition int position, @Nullable Bundle options); + void startTask(int taskId, @StageType int stage, @StagePosition int position, + @Nullable Bundle options); + void startShortcut(String packageName, String shortcutId, @StageType int stage, + @StagePosition int position, @Nullable Bundle options, UserHandle user); + void startIntent(PendingIntent intent, @StageType int stage, @StagePosition int position, + @Nullable Bundle options); void enterSplitScreen(int taskId, boolean leftOrTop); void exitSplitScreen(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 82c4e440fb159..b3423362347fd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -42,7 +42,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.protolog.ShellProtoLogGroup; -import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.ArrayList; @@ -61,7 +61,7 @@ public class DragLayout extends View { private boolean mIsShowing; private boolean mHasDropped; - public DragLayout(Context context, SplitScreen splitscreen) { + public DragLayout(Context context, SplitScreenController splitscreen) { super(context); mPolicy = new DragAndDropPolicy(context, splitscreen); mDisplayMargin = context.getResources().getDimensionPixelSize( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java index 2c6809259459b..177646b22ea39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java @@ -33,6 +33,7 @@ import java.io.PrintWriter; /** * Interface to engage split-screen feature. + * TODO: Figure out which of these are actually needed outside of the Shell */ @ExternalThread public interface SplitScreen extends DragAndDropPolicy.Starter { @@ -102,18 +103,11 @@ public interface SplitScreen extends DragAndDropPolicy.Starter { void setSideStagePosition(@StagePosition int sideStagePosition); /** Hides the side-stage if it is currently visible. */ void setSideStageVisibility(boolean visible); - default void enterSplitScreen(int taskId, boolean leftOrTop) { - moveToSideStage(taskId, - leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT); - } + /** Removes the split-screen stages. */ void exitSplitScreen(); /** Gets the stage bounds. */ void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds); - /** Dumps current status of split-screen. */ - void dump(@NonNull PrintWriter pw, String prefix); - /** Called when the shell organizer has been registered. */ - void onOrganizerRegistered(); void registerSplitScreenListener(SplitScreenListener listener); void unregisterSplitScreenListener(SplitScreenListener listener); 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 18dd53b90ff44..bbad36dcc0469 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 @@ -18,6 +18,13 @@ package com.android.wm.shell.splitscreen; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; + import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.PendingIntent; @@ -35,7 +42,9 @@ import androidx.annotation.Nullable; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.draganddrop.DragAndDropPolicy; import java.io.PrintWriter; @@ -44,25 +53,33 @@ import java.io.PrintWriter; * {@link SplitScreen}. * @see StageCoordinator */ -public class SplitScreenController implements SplitScreen { +public class SplitScreenController implements DragAndDropPolicy.Starter { private static final String TAG = SplitScreenController.class.getSimpleName(); private final ShellTaskOrganizer mTaskOrganizer; private final SyncTransactionQueue mSyncQueue; private final Context mContext; private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; + private final ShellExecutor mMainExecutor; + private final SplitScreenImpl mImpl = new SplitScreenImpl(); + private StageCoordinator mStageCoordinator; public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, - RootTaskDisplayAreaOrganizer rootTDAOrganizer) { + RootTaskDisplayAreaOrganizer rootTDAOrganizer, + ShellExecutor mainExecutor) { mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; mContext = context; mRootTDAOrganizer = rootTDAOrganizer; + mMainExecutor = mainExecutor; + } + + public SplitScreen asSplitScreen() { + return mImpl; } - @Override public void onOrganizerRegistered() { if (mStageCoordinator == null) { // TODO: Multi-display @@ -71,13 +88,11 @@ public class SplitScreenController implements SplitScreen { } } - @Override public boolean isSplitScreenVisible() { return mStageCoordinator.isSplitScreenVisible(); } - @Override - public boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition) { + public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) { final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId); if (task == null) { throw new IllegalArgumentException("Unknown taskId" + taskId); @@ -85,50 +100,46 @@ public class SplitScreenController implements SplitScreen { return moveToSideStage(task, sideStagePosition); } - @Override public boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - @StagePosition int sideStagePosition) { + @SplitScreen.StagePosition int sideStagePosition) { return mStageCoordinator.moveToSideStage(task, sideStagePosition); } - @Override public boolean removeFromSideStage(int taskId) { return mStageCoordinator.removeFromSideStage(taskId); } - @Override - public void setSideStagePosition(@StagePosition int sideStagePosition) { + public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) { mStageCoordinator.setSideStagePosition(sideStagePosition); } - @Override public void setSideStageVisibility(boolean visible) { mStageCoordinator.setSideStageVisibility(visible); } - @Override + public void enterSplitScreen(int taskId, boolean leftOrTop) { + moveToSideStage(taskId, + leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT); + } + public void exitSplitScreen() { mStageCoordinator.exitSplitScreen(); } - @Override public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds); } - @Override - public void registerSplitScreenListener(SplitScreenListener listener) { + public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) { mStageCoordinator.registerSplitScreenListener(listener); } - @Override - public void unregisterSplitScreenListener(SplitScreenListener listener) { + public void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) { mStageCoordinator.unregisterSplitScreenListener(listener); } - @Override - public void startTask(int taskId, - @StageType int stage, @StagePosition int position, @Nullable Bundle options) { + public void startTask(int taskId, @SplitScreen.StageType int stage, + @SplitScreen.StagePosition int position, @Nullable Bundle options) { options = resolveStartStage(stage, position, options); try { @@ -138,9 +149,9 @@ public class SplitScreenController implements SplitScreen { } } - @Override - public void startShortcut(String packageName, String shortcutId, @StageType int stage, - @StagePosition int position, @Nullable Bundle options, UserHandle user) { + public void startShortcut(String packageName, String shortcutId, + @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position, + @Nullable Bundle options, UserHandle user) { options = resolveStartStage(stage, position, options); try { @@ -153,9 +164,8 @@ public class SplitScreenController implements SplitScreen { } } - @Override - public void startIntent(PendingIntent intent, - @StageType int stage, @StagePosition int position, @Nullable Bundle options) { + public void startIntent(PendingIntent intent, @SplitScreen.StageType int stage, + @SplitScreen.StagePosition int position, @Nullable Bundle options) { options = resolveStartStage(stage, position, options); try { @@ -165,8 +175,8 @@ public class SplitScreenController implements SplitScreen { } } - private Bundle resolveStartStage(@StageType int stage, @StagePosition int position, - @Nullable Bundle options) { + private Bundle resolveStartStage(@SplitScreen.StageType int stage, + @SplitScreen.StagePosition int position, @Nullable Bundle options) { switch (stage) { case STAGE_TYPE_UNDEFINED: { // Use the stage of the specified position is valid. @@ -216,7 +226,6 @@ public class SplitScreenController implements SplitScreen { return options; } - @Override public void dump(@NonNull PrintWriter pw, String prefix) { pw.println(prefix + TAG); if (mStageCoordinator != null) { @@ -224,4 +233,113 @@ public class SplitScreenController implements SplitScreen { } } + private class SplitScreenImpl implements SplitScreen { + @Override + public boolean isSplitScreenVisible() { + return mMainExecutor.executeBlockingForResult(() -> { + return SplitScreenController.this.isSplitScreenVisible(); + }, Boolean.class); + } + + @Override + public boolean moveToSideStage(int taskId, int sideStagePosition) { + return mMainExecutor.executeBlockingForResult(() -> { + return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition); + }, Boolean.class); + } + + @Override + public boolean moveToSideStage(ActivityManager.RunningTaskInfo task, + int sideStagePosition) { + return mMainExecutor.executeBlockingForResult(() -> { + return SplitScreenController.this.moveToSideStage(task, sideStagePosition); + }, Boolean.class); + } + + @Override + public boolean removeFromSideStage(int taskId) { + return mMainExecutor.executeBlockingForResult(() -> { + return SplitScreenController.this.removeFromSideStage(taskId); + }, Boolean.class); + } + + @Override + public void setSideStagePosition(int sideStagePosition) { + mMainExecutor.execute(() -> { + SplitScreenController.this.setSideStagePosition(sideStagePosition); + }); + } + + @Override + public void setSideStageVisibility(boolean visible) { + mMainExecutor.execute(() -> { + SplitScreenController.this.setSideStageVisibility(visible); + }); + } + + @Override + public void enterSplitScreen(int taskId, boolean leftOrTop) { + mMainExecutor.execute(() -> { + SplitScreenController.this.enterSplitScreen(taskId, leftOrTop); + }); + } + + @Override + public void exitSplitScreen() { + mMainExecutor.execute(() -> { + SplitScreenController.this.exitSplitScreen(); + }); + } + + @Override + public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { + try { + mMainExecutor.executeBlocking(() -> { + SplitScreenController.this.getStageBounds(outTopOrLeftBounds, + outBottomOrRightBounds); + }); + } catch (InterruptedException e) { + Slog.e(TAG, "Failed to get stage bounds in 2s"); + } + } + + @Override + public void registerSplitScreenListener(SplitScreenListener listener) { + mMainExecutor.execute(() -> { + SplitScreenController.this.registerSplitScreenListener(listener); + }); + } + + @Override + public void unregisterSplitScreenListener(SplitScreenListener listener) { + mMainExecutor.execute(() -> { + SplitScreenController.this.unregisterSplitScreenListener(listener); + }); + } + + @Override + public void startTask(int taskId, int stage, int position, @Nullable Bundle options) { + mMainExecutor.execute(() -> { + SplitScreenController.this.startTask(taskId, stage, position, options); + }); + } + + @Override + public void startShortcut(String packageName, String shortcutId, int stage, int position, + @Nullable Bundle options, UserHandle user) { + mMainExecutor.execute(() -> { + SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position, + options, user); + }); + } + + @Override + public void startIntent(PendingIntent intent, int stage, int position, + @Nullable Bundle options) { + mMainExecutor.execute(() -> { + SplitScreenController.this.startIntent(intent, stage, position, options); + }); + } + } + } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java index 25721066b7130..19ecc49513e51 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java @@ -44,6 +44,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.ActivityManager; @@ -65,7 +66,7 @@ import androidx.test.filters.SmallTest; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target; -import com.android.wm.shell.splitscreen.SplitScreen; +import com.android.wm.shell.splitscreen.SplitScreenController; import org.junit.Before; import org.junit.Test; @@ -92,7 +93,7 @@ public class DragAndDropPolicyTest { // Both the split-screen and start interface. @Mock - private SplitScreen mSplitScreenStarter; + private SplitScreenController mSplitScreenStarter; private DisplayLayout mLandscapeDisplayLayout; private DisplayLayout mPortraitDisplayLayout; @@ -127,8 +128,8 @@ public class DragAndDropPolicyTest { mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false); mInsets = Insets.of(0, 0, 0, 0); - mPolicy = new DragAndDropPolicy( - mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter); + mPolicy = spy(new DragAndDropPolicy( + mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter)); mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); setClipDataResizeable(mNonResizeableActivityClipData, false); @@ -204,8 +205,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @Test @@ -216,13 +217,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @Test @@ -233,13 +234,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @Test @@ -250,8 +251,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @Test @@ -262,8 +263,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); } @Test @@ -275,14 +276,14 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @Test @@ -294,14 +295,14 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any()); reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mSplitScreenStarter).startClipDescription(any(), any(), - eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); + verify(mSplitScreenStarter).startIntent(any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any()); } @Test diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 36506bf5715cc..b42dde63d1c2b 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -180,7 +180,7 @@ public abstract class WMShellBaseModule { DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional appPairsOptional, FullscreenTaskListener fullscreenTaskListener, Transitions transitions, @@ -205,7 +205,7 @@ public abstract class WMShellBaseModule { static Optional provideShellCommandHandler( ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, - Optional splitScreenOptional, + Optional splitScreenOptional, Optional pipOptional, Optional oneHandedOptional, Optional hideDisplayCutout, @@ -320,12 +320,21 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static Optional provideSplitScreen(ShellTaskOrganizer shellTaskOrganizer, + static Optional provideSplitScreen( + Optional splitScreenController) { + return splitScreenController.map((controller) -> controller.asSplitScreen()); + } + + @WMSingleton + @Provides + static Optional provideSplitScreenController( + ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + @ShellMainThread ShellExecutor mainExecutor) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, - rootTaskDisplayAreaOrganizer)); + rootTaskDisplayAreaOrganizer, mainExecutor)); } else { return Optional.empty(); }