Merge "Make PIP into split screen" into tm-qpr-dev am: 5c978d3fb3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20766589

Change-Id: I7bf4d8adbe69e5bbd72289d2fc8420f6717fcd0b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jeff Chang
2023-02-13 06:04:46 +00:00
committed by Automerger Merge Worker
5 changed files with 122 additions and 11 deletions

View File

@@ -216,7 +216,6 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler.
args.argi1 = homeTaskVisible ? 1 : 0; args.argi1 = homeTaskVisible ? 1 : 0;
args.argi2 = clearedTask ? 1 : 0; args.argi2 = clearedTask ? 1 : 0;
args.argi3 = wasVisible ? 1 : 0; args.argi3 = wasVisible ? 1 : 0;
mMainHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
mMainHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget(); mMainHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
} }

View File

@@ -1409,7 +1409,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@PipAnimationController.TransitionDirection int direction, @PipAnimationController.TransitionDirection int direction,
@PipAnimationController.AnimationType int type) { @PipAnimationController.AnimationType int type) {
final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds()); final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
final boolean isPipTopLeft = isPipTopLeft();
mPipBoundsState.setBounds(destinationBounds); mPipBoundsState.setBounds(destinationBounds);
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) { if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately(); removePipImmediately();
@@ -1455,9 +1454,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
null /* callback */, false /* withStartDelay */); null /* callback */, false /* withStartDelay */);
}); });
} else { } else {
applyFinishBoundsResize(wct, direction, isPipTopLeft); applyFinishBoundsResize(wct, direction, false);
} }
} else { } else {
final boolean isPipTopLeft =
direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft();
applyFinishBoundsResize(wct, direction, isPipTopLeft); applyFinishBoundsResize(wct, direction, isPipTopLeft);
} }
@@ -1526,6 +1527,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return topLeft.contains(mPipBoundsState.getBounds()); 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 * 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. * and can be overridden to restore to an alternate windowing mode.
@@ -1662,8 +1671,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final Rect topLeft = new Rect(); final Rect topLeft = new Rect();
final Rect bottomRight = new Rect(); final Rect bottomRight = new Rect();
mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight); mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
final boolean isPipTopLeft = isPipTopLeft(); destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
return true; return true;
} }
@@ -1747,6 +1755,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceControlTransactionFactory = factory; mSurfaceControlTransactionFactory = factory;
} }
public boolean isLaunchToSplit(TaskInfo taskInfo) {
return mSplitScreenOptional.isPresent()
&& mSplitScreenOptional.get().isLaunchToSplit(taskInfo);
}
/** /**
* Dumps internal states. * Dumps internal states.
*/ */

View File

