Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1614422a authored by Chris Li's avatar Chris Li
Browse files

Track the companion activity along with companion TaskFragment

When a split pair is created with finish rule, if the primary contains
multiple activities, we will only track and finish the top activity when
the companion TF is finished.

We need to track this info in Core as well to predict back navigation.

Fix: 433459536
Flag: com.android.window.flags.task_fragment_companion_activity
Test: atest WMJetpackUnitTests:SplitPresenterTest
Test: atest WmTests:TaskFragmentOrganizerControllerTest
Test: atest WmTests:BackNavigationControllerTests
Change-Id: Iff00034d3b01a7d719efc031ccf0bcbe34135c92
parent 8441f07f
Loading
Loading
Loading
Loading
+11 −3
Original line number Original line Diff line number Diff line
@@ -1323,8 +1323,11 @@ public final class WindowContainerTransaction implements Parcelable {
    /**
    /**
     * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
     * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
     * {@code companionFragmentToken}.
     * {@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
     * @param fragmentToken client assigned unique token to create TaskFragment with specified
     *                      in {@link TaskFragmentCreationParams#getFragmentToken()}.
     *                      in {@link TaskFragmentCreationParams#getFragmentToken()}.
@@ -1333,14 +1336,19 @@ public final class WindowContainerTransaction implements Parcelable {
     *                               {@link TaskFragmentCreationParams#getFragmentToken()}.
     *                               {@link TaskFragmentCreationParams#getFragmentToken()}.
     *                               If it is {@code null}, the transaction will reset the companion
     *                               If it is {@code null}, the transaction will reset the companion
     *                               TaskFragment.
     *                               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
     * @hide
     */
     */
    @NonNull
    @NonNull
    public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
    public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
            @Nullable IBinder companionFragmentToken) {
            @Nullable IBinder companionFragmentToken, @Nullable IBinder toBeFinishedActivity) {
        final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
        final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
                OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
                OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
                .setSecondaryFragmentToken(companionFragmentToken)
                .setSecondaryFragmentToken(companionFragmentToken)
                .setActivityToken(toBeFinishedActivity)
                .build();
                .build();
        return addTaskFragmentOperation(fragmentToken, operation);
        return addTaskFragmentOperation(fragmentToken, operation);
    }
    }
+11 −0
Original line number Original line Diff line number Diff line
@@ -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 {
flag {
    namespace: "windowing_sdk"
    namespace: "windowing_sdk"
    name: "support_gemini_on_multi_display"
    name: "support_gemini_on_multi_display"
+23 −8
Original line number Original line Diff line number Diff line
@@ -50,7 +50,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;


import java.util.Map;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
@@ -125,13 +124,15 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
     * @param activityOptions   ActivityOptions to start the secondary Activity with.
     * @param activityOptions   ActivityOptions to start the secondary Activity with.
     * @param windowingMode     the windowing mode to set for the TaskFragments.
     * @param windowingMode     the windowing mode to set for the TaskFragments.
     * @param splitAttributes   the {@link SplitAttributes} to represent the split.
     * @param splitAttributes   the {@link SplitAttributes} to represent the split.
     * @param activityToBeFinishedWithSecondary the activity to be finished with the secondary.
     */
     */
    void startActivityToSide(@NonNull WindowContainerTransaction wct,
    void startActivityToSide(@NonNull WindowContainerTransaction wct,
            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingRelBounds,
            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingRelBounds,
            @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
            @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
            @NonNull Rect secondaryRelBounds, @NonNull Intent activityIntent,
            @NonNull Rect secondaryRelBounds, @NonNull Intent activityIntent,
            @Nullable Bundle activityOptions, @NonNull SplitRule rule,
            @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();
        final IBinder ownerToken = launchingActivity.getActivityToken();


        // Create or resize the launching TaskFragment.
        // Create or resize the launching TaskFragment.
@@ -163,7 +164,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
        // 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.
        setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule);
        setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule);
        setCompanionTaskFragment(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);
    }
    }


    /**
    /**
@@ -279,7 +283,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {


    void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct,
    void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct,
            @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule,
            @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule,
            boolean isStacked) {
            boolean isStacked, @Nullable IBinder activityToBeFinishedWithPrimary,
            @Nullable IBinder activityToBeFinishedWithSecondary) {
        final boolean finishPrimaryWithSecondary;
        final boolean finishPrimaryWithSecondary;
        if (isStacked) {
        if (isStacked) {
            finishPrimaryWithSecondary = shouldFinishAssociatedContainerWhenStacked(
            finishPrimaryWithSecondary = shouldFinishAssociatedContainerWhenStacked(
@@ -287,7 +292,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
        } else {
        } else {
            finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule);
            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;
        final boolean finishSecondaryWithPrimary;
        if (isStacked) {
        if (isStacked) {
@@ -296,12 +306,17 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
        } else {
        } else {
            finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule);
            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,
    void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary,
            @Nullable IBinder secondary) {
            @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) {
        wct.setCompanionTaskFragment(primary, secondary);
        wct.setCompanionTaskFragment(primary, secondary, toBeFinishedActivity);
    }
    }


    void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
    void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+2 −1
Original line number Original line Diff line number Diff line
@@ -838,7 +838,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            container.setLastRequestedBounds(null /* bounds */);
            container.setLastRequestedBounds(null /* bounds */);
            container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED);
            container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED);
            container.clearLastAdjacentTaskFragment();
            container.clearLastAdjacentTaskFragment();
            container.setLastCompanionTaskFragment(null /* fragmentToken */);
            container.setLastCompanionTaskFragment(null /* fragmentToken */,
                    null /* toBeFinishedActivity */);
            container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT);
            container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT);
            cleanupForEnterPip(wct, container);
            cleanupForEnterPip(wct, container);
        } else if (wasInPip) {
        } else if (wasInPip) {
+19 −16
Original line number Original line Diff line number Diff line
@@ -367,7 +367,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
                rule, splitAttributes);
                rule, splitAttributes);
        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRelBounds,
        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRelBounds,
                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRelBounds,
                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRelBounds,
                activityIntent, activityOptions, rule, windowingMode, splitAttributes);
                activityIntent, activityOptions, rule, windowingMode, splitAttributes,
                secondaryContainer.getActivityToFinishOnExit(primaryContainer));
        if (isPlaceholder) {
        if (isPlaceholder) {
            // When placeholder is launched in split, we should keep the focus on the primary.
            // When placeholder is launched in split, we should keep the focus on the primary.
            wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
            wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
@@ -432,7 +433,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
                    secondaryContainer.getTaskFragmentToken(), splitRule);
                    secondaryContainer.getTaskFragmentToken(), splitRule);
        }
        }
        setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(),
        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.
        // Sets the dim area when the two TaskFragments are adjacent.
        final boolean dimOnTask = !isStacked
        final boolean dimOnTask = !isStacked
