diff options
| author | 2022-12-16 13:32:57 +0800 | |
|---|---|---|
| committer | 2023-02-10 11:36:00 +0800 | |
| commit | db4c59f87b68d98cc406d16c00155c279307aa19 (patch) | |
| tree | edf0cfa189f6e081e8aefbf0c4457d337ddf1f43 | |
| parent | c694f8b49455a3140fbb5a8c4afda47f335ac7b4 (diff) | |
Make PIP into split screen
Improve the interaction between split and PIP. e.g support drag and
drop pip app into split, start the pip into split, start Intent and
task into split.
Bug: 259161859
Test: PIP is activated and drag pip app into split.
Video :
https://drive.google.com/file/d/10VdfV7jfGHGRLrEdxAIWFKPhBVgwFTrI/view?usp=share_link&resourcekey=0-jZD7-EzUGc95WQIND3Jxrw
Change-Id: I2d72eeb2a799e94bb53fe42ce2b439644ec8520e
5 files changed, 122 insertions, 11 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java index 9e0a48b13413..e2106e478bb3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java @@ -216,7 +216,6 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. args.argi1 = homeTaskVisible ? 1 : 0; args.argi2 = clearedTask ? 1 : 0; args.argi3 = wasVisible ? 1 : 0; - mMainHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT); mMainHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index aad27b991db9..6412e80d671a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1404,7 +1404,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @PipAnimationController.TransitionDirection int direction, @PipAnimationController.AnimationType int type) { final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds()); - final boolean isPipTopLeft = isPipTopLeft(); mPipBoundsState.setBounds(destinationBounds); if (direction == TRANSITION_DIRECTION_REMOVE_STACK) { removePipImmediately(); @@ -1450,9 +1449,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, null /* callback */, false /* withStartDelay */); }); } else { - applyFinishBoundsResize(wct, direction, isPipTopLeft); + applyFinishBoundsResize(wct, direction, false); } } else { + final boolean isPipTopLeft = + direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft(); applyFinishBoundsResize(wct, direction, isPipTopLeft); } @@ -1521,6 +1522,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return topLeft.contains(mPipBoundsState.getBounds()); } + private boolean isPipToTopLeft() { + if (!mSplitScreenOptional.isPresent()) { + return false; + } + return mSplitScreenOptional.get().getActivateSplitPosition(mTaskInfo) + == SPLIT_POSITION_TOP_OR_LEFT; + } + /** * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined * and can be overridden to restore to an alternate windowing mode. @@ -1652,8 +1661,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final Rect topLeft = new Rect(); final Rect bottomRight = new Rect(); mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight); - final boolean isPipTopLeft = isPipTopLeft(); - destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight); + destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight); return true; } @@ -1737,6 +1745,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceControlTransactionFactory = factory; } + public boolean isLaunchToSplit(TaskInfo taskInfo) { + return mSplitScreenOptional.isPresent() + && mSplitScreenOptional.get().isLaunchToSplit(taskInfo); + } + /** * Dumps internal states. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index d86468a838d9..541dc19c3829 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -570,8 +570,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb if (task.getWindowingMode() != WINDOWING_MODE_PINNED) { return; } - mTouchHandler.getMotionHelper().expandLeavePip( - clearedTask /* skipAnimation */); + if (mPipTaskOrganizer.isLaunchToSplit(task)) { + mTouchHandler.getMotionHelper().expandIntoSplit(); + } else { + mTouchHandler.getMotionHelper().expandLeavePip( + clearedTask /* skipAnimation */); + } } }); 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 36da4cf12706..c7ad4fdcacf0 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 @@ -42,6 +42,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; +import android.app.TaskInfo; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; @@ -421,6 +422,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator.goToFullscreenFromSplit(); } + public boolean isLaunchToSplit(TaskInfo taskInfo) { + return mStageCoordinator.isLaunchToSplit(taskInfo); + } + + public int getActivateSplitPosition(TaskInfo taskInfo) { + return mStageCoordinator.getActivateSplitPosition(taskInfo); + } + public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) { final int[] result = new int[1]; IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { 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 0f18ddaba218..a42820d2e765 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 @@ -74,6 +74,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IActivityTaskManager; import android.app.PendingIntent; +import android.app.TaskInfo; import android.app.WindowConfiguration; import android.content.ActivityNotFoundException; import android.content.Context; @@ -124,6 +125,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; +import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.common.split.SplitWindowManager; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; @@ -208,6 +210,36 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private DefaultMixedHandler mMixedHandler; private final Toast mSplitUnsupportedToast; + private SplitRequest mSplitRequest; + + class SplitRequest { + @SplitPosition + int mActivatePosition; + int mActivateTaskId; + int mActivateTaskId2; + Intent mStartIntent; + Intent mStartIntent2; + + SplitRequest(int taskId, Intent startIntent, int position) { + mActivateTaskId = taskId; + mStartIntent = startIntent; + mActivatePosition = position; + } + SplitRequest(Intent startIntent, int position) { + mStartIntent = startIntent; + mActivatePosition = position; + } + SplitRequest(Intent startIntent, Intent startIntent2, int position) { + mStartIntent = startIntent; + mStartIntent2 = startIntent2; + mActivatePosition = position; + } + SplitRequest(int taskId1, int taskId2, int position) { + mActivateTaskId = taskId1; + mActivateTaskId2 = taskId2; + mActivatePosition = position; + } + } private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks = new SplitWindowManager.ParentContainerCallbacks() { @@ -393,6 +425,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, setSideStagePosition(sideStagePosition, wct); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); targetStage.evictAllChildren(evictWct); + + // Apply surface bounds before animation start. + SurfaceControl.Transaction startT = mTransactionPool.acquire(); + if (startT != null) { + updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */); + startT.apply(); + mTransactionPool.release(startT); + } + // reparent the task to an invisible split root will make the activity invisible. Reorder + // the root task to front to make the entering transition from pip to split smooth. + wct.reorder(mRootTaskInfo.token, true); + wct.setForceTranslucent(mRootTaskInfo.token, true); + wct.reorder(targetStage.mRootTaskInfo.token, true); + wct.setForceTranslucent(targetStage.mRootTaskInfo.token, true); + // prevent the fling divider to center transition + mIsDropEntering = true; + targetStage.addTask(task, wct); if (ENABLE_SHELL_TRANSITIONS) { @@ -547,7 +596,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } - if (isEnteringSplit && !openingToSide) { + if (isEnteringSplit && !openingToSide && apps != null) { mMainExecutor.execute(() -> exitSplitScreen( mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, EXIT_REASON_UNKNOWN)); @@ -587,7 +636,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) { updateWindowBounds(mSplitLayout, wct); } - + mSplitRequest = new SplitRequest(intent.getIntent(), position); wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } @@ -686,6 +735,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, addActivityOptions(options1, mSideStage); wct.startTask(taskId1, options1); + mSplitRequest = new SplitRequest(taskId1, taskId2, splitPosition); startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter, instanceId); } @@ -719,6 +769,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); } else { wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); + mSplitRequest = new SplitRequest(pendingIntent1.getIntent(), + pendingIntent2 != null ? pendingIntent2.getIntent() : null, splitPosition); } startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, shortcutInfo2, options2, splitPosition, splitRatio, adapter, instanceId); @@ -743,6 +795,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, addActivityOptions(options1, mSideStage); wct.sendPendingIntent(pendingIntent, fillInIntent, options1); + mSplitRequest = new SplitRequest(taskId, pendingIntent.getIntent(), splitPosition); startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter, instanceId); } @@ -815,7 +868,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; mIsSplitEntering = true; - + if (mSplitRequest == null) { + mSplitRequest = new SplitRequest(mainTaskId, + mainPendingIntent != null ? mainPendingIntent.getIntent() : null, + sidePosition); + } setSideStagePosition(sidePosition, wct); if (!mMainStage.isActive()) { mMainStage.activate(wct, false /* reparent */); @@ -906,6 +963,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, WindowContainerTransaction evictWct) { mIsSplitEntering = false; mShouldUpdateRecents = true; + mSplitRequest = null; // If any stage has no child after animation finished, it means that split will display // nothing, such status will happen if task and intent is same app but not support // multi-instance, we should exit split and expand that app as full screen. @@ -1739,7 +1797,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.init(); final WindowContainerTransaction wct = new WindowContainerTransaction(); - if (mLogger.isEnterRequestedByDrag()) { + if (mIsDropEntering) { prepareEnterSplitScreen(wct); } else { // TODO (b/238697912) : Add the validation to prevent entering non-recovered status @@ -1764,6 +1822,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; + mSplitRequest = null; updateRecentTasksSplitPair(); if (!mLogger.hasStartedSession()) { @@ -2316,6 +2375,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.flingDividerToDismiss(!leftOrTop, EXIT_REASON_FULLSCREEN_SHORTCUT); } + boolean isLaunchToSplit(TaskInfo taskInfo) { + return getActivateSplitPosition(taskInfo) != SPLIT_POSITION_UNDEFINED; + } + + int getActivateSplitPosition(TaskInfo taskInfo) { + if (mSplitRequest == null || taskInfo == null) { + return SPLIT_POSITION_UNDEFINED; + } + if (mSplitRequest.mActivateTaskId != 0 + && mSplitRequest.mActivateTaskId2 == taskInfo.taskId) { + return mSplitRequest.mActivatePosition; + } + if (mSplitRequest.mActivateTaskId == taskInfo.taskId) { + return mSplitRequest.mActivatePosition; + } + final String packageName1 = SplitScreenUtils.getPackageName(mSplitRequest.mStartIntent); + final String basePackageName = SplitScreenUtils.getPackageName(taskInfo.baseIntent); + if (packageName1 != null && packageName1.equals(basePackageName)) { + return mSplitRequest.mActivatePosition; + } + final String packageName2 = SplitScreenUtils.getPackageName(mSplitRequest.mStartIntent2); + if (packageName2 != null && packageName2.equals(basePackageName)) { + return mSplitRequest.mActivatePosition; + } + return SPLIT_POSITION_UNDEFINED; + } + /** Synchronize split-screen state with transition and make appropriate preparations. */ public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, |