@@ -570,9 +570,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb
if (task.getWindowingMode() != WINDOWING_MODE_PINNED) { if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
return; return;
} }
if (mPipTaskOrganizer.isLaunchToSplit(task)) {
mTouchHandler.getMotionHelper().expandIntoSplit();
} else {
mTouchHandler.getMotionHelper().expandLeavePip( mTouchHandler.getMotionHelper().expandLeavePip(
clearedTask /* skipAnimation */); clearedTask /* skipAnimation */);
} }
}
}); });
mPipParamsChangedForwarder.addListener( mPipParamsChangedForwarder.addListener(

View File

@@ -42,6 +42,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.app.ActivityTaskManager; import android.app.ActivityTaskManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.TaskInfo;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
@@ -421,6 +422,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.goToFullscreenFromSplit(); 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) { public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) {
final int[] result = new int[1]; final int[] result = new int[1];
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {

View File

@@ -74,6 +74,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.app.IActivityTaskManager; import android.app.IActivityTaskManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.TaskInfo;
import android.app.WindowConfiguration; import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context; 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.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; 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.common.split.SplitWindowManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.recents.RecentTasksController;
@@ -208,6 +210,36 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private DefaultMixedHandler mMixedHandler; private DefaultMixedHandler mMixedHandler;
private final Toast mSplitUnsupportedToast; 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 = private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
new SplitWindowManager.ParentContainerCallbacks() { new SplitWindowManager.ParentContainerCallbacks() {
@@ -393,6 +425,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSideStagePosition(sideStagePosition, wct); setSideStagePosition(sideStagePosition, wct);
final WindowContainerTransaction evictWct = new WindowContainerTransaction(); final WindowContainerTransaction evictWct = new WindowContainerTransaction();
targetStage.evictAllChildren(evictWct); 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); targetStage.addTask(task, wct);
if (ENABLE_SHELL_TRANSITIONS) { 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( mMainExecutor.execute(() -> exitSplitScreen(
mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
EXIT_REASON_UNKNOWN)); EXIT_REASON_UNKNOWN));
@@ -587,7 +636,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) { if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) {
updateWindowBounds(mSplitLayout, wct); updateWindowBounds(mSplitLayout, wct);
} }
mSplitRequest = new SplitRequest(intent.getIntent(), position);
wct.sendPendingIntent(intent, fillInIntent, options); wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
} }
@@ -686,6 +735,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
addActivityOptions(options1, mSideStage); addActivityOptions(options1, mSideStage);
wct.startTask(taskId1, options1); wct.startTask(taskId1, options1);
mSplitRequest = new SplitRequest(taskId1, taskId2, splitPosition);
startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter, startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter,
instanceId); instanceId);
} }
@@ -719,6 +769,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1);
} else { } else {
wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
mSplitRequest = new SplitRequest(pendingIntent1.getIntent(),
pendingIntent2 != null ? pendingIntent2.getIntent() : null, splitPosition);
} }
startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, shortcutInfo2, options2, startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, shortcutInfo2, options2,
splitPosition, splitRatio, adapter, instanceId); splitPosition, splitRatio, adapter, instanceId);
@@ -743,6 +795,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
addActivityOptions(options1, mSideStage); addActivityOptions(options1, mSideStage);
wct.sendPendingIntent(pendingIntent, fillInIntent, options1); wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
mSplitRequest = new SplitRequest(taskId, pendingIntent.getIntent(), splitPosition);
startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter, startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
instanceId); instanceId);
} }
@@ -815,7 +868,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Set false to avoid record new bounds with old task still on top; // Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false; mShouldUpdateRecents = false;
mIsSplitEntering = true; mIsSplitEntering = true;
if (mSplitRequest == null) {
mSplitRequest = new SplitRequest(mainTaskId,
mainPendingIntent != null ? mainPendingIntent.getIntent() : null,
sidePosition);
}
setSideStagePosition(sidePosition, wct); setSideStagePosition(sidePosition, wct);
if (!mMainStage.isActive()) { if (!mMainStage.isActive()) {
mMainStage.activate(wct, false /* reparent */); mMainStage.activate(wct, false /* reparent */);
@@ -906,6 +963,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
WindowContainerTransaction evictWct) { WindowContainerTransaction evictWct) {
mIsSplitEntering = false; mIsSplitEntering = false;
mShouldUpdateRecents = true; mShouldUpdateRecents = true;
mSplitRequest = null;
// If any stage has no child after animation finished, it means that split will display // 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 // 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. // 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(); mSplitLayout.init();
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mLogger.isEnterRequestedByDrag()) { if (mIsDropEntering) {
prepareEnterSplitScreen(wct); prepareEnterSplitScreen(wct);
} else { } else {
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status // 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) { if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true; mShouldUpdateRecents = true;
mSplitRequest = null;
updateRecentTasksSplitPair(); updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) { if (!mLogger.hasStartedSession()) {
@@ -2316,6 +2375,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.flingDividerToDismiss(!leftOrTop, EXIT_REASON_FULLSCREEN_SHORTCUT); 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. */ /** Synchronize split-screen state with transition and make appropriate preparations. */
public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason, public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,