@@ -640,20 +643,20 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {


    @Override
    @Override
    void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary,
    void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary,
                                  @Nullable IBinder secondary) {
            @Nullable IBinder secondary, @Nullable IBinder toBeFinishedActivity) {
        final TaskFragmentContainer container = mController.getContainer(primary);
        final TaskFragmentContainer container = mController.getContainer(primary);
        if (container == null) {
        if (container == null) {
            throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is"
            throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is"
                    + " not registered with controller.");
                    + " not registered with controller.");
        }
        }


        if (container.isLastCompanionTaskFragmentEqual(secondary)) {
        if (container.isLastCompanionTaskFragmentEqual(secondary, toBeFinishedActivity)) {
            // Return early if the same companion TaskFragment was already requested
            // Return early if the same companion TaskFragment was already requested
            return;
            return;
        }
        }


        container.setLastCompanionTaskFragment(secondary);
        container.setLastCompanionTaskFragment(secondary, toBeFinishedActivity);
        super.setCompanionTaskFragment(wct, primary, secondary);
        super.setCompanionTaskFragment(wct, primary, secondary, toBeFinishedActivity);
    }
    }


    /**
    /**
@@ -859,19 +862,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
        if (!shouldShowSplit(splitAttributes)) {
        if (!shouldShowSplit(splitAttributes)) {
            // If the client side hasn't received TaskFragmentInfo yet, we can't change TaskFragment
            // 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.
            // bounds. Return failure to create a new SplitContainer which fills task bounds.
            if (splitContainer.getPrimaryContainer().getInfo() == null
            final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer();
                    || splitContainer.getSecondaryContainer().getInfo() == null) {
            final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
            if (primaryContainer.getInfo() == null || secondaryContainer.getInfo() == null) {
                return RESULT_EXPAND_FAILED_NO_TF_INFO;
                return RESULT_EXPAND_FAILED_NO_TF_INFO;
            }
            }
            final IBinder primaryToken =
            expandTaskFragment(wct, primaryContainer);
                    splitContainer.getPrimaryContainer().getTaskFragmentToken();
            expandTaskFragment(wct, secondaryContainer);
            final IBinder secondaryToken =
                    splitContainer.getSecondaryContainer().getTaskFragmentToken();
            expandTaskFragment(wct, splitContainer.getPrimaryContainer());
            expandTaskFragment(wct, splitContainer.getSecondaryContainer());
            // Set the companion TaskFragment when the two containers stacked.
            // Set the companion TaskFragment when the two containers stacked.
            setCompanionTaskFragment(wct, primaryToken, secondaryToken,
            setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(),
                    splitContainer.getSplitRule(), true /* isStacked */);
                    secondaryContainer.getTaskFragmentToken(), splitContainer.getSplitRule(),
                    true /* isStacked */,
                    primaryContainer.getActivityToFinishOnExit(secondaryContainer),
                    secondaryContainer.getActivityToFinishOnExit(primaryContainer));
            return RESULT_EXPANDED;
            return RESULT_EXPANDED;
        }
        }
        return RESULT_NOT_EXPANDED;
        return RESULT_NOT_EXPANDED;
Loading