Loading core/java/android/window/TaskFragmentCreationParams.java +62 −2 Original line number Diff line number Diff line Loading @@ -71,20 +71,42 @@ public final class TaskFragmentCreationParams implements Parcelable { * * This is needed in case we need to launch a placeholder Activity to split below a transparent * always-expand Activity. * * This should not be used with {@link #mPairedActivityToken}. */ @Nullable private final IBinder mPairedPrimaryFragmentToken; /** * The Activity token to place the new TaskFragment on top of. * When it is set, the new TaskFragment will be positioned right above the target Activity. * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. * * This is needed in case we need to place an Activity into TaskFragment to launch placeholder * below a transparent always-expand Activity, or when there is another Intent being started in * a TaskFragment above. * * This should not be used with {@link #mPairedPrimaryFragmentToken}. */ @Nullable private final IBinder mPairedActivityToken; private TaskFragmentCreationParams( @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect initialBounds, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken) { @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @Nullable IBinder pairedActivityToken) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { throw new IllegalArgumentException("pairedPrimaryFragmentToken and" + " pairedActivityToken should not be set at the same time."); } mOrganizer = organizer; mFragmentToken = fragmentToken; mOwnerToken = ownerToken; mInitialBounds.set(initialBounds); mWindowingMode = windowingMode; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedActivityToken = pairedActivityToken; } @NonNull Loading Loading @@ -121,6 +143,15 @@ public final class TaskFragmentCreationParams implements Parcelable { return mPairedPrimaryFragmentToken; } /** * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ @Nullable public IBinder getPairedActivityToken() { return mPairedActivityToken; } private TaskFragmentCreationParams(Parcel in) { mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mFragmentToken = in.readStrongBinder(); Loading @@ -128,6 +159,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mInitialBounds.readFromParcel(in); mWindowingMode = in.readInt(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); } /** @hide */ Loading @@ -139,6 +171,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mInitialBounds.writeToParcel(dest, flags); dest.writeInt(mWindowingMode); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedActivityToken); } @NonNull Loading @@ -164,6 +197,7 @@ public final class TaskFragmentCreationParams implements Parcelable { + " initialBounds=" + mInitialBounds + " windowingMode=" + mWindowingMode + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedActivityToken=" + mPairedActivityToken + "}"; } Loading Loading @@ -194,6 +228,9 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable private IBinder mPairedPrimaryFragmentToken; @Nullable private IBinder mPairedActivityToken; public Builder(@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { mOrganizer = organizer; Loading Loading @@ -224,6 +261,8 @@ public final class TaskFragmentCreationParams implements Parcelable { * This is needed in case we need to launch a placeholder Activity to split below a * transparent always-expand Activity. * * This should not be used with {@link #setPairedActivityToken}. * * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ Loading @@ -233,11 +272,32 @@ public final class TaskFragmentCreationParams implements Parcelable { return this; } /** * Sets the Activity token to place the new TaskFragment on top of. * When it is set, the new TaskFragment will be positioned right above the target Activity. * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. * * This is needed in case we need to place an Activity into TaskFragment to launch * placeholder below a transparent always-expand Activity, or when there is another Intent * being started in a TaskFragment above. * * This should not be used with {@link #setPairedPrimaryFragmentToken}. * * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ @NonNull public Builder setPairedActivityToken(@Nullable IBinder activityToken) { mPairedActivityToken = activityToken; return this; } /** Constructs the options to create TaskFragment with. */ @NonNull public TaskFragmentCreationParams build() { return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken); mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken, mPairedActivityToken); } } } libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +19 −2 Original line number Diff line number Diff line Loading @@ -191,10 +191,25 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { */ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) { createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode, null /* pairedActivityToken */); } /** * @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. * @param pairedActivityToken The token of the activity that will be reparented to this task * fragment. When it is not {@code null}, the task fragment will be * positioned right above it. */ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, @Nullable IBinder pairedActivityToken) { final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder( getOrganizerToken(), fragmentToken, ownerToken) .setInitialBounds(bounds) .setWindowingMode(windowingMode) .setPairedActivityToken(pairedActivityToken) .build(); createTaskFragment(wct, fragmentOptions); } Loading @@ -216,8 +231,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, @NonNull Activity activity) { createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode); wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken()); final IBinder reparentActivityToken = activity.getActivityToken(); createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode, reparentActivityToken); wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +1 −1 Original line number Diff line number Diff line Loading @@ -1499,7 +1499,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * Returns the active split that has the provided containers as primary and secondary or as * secondary and primary, if available. */ @VisibleForTesting @GuardedBy("mLock") @Nullable SplitContainer getActiveSplitForContainers( @NonNull TaskFragmentContainer firstContainer, Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +4 −3 Original line number Diff line number Diff line Loading @@ -268,10 +268,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { container = mController.newContainer(activity, taskId); final int windowingMode = mController.getTaskContainer(taskId) .getWindowingModeForSplitTaskFragment(bounds); createTaskFragment(wct, container.getTaskFragmentToken(), activity.getActivityToken(), bounds, windowingMode); final IBinder reparentActivityToken = activity.getActivityToken(); createTaskFragment(wct, container.getTaskFragmentToken(), reparentActivityToken, bounds, windowingMode, reparentActivityToken); wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(), activity.getActivityToken()); reparentActivityToken); } else { resizeTaskFragmentIfRegistered(wct, container, bounds); final int windowingMode = mController.getTaskContainer(taskId) Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +38 −0 Original line number Diff line number Diff line Loading @@ -141,12 +141,26 @@ class TaskFragmentContainer { mToken = new Binder("TaskFragmentContainer"); mTaskContainer = taskContainer; if (pairedPrimaryContainer != null) { // The TaskFragment will be positioned right above the paired container. if (pairedPrimaryContainer.getTaskContainer() != taskContainer) { throw new IllegalArgumentException( "pairedPrimaryContainer must be in the same Task"); } final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer); taskContainer.mContainers.add(primaryIndex + 1, this); } else if (pendingAppearedActivity != null) { // The TaskFragment will be positioned right above the pending appeared Activity. If any // existing TaskFragment is empty with pending Intent, it is likely that the Activity of // the pending Intent hasn't been created yet, so the new Activity should be below the // empty TaskFragment. int i = taskContainer.mContainers.size() - 1; for (; i >= 0; i--) { final TaskFragmentContainer container = taskContainer.mContainers.get(i); if (!container.isEmpty() || container.getPendingAppearedIntent() == null) { break; } } taskContainer.mContainers.add(i + 1, this); } else { taskContainer.mContainers.add(this); } Loading Loading @@ -500,6 +514,8 @@ class TaskFragmentContainer { } if (!shouldFinishDependent) { // Always finish the placeholder when the primary is finished. finishPlaceholderIfAny(wct, presenter); return; } Loading @@ -526,6 +542,28 @@ class TaskFragmentContainer { mActivitiesToFinishOnExit.clear(); } @GuardedBy("mController.mLock") private void finishPlaceholderIfAny(@NonNull WindowContainerTransaction wct, @NonNull SplitPresenter presenter) { final List<TaskFragmentContainer> containersToRemove = new ArrayList<>(); for (TaskFragmentContainer container : mContainersToFinishOnExit) { if (container.mIsFinished) { continue; } final SplitContainer splitContainer = mController.getActiveSplitForContainers( this, container); if (splitContainer != null && splitContainer.isPlaceholderContainer() && splitContainer.getSecondaryContainer() == container) { // Remove the placeholder secondary TaskFragment. containersToRemove.add(container); } } mContainersToFinishOnExit.removeAll(containersToRemove); for (TaskFragmentContainer container : containersToRemove) { container.finish(false /* shouldFinishDependent */, presenter, wct, mController); } } boolean isFinished() { return mIsFinished; } Loading Loading
core/java/android/window/TaskFragmentCreationParams.java +62 −2 Original line number Diff line number Diff line Loading @@ -71,20 +71,42 @@ public final class TaskFragmentCreationParams implements Parcelable { * * This is needed in case we need to launch a placeholder Activity to split below a transparent * always-expand Activity. * * This should not be used with {@link #mPairedActivityToken}. */ @Nullable private final IBinder mPairedPrimaryFragmentToken; /** * The Activity token to place the new TaskFragment on top of. * When it is set, the new TaskFragment will be positioned right above the target Activity. * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. * * This is needed in case we need to place an Activity into TaskFragment to launch placeholder * below a transparent always-expand Activity, or when there is another Intent being started in * a TaskFragment above. * * This should not be used with {@link #mPairedPrimaryFragmentToken}. */ @Nullable private final IBinder mPairedActivityToken; private TaskFragmentCreationParams( @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect initialBounds, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken) { @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @Nullable IBinder pairedActivityToken) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { throw new IllegalArgumentException("pairedPrimaryFragmentToken and" + " pairedActivityToken should not be set at the same time."); } mOrganizer = organizer; mFragmentToken = fragmentToken; mOwnerToken = ownerToken; mInitialBounds.set(initialBounds); mWindowingMode = windowingMode; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedActivityToken = pairedActivityToken; } @NonNull Loading Loading @@ -121,6 +143,15 @@ public final class TaskFragmentCreationParams implements Parcelable { return mPairedPrimaryFragmentToken; } /** * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ @Nullable public IBinder getPairedActivityToken() { return mPairedActivityToken; } private TaskFragmentCreationParams(Parcel in) { mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mFragmentToken = in.readStrongBinder(); Loading @@ -128,6 +159,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mInitialBounds.readFromParcel(in); mWindowingMode = in.readInt(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); } /** @hide */ Loading @@ -139,6 +171,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mInitialBounds.writeToParcel(dest, flags); dest.writeInt(mWindowingMode); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedActivityToken); } @NonNull Loading @@ -164,6 +197,7 @@ public final class TaskFragmentCreationParams implements Parcelable { + " initialBounds=" + mInitialBounds + " windowingMode=" + mWindowingMode + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedActivityToken=" + mPairedActivityToken + "}"; } Loading Loading @@ -194,6 +228,9 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable private IBinder mPairedPrimaryFragmentToken; @Nullable private IBinder mPairedActivityToken; public Builder(@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { mOrganizer = organizer; Loading Loading @@ -224,6 +261,8 @@ public final class TaskFragmentCreationParams implements Parcelable { * This is needed in case we need to launch a placeholder Activity to split below a * transparent always-expand Activity. * * This should not be used with {@link #setPairedActivityToken}. * * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ Loading @@ -233,11 +272,32 @@ public final class TaskFragmentCreationParams implements Parcelable { return this; } /** * Sets the Activity token to place the new TaskFragment on top of. * When it is set, the new TaskFragment will be positioned right above the target Activity. * Otherwise, the new TaskFragment will be positioned on the top of the Task by default. * * This is needed in case we need to place an Activity into TaskFragment to launch * placeholder below a transparent always-expand Activity, or when there is another Intent * being started in a TaskFragment above. * * This should not be used with {@link #setPairedPrimaryFragmentToken}. * * TODO(b/232476698): remove the hide with adding CTS for this in next release. * @hide */ @NonNull public Builder setPairedActivityToken(@Nullable IBinder activityToken) { mPairedActivityToken = activityToken; return this; } /** Constructs the options to create TaskFragment with. */ @NonNull public TaskFragmentCreationParams build() { return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken); mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken, mPairedActivityToken); } } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +19 −2 Original line number Diff line number Diff line Loading @@ -191,10 +191,25 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { */ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) { createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode, null /* pairedActivityToken */); } /** * @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. * @param pairedActivityToken The token of the activity that will be reparented to this task * fragment. When it is not {@code null}, the task fragment will be * positioned right above it. */ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, @Nullable IBinder pairedActivityToken) { final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder( getOrganizerToken(), fragmentToken, ownerToken) .setInitialBounds(bounds) .setWindowingMode(windowingMode) .setPairedActivityToken(pairedActivityToken) .build(); createTaskFragment(wct, fragmentOptions); } Loading @@ -216,8 +231,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, @NonNull Activity activity) { createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode); wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken()); final IBinder reparentActivityToken = activity.getActivityToken(); createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode, reparentActivityToken); wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +1 −1 Original line number Diff line number Diff line Loading @@ -1499,7 +1499,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * Returns the active split that has the provided containers as primary and secondary or as * secondary and primary, if available. */ @VisibleForTesting @GuardedBy("mLock") @Nullable SplitContainer getActiveSplitForContainers( @NonNull TaskFragmentContainer firstContainer, Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +4 −3 Original line number Diff line number Diff line Loading @@ -268,10 +268,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { container = mController.newContainer(activity, taskId); final int windowingMode = mController.getTaskContainer(taskId) .getWindowingModeForSplitTaskFragment(bounds); createTaskFragment(wct, container.getTaskFragmentToken(), activity.getActivityToken(), bounds, windowingMode); final IBinder reparentActivityToken = activity.getActivityToken(); createTaskFragment(wct, container.getTaskFragmentToken(), reparentActivityToken, bounds, windowingMode, reparentActivityToken); wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(), activity.getActivityToken()); reparentActivityToken); } else { resizeTaskFragmentIfRegistered(wct, container, bounds); final int windowingMode = mController.getTaskContainer(taskId) Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +38 −0 Original line number Diff line number Diff line Loading @@ -141,12 +141,26 @@ class TaskFragmentContainer { mToken = new Binder("TaskFragmentContainer"); mTaskContainer = taskContainer; if (pairedPrimaryContainer != null) { // The TaskFragment will be positioned right above the paired container. if (pairedPrimaryContainer.getTaskContainer() != taskContainer) { throw new IllegalArgumentException( "pairedPrimaryContainer must be in the same Task"); } final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer); taskContainer.mContainers.add(primaryIndex + 1, this); } else if (pendingAppearedActivity != null) { // The TaskFragment will be positioned right above the pending appeared Activity. If any // existing TaskFragment is empty with pending Intent, it is likely that the Activity of // the pending Intent hasn't been created yet, so the new Activity should be below the // empty TaskFragment. int i = taskContainer.mContainers.size() - 1; for (; i >= 0; i--) { final TaskFragmentContainer container = taskContainer.mContainers.get(i); if (!container.isEmpty() || container.getPendingAppearedIntent() == null) { break; } } taskContainer.mContainers.add(i + 1, this); } else { taskContainer.mContainers.add(this); } Loading Loading @@ -500,6 +514,8 @@ class TaskFragmentContainer { } if (!shouldFinishDependent) { // Always finish the placeholder when the primary is finished. finishPlaceholderIfAny(wct, presenter); return; } Loading @@ -526,6 +542,28 @@ class TaskFragmentContainer { mActivitiesToFinishOnExit.clear(); } @GuardedBy("mController.mLock") private void finishPlaceholderIfAny(@NonNull WindowContainerTransaction wct, @NonNull SplitPresenter presenter) { final List<TaskFragmentContainer> containersToRemove = new ArrayList<>(); for (TaskFragmentContainer container : mContainersToFinishOnExit) { if (container.mIsFinished) { continue; } final SplitContainer splitContainer = mController.getActiveSplitForContainers( this, container); if (splitContainer != null && splitContainer.isPlaceholderContainer() && splitContainer.getSecondaryContainer() == container) { // Remove the placeholder secondary TaskFragment. containersToRemove.add(container); } } mContainersToFinishOnExit.removeAll(containersToRemove); for (TaskFragmentContainer container : containersToRemove) { container.finish(false /* shouldFinishDependent */, presenter, wct, mController); } } boolean isFinished() { return mIsFinished; } Loading