Loading core/java/android/window/WindowContainerTransaction.java +11 −3 Original line number Diff line number Diff line Loading @@ -1323,8 +1323,11 @@ public final class WindowContainerTransaction implements Parcelable { /** * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment * {@code companionFragmentToken}. * This indicates that the organizer will remove the TaskFragment when the companion * TaskFragment is removed. * * If {@code toBeFinishedActivity} is {@code null}, this indicates that the organizer will * remove the TaskFragment when the companion TaskFragment is removed; otherwise, the organizer * will finish the {@code toBeFinishedActivity} when the companion TaskFragment is removed * unless it is the last activity in the TaskFragment. * * @param fragmentToken client assigned unique token to create TaskFragment with specified * in {@link TaskFragmentCreationParams#getFragmentToken()}. Loading @@ -1333,14 +1336,19 @@ public final class WindowContainerTransaction implements Parcelable { * {@link TaskFragmentCreationParams#getFragmentToken()}. * If it is {@code null}, the transaction will reset the companion * TaskFragment. * @param toBeFinishedActivity Activity token. If non-{@code null}, it indicates that the * organizer will only remove this activity when the companion * TaskFragment is removed. The request TaskFragment will only be * removed when this activity is the last running activity in it. * @hide */ @NonNull public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken, @Nullable IBinder companionFragmentToken) { @Nullable IBinder companionFragmentToken, @Nullable IBinder toBeFinishedActivity) { final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( OP_TYPE_SET_COMPANION_TASK_FRAGMENT) .setSecondaryFragmentToken(companionFragmentToken) .setActivityToken(toBeFinishedActivity) .build(); return addTaskFragmentOperation(fragmentToken, operation); } Loading core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,17 @@ flag { } } flag { namespace: "windowing_sdk" name: "task_fragment_companion_activity" description: "Track the activity to be finished with tf in core" bug: "433459536" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { namespace: "windowing_sdk" name: "support_gemini_on_multi_display" Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +23 −8 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; import java.util.Map; import java.util.concurrent.Executor; Loading Loading @@ -125,13 +124,15 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { * @param activityOptions ActivityOptions to start the secondary Activity with. * @param windowingMode the windowing mode to set for the TaskFragments. * @param splitAttributes the {@link SplitAttributes} to represent the split. * @param activityToBeFinishedWithSecondary the activity to be finished with the secondary. */ void startActivityToSide(@NonNull WindowContainerTransaction wct, @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingRelBounds, @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken, @NonNull Rect secondaryRelBounds, @NonNull Intent activityIntent, @Nullable Bundle activityOptions, @NonNull SplitRule rule, @WindowingMode int windowingMode, @NonNull SplitAttributes splitAttributes) { @WindowingMode int windowingMode, @NonNull SplitAttributes splitAttributes, @Nullable IBinder activityToBeFinishedWithSecondary) { final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. Loading Loading @@ -163,7 +164,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { // Set adjacent to each other so that the containers below will be invisible. setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule); setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, false /* isStacked */); false /* isStacked */, // No activity to be finished with primary because secondary is still empty. null /* activityToBeFinishedWithPrimary */, activityToBeFinishedWithSecondary); } /** Loading Loading @@ -279,7 +283,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, boolean isStacked) { boolean isStacked, @Nullable IBinder activityToBeFinishedWithPrimary, @Nullable IBinder activityToBeFinishedWithSecondary) { final boolean finishPrimaryWithSecondary; if (isStacked) { finishPrimaryWithSecondary = shouldFinishAssociatedContainerWhenStacked( Loading @@ -287,7 +292,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); } setCompanionTaskFragment(wct, primary, finishPrimaryWithSecondary ? secondary : null); if (finishPrimaryWithSecondary) { setCompanionTaskFragment(wct, primary, secondary, activityToBeFinishedWithSecondary); } else { setCompanionTaskFragment(wct, primary, null /* secondary */, null /* toBeFinishedActivity*/); } final boolean finishSecondaryWithPrimary; if (isStacked) { Loading @@ -296,12 +306,17 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); } setCompanionTaskFragment(wct, secondary, finishSecondaryWithPrimary ? primary : null); if (finishSecondaryWithPrimary) { setCompanionTaskFragment(wct, secondary, primary, activityToBeFinishedWithPrimary); } else { setCompanionTaskFragment(wct, secondary, null /* secondary */, null /* toBeFinishedActivity*/); } } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { wct.setCompanionTaskFragment(primary, secondary); @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) { wct.setCompanionTaskFragment(primary, secondary, toBeFinishedActivity); } void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +2 −1 Original line number Diff line number Diff line Loading @@ -838,7 +838,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.clearLastAdjacentTaskFragment(); container.setLastCompanionTaskFragment(null /* fragmentToken */); container.setLastCompanionTaskFragment(null /* fragmentToken */, null /* toBeFinishedActivity */); container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT); cleanupForEnterPip(wct, container); } else if (wasInPip) { Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +19 −16 Original line number Diff line number Diff line Loading @@ -367,7 +367,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { rule, splitAttributes); startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRelBounds, launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRelBounds, activityIntent, activityOptions, rule, windowingMode, splitAttributes); activityIntent, activityOptions, rule, windowingMode, splitAttributes, secondaryContainer.getActivityToFinishOnExit(primaryContainer)); if (isPlaceholder) { // When placeholder is launched in split, we should keep the focus on the primary. wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); Loading Loading @@ -432,7 +433,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryContainer.getTaskFragmentToken(), splitRule); } setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitRule, isStacked); secondaryContainer.getTaskFragmentToken(), splitRule, isStacked, primaryContainer.getActivityToFinishOnExit(secondaryContainer), secondaryContainer.getActivityToFinishOnExit(primaryContainer)); // Sets the dim area when the two TaskFragments are adjacent. final boolean dimOnTask = !isStacked Loading Loading @@ -640,20 +643,20 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @Override void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) { final TaskFragmentContainer container = mController.getContainer(primary); if (container == null) { throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is" + " not registered with controller."); } if (container.isLastCompanionTaskFragmentEqual(secondary)) { if (container.isLastCompanionTaskFragmentEqual(secondary, toBeFinishedActivity)) { // Return early if the same companion TaskFragment was already requested return; } container.setLastCompanionTaskFragment(secondary); super.setCompanionTaskFragment(wct, primary, secondary); container.setLastCompanionTaskFragment(secondary, toBeFinishedActivity); super.setCompanionTaskFragment(wct, primary, secondary, toBeFinishedActivity); } /** Loading Loading @@ -859,19 +862,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { if (!shouldShowSplit(splitAttributes)) { // If the client side hasn't received TaskFragmentInfo yet, we can't change TaskFragment // bounds. Return failure to create a new SplitContainer which fills task bounds. if (splitContainer.getPrimaryContainer().getInfo() == null || splitContainer.getSecondaryContainer().getInfo() == null) { final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer(); final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer(); if (primaryContainer.getInfo() == null || secondaryContainer.getInfo() == null) { return RESULT_EXPAND_FAILED_NO_TF_INFO; } final IBinder primaryToken = splitContainer.getPrimaryContainer().getTaskFragmentToken(); final IBinder secondaryToken = splitContainer.getSecondaryContainer().getTaskFragmentToken(); expandTaskFragment(wct, splitContainer.getPrimaryContainer()); expandTaskFragment(wct, splitContainer.getSecondaryContainer()); expandTaskFragment(wct, primaryContainer); expandTaskFragment(wct, secondaryContainer); // Set the companion TaskFragment when the two containers stacked. setCompanionTaskFragment(wct, primaryToken, secondaryToken, splitContainer.getSplitRule(), true /* isStacked */); setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitContainer.getSplitRule(), true /* isStacked */, primaryContainer.getActivityToFinishOnExit(secondaryContainer), secondaryContainer.getActivityToFinishOnExit(primaryContainer)); return RESULT_EXPANDED; } return RESULT_NOT_EXPANDED; Loading Loading
core/java/android/window/WindowContainerTransaction.java +11 −3 Original line number Diff line number Diff line Loading @@ -1323,8 +1323,11 @@ public final class WindowContainerTransaction implements Parcelable { /** * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment * {@code companionFragmentToken}. * This indicates that the organizer will remove the TaskFragment when the companion * TaskFragment is removed. * * If {@code toBeFinishedActivity} is {@code null}, this indicates that the organizer will * remove the TaskFragment when the companion TaskFragment is removed; otherwise, the organizer * will finish the {@code toBeFinishedActivity} when the companion TaskFragment is removed * unless it is the last activity in the TaskFragment. * * @param fragmentToken client assigned unique token to create TaskFragment with specified * in {@link TaskFragmentCreationParams#getFragmentToken()}. Loading @@ -1333,14 +1336,19 @@ public final class WindowContainerTransaction implements Parcelable { * {@link TaskFragmentCreationParams#getFragmentToken()}. * If it is {@code null}, the transaction will reset the companion * TaskFragment. * @param toBeFinishedActivity Activity token. If non-{@code null}, it indicates that the * organizer will only remove this activity when the companion * TaskFragment is removed. The request TaskFragment will only be * removed when this activity is the last running activity in it. * @hide */ @NonNull public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken, @Nullable IBinder companionFragmentToken) { @Nullable IBinder companionFragmentToken, @Nullable IBinder toBeFinishedActivity) { final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( OP_TYPE_SET_COMPANION_TASK_FRAGMENT) .setSecondaryFragmentToken(companionFragmentToken) .setActivityToken(toBeFinishedActivity) .build(); return addTaskFragmentOperation(fragmentToken, operation); } Loading
core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,17 @@ flag { } } flag { namespace: "windowing_sdk" name: "task_fragment_companion_activity" description: "Track the activity to be finished with tf in core" bug: "433459536" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } flag { namespace: "windowing_sdk" name: "support_gemini_on_multi_display" Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +23 −8 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; import java.util.Map; import java.util.concurrent.Executor; Loading Loading @@ -125,13 +124,15 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { * @param activityOptions ActivityOptions to start the secondary Activity with. * @param windowingMode the windowing mode to set for the TaskFragments. * @param splitAttributes the {@link SplitAttributes} to represent the split. * @param activityToBeFinishedWithSecondary the activity to be finished with the secondary. */ void startActivityToSide(@NonNull WindowContainerTransaction wct, @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingRelBounds, @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken, @NonNull Rect secondaryRelBounds, @NonNull Intent activityIntent, @Nullable Bundle activityOptions, @NonNull SplitRule rule, @WindowingMode int windowingMode, @NonNull SplitAttributes splitAttributes) { @WindowingMode int windowingMode, @NonNull SplitAttributes splitAttributes, @Nullable IBinder activityToBeFinishedWithSecondary) { final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. Loading Loading @@ -163,7 +164,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { // Set adjacent to each other so that the containers below will be invisible. setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule); setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, false /* isStacked */); false /* isStacked */, // No activity to be finished with primary because secondary is still empty. null /* activityToBeFinishedWithPrimary */, activityToBeFinishedWithSecondary); } /** Loading Loading @@ -279,7 +283,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, boolean isStacked) { boolean isStacked, @Nullable IBinder activityToBeFinishedWithPrimary, @Nullable IBinder activityToBeFinishedWithSecondary) { final boolean finishPrimaryWithSecondary; if (isStacked) { finishPrimaryWithSecondary = shouldFinishAssociatedContainerWhenStacked( Loading @@ -287,7 +292,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); } setCompanionTaskFragment(wct, primary, finishPrimaryWithSecondary ? secondary : null); if (finishPrimaryWithSecondary) { setCompanionTaskFragment(wct, primary, secondary, activityToBeFinishedWithSecondary); } else { setCompanionTaskFragment(wct, primary, null /* secondary */, null /* toBeFinishedActivity*/); } final boolean finishSecondaryWithPrimary; if (isStacked) { Loading @@ -296,12 +306,17 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); } setCompanionTaskFragment(wct, secondary, finishSecondaryWithPrimary ? primary : null); if (finishSecondaryWithPrimary) { setCompanionTaskFragment(wct, secondary, primary, activityToBeFinishedWithPrimary); } else { setCompanionTaskFragment(wct, secondary, null /* secondary */, null /* toBeFinishedActivity*/); } } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { wct.setCompanionTaskFragment(primary, secondary); @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) { wct.setCompanionTaskFragment(primary, secondary, toBeFinishedActivity); } void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +2 −1 Original line number Diff line number Diff line Loading @@ -838,7 +838,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.clearLastAdjacentTaskFragment(); container.setLastCompanionTaskFragment(null /* fragmentToken */); container.setLastCompanionTaskFragment(null /* fragmentToken */, null /* toBeFinishedActivity */); container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT); cleanupForEnterPip(wct, container); } else if (wasInPip) { Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +19 −16 Original line number Diff line number Diff line Loading @@ -367,7 +367,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { rule, splitAttributes); startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRelBounds, launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRelBounds, activityIntent, activityOptions, rule, windowingMode, splitAttributes); activityIntent, activityOptions, rule, windowingMode, splitAttributes, secondaryContainer.getActivityToFinishOnExit(primaryContainer)); if (isPlaceholder) { // When placeholder is launched in split, we should keep the focus on the primary. wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); Loading Loading @@ -432,7 +433,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryContainer.getTaskFragmentToken(), splitRule); } setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitRule, isStacked); secondaryContainer.getTaskFragmentToken(), splitRule, isStacked, primaryContainer.getActivityToFinishOnExit(secondaryContainer), secondaryContainer.getActivityToFinishOnExit(primaryContainer)); // Sets the dim area when the two TaskFragments are adjacent. final boolean dimOnTask = !isStacked Loading Loading @@ -640,20 +643,20 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @Override void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) { final TaskFragmentContainer container = mController.getContainer(primary); if (container == null) { throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is" + " not registered with controller."); } if (container.isLastCompanionTaskFragmentEqual(secondary)) { if (container.isLastCompanionTaskFragmentEqual(secondary, toBeFinishedActivity)) { // Return early if the same companion TaskFragment was already requested return; } container.setLastCompanionTaskFragment(secondary); super.setCompanionTaskFragment(wct, primary, secondary); container.setLastCompanionTaskFragment(secondary, toBeFinishedActivity); super.setCompanionTaskFragment(wct, primary, secondary, toBeFinishedActivity); } /** Loading Loading @@ -859,19 +862,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { if (!shouldShowSplit(splitAttributes)) { // If the client side hasn't received TaskFragmentInfo yet, we can't change TaskFragment // bounds. Return failure to create a new SplitContainer which fills task bounds. if (splitContainer.getPrimaryContainer().getInfo() == null || splitContainer.getSecondaryContainer().getInfo() == null) { final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer(); final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer(); if (primaryContainer.getInfo() == null || secondaryContainer.getInfo() == null) { return RESULT_EXPAND_FAILED_NO_TF_INFO; } final IBinder primaryToken = splitContainer.getPrimaryContainer().getTaskFragmentToken(); final IBinder secondaryToken = splitContainer.getSecondaryContainer().getTaskFragmentToken(); expandTaskFragment(wct, splitContainer.getPrimaryContainer()); expandTaskFragment(wct, splitContainer.getSecondaryContainer()); expandTaskFragment(wct, primaryContainer); expandTaskFragment(wct, secondaryContainer); // Set the companion TaskFragment when the two containers stacked. setCompanionTaskFragment(wct, primaryToken, secondaryToken, splitContainer.getSplitRule(), true /* isStacked */); setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitContainer.getSplitRule(), true /* isStacked */, primaryContainer.getActivityToFinishOnExit(secondaryContainer), secondaryContainer.getActivityToFinishOnExit(primaryContainer)); return RESULT_EXPANDED; } return RESULT_NOT_EXPANDED; Loading