Support launching intent and task in split screen

Bug: 216829535
Test: see the other cl in the same topic
Change-Id: Id0f58a788585e2dabeae476b8a2bd80ba85bb9fe
This commit is contained in:
Tracy Zhou
2022-01-31 12:14:48 -08:00
parent 849d24421c
commit 275a1a4b80
3 changed files with 138 additions and 4 deletions

View File

@@ -89,9 +89,17 @@ interface ISplitScreen {
/**
* Version of startTasks using legacy transition system.
*/
oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
int sideTaskId, in Bundle sideOptions, int sidePosition,
float splitRatio, in RemoteAnimationAdapter adapter) = 11;
oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
int sideTaskId, in Bundle sideOptions, int sidePosition,
float splitRatio, in RemoteAnimationAdapter adapter) = 11;
/**
* Start a pair of intent and task using legacy transition system.
*/
oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
in Intent fillInIntent, int taskId, boolean intentFirst, in Bundle mainOptions,
in Bundle sideOptions, int sidePosition, float splitRatio,
in RemoteAnimationAdapter adapter) = 12;
/**
* Blocking call that notifies and gets additional split-screen targets when entering
@@ -100,5 +108,7 @@ interface ISplitScreen {
* @param appTargets apps that will be re-parented to display area
*/
RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
in RemoteAnimationTarget[] appTargets) = 12;
in RemoteAnimationTarget[] appTargets) = 13;
}

View File

@@ -640,6 +640,18 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
splitRatio, adapter));
}
@Override
public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
Bundle sideOptions, int sidePosition, float splitRatio,
RemoteAnimationAdapter adapter) {
executeRemoteCallWithTaskPermission(mController,
"startIntentAndTaskWithLegacyTransition", (controller) ->
controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
pendingIntent, fillInIntent, taskId, intentFirst, mainOptions,
sideOptions, sidePosition, splitRatio, adapter));
}
@Override
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,

View File

@@ -57,8 +57,10 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
@@ -467,6 +469,116 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTaskOrganizer.applyTransaction(wct);
}
/** Start an intent and a task ordered by {@code intentFirst}. */
void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
int taskId, boolean intentFirst, @Nullable Bundle mainOptions,
@Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
RemoteAnimationAdapter adapter) {
// TODO: try pulling the first chunk of this method into a method so that it can be shared
// with startTasksWithLegacyTransition. So far attempts to do so result in failure in split.
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
final WindowContainerTransaction wct = new WindowContainerTransaction();
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
// Need to add another wrapper here in shell so that we can inject the divider bar
// and also manage the process elevation via setRunningRemote
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@Override
public void onAnimationStart(@WindowManager.TransitionOldType int transit,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
RemoteAnimationTarget[] augmentedNonApps =
new RemoteAnimationTarget[nonApps.length + 1];
for (int i = 0; i < nonApps.length; ++i) {
augmentedNonApps[i] = nonApps[i];
}
augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
IRemoteAnimationFinishedCallback wrapCallback =
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
finishedCallback.onAnimationFinished();
}
};
try {
try {
ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
adapter.getCallingApplication());
} catch (SecurityException e) {
Slog.e(TAG, "Unable to boost animation thread. This should only happen"
+ " during unit tests");
}
adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
augmentedNonApps, wrapCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Error starting remote animation", e);
}
}
@Override
public void onAnimationCancelled() {
mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
try {
adapter.getRunner().onAnimationCancelled();
} catch (RemoteException e) {
Slog.e(TAG, "Error starting remote animation", e);
}
}
};
RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
if (mainOptions == null) {
mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
} else {
ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
mainOptions = mainActivityOptions.toBundle();
}
sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
if (mMainStage.isActive()) {
mMainStage.moveToTop(getMainStageBounds(), wct);
} else {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
}
mSideStage.moveToTop(getSideStageBounds(), wct);
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
addActivityOptions(sideOptions, mSideStage);
// Add task launch requests
if (intentFirst) {
wct.sendPendingIntent(pendingIntent, fillInIntent, mainOptions);
wct.startTask(taskId, sideOptions);
} else {
wct.startTask(taskId, mainOptions);
wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
}
// Using legacy transitions, so we can't use blast sync since it conflicts.
mTaskOrganizer.applyTransaction(wct);
}
/**
* Collects all the current child tasks of a specific split and prepares transaction to evict
* them to display.