Merge "Intercept activity start requests in client organizer" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
94a6a10f90
@@ -214,6 +214,14 @@ public class ActivityOptions {
|
|||||||
public static final String KEY_LAUNCH_ROOT_TASK_TOKEN =
|
public static final String KEY_LAUNCH_ROOT_TASK_TOKEN =
|
||||||
"android.activity.launchRootTaskToken";
|
"android.activity.launchRootTaskToken";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link com.android.server.wm.TaskFragment} token the activity should be launched into.
|
||||||
|
* @see #setLaunchTaskFragmentToken(IBinder)
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final String KEY_LAUNCH_TASK_FRAGMENT_TOKEN =
|
||||||
|
"android.activity.launchTaskFragmentToken";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The windowing mode the activity should be launched into.
|
* The windowing mode the activity should be launched into.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -396,6 +404,7 @@ public class ActivityOptions {
|
|||||||
private int mCallerDisplayId = INVALID_DISPLAY;
|
private int mCallerDisplayId = INVALID_DISPLAY;
|
||||||
private WindowContainerToken mLaunchTaskDisplayArea;
|
private WindowContainerToken mLaunchTaskDisplayArea;
|
||||||
private WindowContainerToken mLaunchRootTask;
|
private WindowContainerToken mLaunchRootTask;
|
||||||
|
private IBinder mLaunchTaskFragmentToken;
|
||||||
@WindowConfiguration.WindowingMode
|
@WindowConfiguration.WindowingMode
|
||||||
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
|
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
|
||||||
@WindowConfiguration.ActivityType
|
@WindowConfiguration.ActivityType
|
||||||
@@ -1138,6 +1147,7 @@ public class ActivityOptions {
|
|||||||
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
|
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
|
||||||
mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
|
mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
|
||||||
mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
|
mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
|
||||||
|
mLaunchTaskFragmentToken = opts.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
|
||||||
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
|
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
|
||||||
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
|
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
|
||||||
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
|
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
|
||||||
@@ -1472,6 +1482,17 @@ public class ActivityOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public IBinder getLaunchTaskFragmentToken() {
|
||||||
|
return mLaunchTaskFragmentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public ActivityOptions setLaunchTaskFragmentToken(IBinder taskFragmentToken) {
|
||||||
|
mLaunchTaskFragmentToken = taskFragmentToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public int getLaunchWindowingMode() {
|
public int getLaunchWindowingMode() {
|
||||||
return mLaunchWindowingMode;
|
return mLaunchWindowingMode;
|
||||||
@@ -1882,6 +1903,9 @@ public class ActivityOptions {
|
|||||||
if (mLaunchRootTask != null) {
|
if (mLaunchRootTask != null) {
|
||||||
b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
|
b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
|
||||||
}
|
}
|
||||||
|
if (mLaunchTaskFragmentToken != null) {
|
||||||
|
b.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, mLaunchTaskFragmentToken);
|
||||||
|
}
|
||||||
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
|
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
|
||||||
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
|
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -742,6 +742,17 @@ public class Instrumentation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This overload is used for notifying the {@link android.window.TaskFragmentOrganizer}
|
||||||
|
* implementation internally about started activities.
|
||||||
|
*
|
||||||
|
* @see #onStartActivity(Intent)
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public ActivityResult onStartActivity(Context who, Intent intent, Bundle options) {
|
||||||
|
return onStartActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for intercepting any started activity.
|
* Used for intercepting any started activity.
|
||||||
*
|
*
|
||||||
@@ -1722,7 +1733,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intent);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intent, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
@@ -1790,7 +1804,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intents[0]);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intents[0], options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
@@ -1861,7 +1878,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intent);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intent, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
@@ -1928,7 +1948,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intent);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intent, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
@@ -1974,7 +1997,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intent);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intent, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
@@ -2021,7 +2047,10 @@ public class Instrumentation {
|
|||||||
final ActivityMonitor am = mActivityMonitors.get(i);
|
final ActivityMonitor am = mActivityMonitors.get(i);
|
||||||
ActivityResult result = null;
|
ActivityResult result = null;
|
||||||
if (am.ignoreMatchingSpecificIntents()) {
|
if (am.ignoreMatchingSpecificIntents()) {
|
||||||
result = am.onStartActivity(intent);
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic().toBundle();
|
||||||
|
}
|
||||||
|
result = am.onStartActivity(who, intent, options);
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
am.mHits++;
|
am.mHits++;
|
||||||
|
|||||||
@@ -155,6 +155,17 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
applyTransaction(wct);
|
applyTransaction(wct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ownerToken The token of the activity that creates this task fragment. It does not
|
||||||
|
* have to be a child of this task fragment, but must belong to the same task.
|
||||||
|
*/
|
||||||
|
void createTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
|
||||||
|
IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
|
||||||
|
final TaskFragmentCreationParams fragmentOptions =
|
||||||
|
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
|
||||||
|
wct.createTaskFragment(fragmentOptions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ownerToken The token of the activity that creates this task fragment. It does not
|
* @param ownerToken The token of the activity that creates this task fragment. It does not
|
||||||
* have to be a child of this task fragment, but must belong to the same task.
|
* have to be a child of this task fragment, but must belong to the same task.
|
||||||
@@ -162,10 +173,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
private void createTaskFragmentAndReparentActivity(
|
private void createTaskFragmentAndReparentActivity(
|
||||||
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
|
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
|
||||||
@NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
|
@NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
|
||||||
final TaskFragmentCreationParams fragmentOptions =
|
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
|
||||||
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
|
wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
|
||||||
wct.createTaskFragment(fragmentOptions)
|
|
||||||
.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,11 +185,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
|
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
|
||||||
@NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
|
@NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
|
||||||
@Nullable Bundle activityOptions) {
|
@Nullable Bundle activityOptions) {
|
||||||
final TaskFragmentCreationParams fragmentOptions =
|
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
|
||||||
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
|
wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
|
||||||
wct.createTaskFragment(fragmentOptions)
|
|
||||||
.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
|
|
||||||
activityOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
|
TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ import android.annotation.NonNull;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityClient;
|
import android.app.ActivityClient;
|
||||||
|
import android.app.ActivityOptions;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.app.Application.ActivityLifecycleCallbacks;
|
import android.app.Application.ActivityLifecycleCallbacks;
|
||||||
|
import android.app.Instrumentation;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -61,9 +64,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
|
|
||||||
public SplitController() {
|
public SplitController() {
|
||||||
mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
|
mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
|
||||||
|
ActivityThread activityThread = ActivityThread.currentActivityThread();
|
||||||
// Register a callback to be notified about activities being created.
|
// Register a callback to be notified about activities being created.
|
||||||
ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
|
activityThread.getApplication().registerActivityLifecycleCallbacks(
|
||||||
new LifecycleCallbacks());
|
new LifecycleCallbacks());
|
||||||
|
// Intercept activity starts to route activities to new containers if necessary.
|
||||||
|
Instrumentation instrumentation = activityThread.getInstrumentation();
|
||||||
|
instrumentation.addMonitor(new ActivityStartMonitor());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
|
public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
|
||||||
@@ -118,7 +125,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.setInfo(taskFragmentInfo);
|
container.setInfo(taskFragmentInfo);
|
||||||
if (taskFragmentInfo.isEmpty()) {
|
// Check if there are no running activities - consider the container empty if there are no
|
||||||
|
// non-finishing activities left.
|
||||||
|
if (!taskFragmentInfo.hasRunningActivity()) {
|
||||||
cleanupContainer(container, true /* shouldFinishDependent */);
|
cleanupContainer(container, true /* shouldFinishDependent */);
|
||||||
updateCallbackIfNecessary();
|
updateCallbackIfNecessary();
|
||||||
}
|
}
|
||||||
@@ -664,4 +673,40 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
handler.post(r);
|
handler.post(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A monitor that intercepts all activity start requests originating in the client process and
|
||||||
|
* can amend them to target a specific task fragment to form a split.
|
||||||
|
*/
|
||||||
|
private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instrumentation.ActivityResult onStartActivity(Context who, Intent intent,
|
||||||
|
Bundle options) {
|
||||||
|
// TODO(b/190433398): Check if the activity is configured to always be expanded.
|
||||||
|
|
||||||
|
// Check if activity should be put in a split with the activity that launched it.
|
||||||
|
if (!(who instanceof Activity)) {
|
||||||
|
return super.onStartActivity(who, intent, options);
|
||||||
|
}
|
||||||
|
final Activity launchingActivity = (Activity) who;
|
||||||
|
|
||||||
|
final ExtensionSplitPairRule splitPairRule = getSplitRule(
|
||||||
|
launchingActivity.getComponentName(), intent.getComponent(), getSplitRules());
|
||||||
|
if (splitPairRule == null) {
|
||||||
|
return super.onStartActivity(who, intent, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new split with an empty side container
|
||||||
|
final TaskFragmentContainer secondaryContainer = mPresenter
|
||||||
|
.createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
|
||||||
|
|
||||||
|
// Amend the request to let the WM know that the activity should be placed in the
|
||||||
|
// dedicated container.
|
||||||
|
options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
|
||||||
|
secondaryContainer.getTaskFragmentToken());
|
||||||
|
|
||||||
|
return super.onStartActivity(who, intent, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,37 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
applyTransaction(wct);
|
applyTransaction(wct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new split with the primary activity and an empty secondary container.
|
||||||
|
* @return The newly created secondary container.
|
||||||
|
*/
|
||||||
|
TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
|
||||||
|
@NonNull ExtensionSplitPairRule rule) {
|
||||||
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
|
||||||
|
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
||||||
|
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
||||||
|
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
|
||||||
|
primaryActivity, primaryRectBounds, null);
|
||||||
|
|
||||||
|
// Create new empty task fragment
|
||||||
|
TaskFragmentContainer secondaryContainer = mController.newContainer(null);
|
||||||
|
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
||||||
|
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
|
||||||
|
primaryActivity.getActivityToken(), secondaryRectBounds,
|
||||||
|
WINDOWING_MODE_MULTI_WINDOW);
|
||||||
|
secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
|
||||||
|
|
||||||
|
// Set adjacent to each other so that the containers below will be invisible.
|
||||||
|
wct.setAdjacentTaskFragments(
|
||||||
|
primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
|
||||||
|
applyTransaction(wct);
|
||||||
|
|
||||||
|
mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
|
||||||
|
|
||||||
|
return secondaryContainer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new split container with the two provided activities.
|
* Creates a new split container with the two provided activities.
|
||||||
* @param primaryActivity An activity that should be in the primary container. If it is not
|
* @param primaryActivity An activity that should be in the primary container. If it is not
|
||||||
@@ -99,48 +130,12 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
|
|
||||||
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
||||||
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
||||||
TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
|
final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
|
||||||
primaryActivity.getActivityToken());
|
primaryActivity, primaryRectBounds, null);
|
||||||
if (primaryContainer == null) {
|
|
||||||
primaryContainer = mController.newContainer(primaryActivity);
|
|
||||||
|
|
||||||
final TaskFragmentCreationParams fragmentOptions =
|
|
||||||
createFragmentOptions(
|
|
||||||
primaryContainer.getTaskFragmentToken(),
|
|
||||||
primaryActivity.getActivityToken(),
|
|
||||||
primaryRectBounds,
|
|
||||||
WINDOWING_MODE_MULTI_WINDOW);
|
|
||||||
wct.createTaskFragment(fragmentOptions);
|
|
||||||
|
|
||||||
wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
|
|
||||||
primaryActivity.getActivityToken());
|
|
||||||
|
|
||||||
primaryContainer.setLastRequestedBounds(primaryRectBounds);
|
|
||||||
} else {
|
|
||||||
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
||||||
TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
|
final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
|
||||||
secondaryActivity.getActivityToken());
|
secondaryActivity, secondaryRectBounds, primaryContainer);
|
||||||
if (secondaryContainer == null || secondaryContainer == primaryContainer) {
|
|
||||||
secondaryContainer = mController.newContainer(secondaryActivity);
|
|
||||||
|
|
||||||
final TaskFragmentCreationParams fragmentOptions =
|
|
||||||
createFragmentOptions(
|
|
||||||
secondaryContainer.getTaskFragmentToken(),
|
|
||||||
secondaryActivity.getActivityToken(),
|
|
||||||
secondaryRectBounds,
|
|
||||||
WINDOWING_MODE_MULTI_WINDOW);
|
|
||||||
wct.createTaskFragment(fragmentOptions);
|
|
||||||
|
|
||||||
wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
|
|
||||||
secondaryActivity.getActivityToken());
|
|
||||||
|
|
||||||
secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
|
|
||||||
} else {
|
|
||||||
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set adjacent to each other so that the containers below will be invisible.
|
// Set adjacent to each other so that the containers below will be invisible.
|
||||||
wct.setAdjacentTaskFragments(
|
wct.setAdjacentTaskFragments(
|
||||||
@@ -150,6 +145,38 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
|
mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new container or resizes an existing container for activity to the provided bounds.
|
||||||
|
* @param activity The activity to be re-parented to the container if necessary.
|
||||||
|
* @param containerToAvoid Re-parent from this container if an activity is already in it.
|
||||||
|
*/
|
||||||
|
private TaskFragmentContainer prepareContainerForActivity(
|
||||||
|
@NonNull WindowContainerTransaction wct, @NonNull Activity activity,
|
||||||
|
@NonNull Rect bounds, @Nullable TaskFragmentContainer containerToAvoid) {
|
||||||
|
TaskFragmentContainer container = mController.getContainerWithActivity(
|
||||||
|
activity.getActivityToken());
|
||||||
|
if (container == null || container == containerToAvoid) {
|
||||||
|
container = mController.newContainer(activity);
|
||||||
|
|
||||||
|
final TaskFragmentCreationParams fragmentOptions =
|
||||||
|
createFragmentOptions(
|
||||||
|
container.getTaskFragmentToken(),
|
||||||
|
activity.getActivityToken(),
|
||||||
|
bounds,
|
||||||
|
WINDOWING_MODE_MULTI_WINDOW);
|
||||||
|
wct.createTaskFragment(fragmentOptions);
|
||||||
|
|
||||||
|
wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
|
||||||
|
activity.getActivityToken());
|
||||||
|
|
||||||
|
container.setLastRequestedBounds(bounds);
|
||||||
|
} else {
|
||||||
|
resizeTaskFragmentIfRegistered(wct, container, bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a new activity to the side, creating a new split container. A new container will be
|
* Starts a new activity to the side, creating a new split container. A new container will be
|
||||||
* created for the activity that will be started.
|
* created for the activity that will be started.
|
||||||
|
|||||||
@@ -2384,6 +2384,11 @@ class ActivityStarter {
|
|||||||
}
|
}
|
||||||
mTransientLaunch = mOptions.getTransientLaunch();
|
mTransientLaunch = mOptions.getTransientLaunch();
|
||||||
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
|
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
|
||||||
|
|
||||||
|
if (inTaskFragment == null) {
|
||||||
|
inTaskFragment = TaskFragment.fromTaskFragmentToken(
|
||||||
|
mOptions.getLaunchTaskFragmentToken(), mService);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
|
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
|
||||||
|
|||||||
@@ -293,6 +293,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
mRemoteToken = new RemoteToken(this);
|
mRemoteToken = new RemoteToken(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
static TaskFragment fromTaskFragmentToken(@Nullable IBinder token,
|
||||||
|
@NonNull ActivityTaskManagerService service) {
|
||||||
|
if (token == null) return null;
|
||||||
|
return service.mWindowOrganizerController.getTaskFragment(token);
|
||||||
|
}
|
||||||
|
|
||||||
void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
|
void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
|
||||||
if (mAdjacentTaskFragment == taskFragment) {
|
if (mAdjacentTaskFragment == taskFragment) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1174,6 +1174,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
taskFragment.removeImmediately();
|
taskFragment.removeImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
TaskFragment getTaskFragment(IBinder tfToken) {
|
||||||
|
return mLaunchTaskFragments.get(tfToken);
|
||||||
|
}
|
||||||
|
|
||||||
static class CallerInfo {
|
static class CallerInfo {
|
||||||
final int mPid;
|
final int mPid;
|
||||||
final int mUid;
|
final int mUid;
|
||||||
|
|||||||
Reference in New Issue
Block a user