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

Commit ef49a02e authored by Louis Chang's avatar Louis Chang
Browse files

Prevent activity being destroyed immediately if embedded

The embedded activity was destroyed immediately when being
finished because the next top activity was on the adjacent
TaskFragment and was already visible. Therefore, the finishing
animation was played before the organizer requested to
finish the activity on the adjacent TaskFragment.

Prevent the last activity of the embedded TaskFragment to
be removed immediately if the organizer requested to.

Bug: 189386466
Test: finish both activities on separate TaskFragments

Change-Id: I916eddc4dcf0de3bc7ed7264296f441d1b7bb726
parent ed8dd882
Loading
Loading
Loading
Loading
+51 −1
Original line number Original line Diff line number Diff line
@@ -516,11 +516,13 @@ public final class WindowContainerTransaction implements Parcelable {
     */
     */
    @NonNull
    @NonNull
    public WindowContainerTransaction setAdjacentTaskFragments(
    public WindowContainerTransaction setAdjacentTaskFragments(
            @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) {
            @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2,
            @Nullable TaskFragmentAdjacentOptions options) {
        final HierarchyOp hierarchyOp =
        final HierarchyOp hierarchyOp =
                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
                        .setContainer(fragmentToken1)
                        .setContainer(fragmentToken1)
                        .setReparentContainer(fragmentToken2)
                        .setReparentContainer(fragmentToken2)
                        .setLaunchOptions(options != null ? options.toBundle() : null)
                        .build();
                        .build();
        mHierarchyOps.add(hierarchyOp);
        mHierarchyOps.add(hierarchyOp);
        return this;
        return this;
@@ -1298,4 +1300,52 @@ public final class WindowContainerTransaction implements Parcelable {
            }
            }
        }
        }
    }
    }

    /**
     * Helper class for building an options Bundle that can be used to set adjacent rules of
     * TaskFragments.
     * @hide
     */
    public static class TaskFragmentAdjacentOptions {
        private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL =
                "android:transaction.adjacent.option.delay_primary_removal";
        private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL =
                "android:transaction.adjacent.option.delay_secondary_removal";

        private boolean mDelayPrimaryLastActivityRemoval;
        private boolean mDelaySecondaryLastActivityRemoval;

        public TaskFragmentAdjacentOptions() {
        }

        public TaskFragmentAdjacentOptions(@NonNull Bundle bundle) {
            mDelayPrimaryLastActivityRemoval = bundle.getBoolean(
                    DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL);
            mDelaySecondaryLastActivityRemoval = bundle.getBoolean(
                    DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL);
        }

        public void setDelayPrimaryLastActivityRemoval(boolean delay) {
            mDelayPrimaryLastActivityRemoval = delay;
        }

        public void setDelaySecondaryLastActivityRemoval(boolean delay) {
            mDelaySecondaryLastActivityRemoval = delay;
        }

        public boolean isDelayPrimaryLastActivityRemoval() {
            return mDelayPrimaryLastActivityRemoval;
        }

        public boolean isDelaySecondaryLastActivityRemoval() {
            return mDelaySecondaryLastActivityRemoval;
        }

        Bundle toBundle() {
            final Bundle b = new Bundle();
            b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval);
            b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval);
            return b;
        }
    }
}
}
+19 −3
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ import android.window.WindowContainerTransaction;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;
import androidx.window.extensions.embedding.SplitRule;


import java.util.Map;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
@@ -100,7 +101,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds,
            @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds,
            @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
            @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
            @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent,
            @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent,
            @Nullable Bundle activityOptions) {
            @Nullable Bundle activityOptions, @NonNull SplitRule rule) {
        final IBinder ownerToken = launchingActivity.getActivityToken();
        final IBinder ownerToken = launchingActivity.getActivityToken();


        // Create or resize the launching TaskFragment.
        // Create or resize the launching TaskFragment.
@@ -117,7 +118,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
                activityOptions);
                activityOptions);


        // 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(launchingFragmentToken, secondaryFragmentToken);
        setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule);
    }
    }


    /**
    /**
@@ -127,7 +128,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
     */
     */
    void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
    void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
        resizeTaskFragment(wct, fragmentToken, new Rect());
        resizeTaskFragment(wct, fragmentToken, new Rect());
        wct.setAdjacentTaskFragments(fragmentToken, null);
        setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */);
    }
    }


    /**
    /**
@@ -187,6 +188,21 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
        wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
        wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
    }
    }


    void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
            @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) {
        WindowContainerTransaction.TaskFragmentAdjacentOptions adjacentOptions = null;
        final boolean finishSecondaryWithPrimary =
                splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule);
        final boolean finishPrimaryWithSecondary =
                splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule);
        if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) {
            adjacentOptions = new WindowContainerTransaction.TaskFragmentAdjacentOptions();
            adjacentOptions.setDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary);
            adjacentOptions.setDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary);
        }
        wct.setAdjacentTaskFragments(primary, secondary, adjacentOptions);
    }

    TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
    TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
            Rect bounds, @WindowingMode int windowingMode) {
            Rect bounds, @WindowingMode int windowingMode) {
        if (mFragmentInfos.containsKey(fragmentToken)) {
        if (mFragmentInfos.containsKey(fragmentToken)) {
+16 −8
Original line number Original line Diff line number Diff line
@@ -39,16 +39,10 @@ class SplitContainer {
        mSecondaryContainer = secondaryContainer;
        mSecondaryContainer = secondaryContainer;
        mSplitRule = splitRule;
        mSplitRule = splitRule;


        final boolean isPlaceholderContainer = isPlaceholderContainer();
        if (shouldFinishPrimaryWithSecondary(splitRule)) {
        final boolean shouldFinishPrimaryWithSecondary = (mSplitRule instanceof SplitPairRule)
                && ((SplitPairRule) mSplitRule).shouldFinishPrimaryWithSecondary();
        final boolean shouldFinishSecondaryWithPrimary = (mSplitRule instanceof SplitPairRule)
                && ((SplitPairRule) mSplitRule).shouldFinishSecondaryWithPrimary();

        if (shouldFinishPrimaryWithSecondary || isPlaceholderContainer) {
            mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
            mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
        }
        }
        if (shouldFinishSecondaryWithPrimary || isPlaceholderContainer) {
        if (shouldFinishSecondaryWithPrimary(splitRule)) {
            mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
            mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
        }
        }
    }
    }
@@ -71,4 +65,18 @@ class SplitContainer {
    boolean isPlaceholderContainer() {
    boolean isPlaceholderContainer() {
        return (mSplitRule instanceof SplitPlaceholderRule);
        return (mSplitRule instanceof SplitPlaceholderRule);
    }
    }

    static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
        final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
        final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule)
                && ((SplitPairRule) splitRule).shouldFinishPrimaryWithSecondary();
        return shouldFinishPrimaryWithSecondary || isPlaceholderContainer;
    }

    static boolean shouldFinishSecondaryWithPrimary(@NonNull SplitRule splitRule) {
        final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
        final boolean shouldFinishSecondaryWithPrimary = (splitRule instanceof SplitPairRule)
                && ((SplitPairRule) splitRule).shouldFinishSecondaryWithPrimary();
        return shouldFinishSecondaryWithPrimary || isPlaceholderContainer;
    }
}
}
+5 −5
Original line number Original line Diff line number Diff line
@@ -109,8 +109,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
        secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
        secondaryContainer.setLastRequestedBounds(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(
        setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
                secondaryContainer.getTaskFragmentToken(), rule);


        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);


@@ -144,8 +144,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
                secondaryActivity, secondaryRectBounds, primaryContainer);
                secondaryActivity, secondaryRectBounds, primaryContainer);


        // 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(
        setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
                secondaryContainer.getTaskFragmentToken(), rule);


        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
        mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);


@@ -212,7 +212,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
                rule);
                rule);
        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
        startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
                launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
                activityIntent, activityOptions);
                activityIntent, activityOptions, rule);
        applyTransaction(wct);
        applyTransaction(wct);


        primaryContainer.setLastRequestedBounds(primaryRectBounds);
        primaryContainer.setLastRequestedBounds(primaryRectBounds);
+15 −1
Original line number Original line Diff line number Diff line
@@ -3234,6 +3234,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
        // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
        final ActivityRecord next = getDisplayArea().topRunningActivity(
        final ActivityRecord next = getDisplayArea().topRunningActivity(
                true /* considerKeyguardState */);
                true /* considerKeyguardState */);

        // If the finishing activity is the last activity of a organized TaskFragment and has an
        // adjacent TaskFragment, check if the activity removal should be delayed.
        boolean delayRemoval = false;
        final TaskFragment taskFragment = getTaskFragment();
        if (next != null && taskFragment != null && taskFragment.isEmbedded()) {
            final TaskFragment organized = taskFragment.getOrganizedTaskFragment();
            final TaskFragment adjacent =
                    organized != null ? organized.getAdjacentTaskFragment() : null;
            if (adjacent != null && organized.topRunningActivity() == null) {
                delayRemoval = organized.isDelayLastActivityRemoval();
            }
        }

        // isNextNotYetVisible is to check if the next activity is invisible, or it has been
        // isNextNotYetVisible is to check if the next activity is invisible, or it has been
        // requested to be invisible but its windows haven't reported as invisible.  If so, it
        // requested to be invisible but its windows haven't reported as invisible.  If so, it
        // implied that the current finishing activity should be added into stopping list rather
        // implied that the current finishing activity should be added into stopping list rather
@@ -3248,7 +3262,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
        }


        if (isCurrentVisible) {
        if (isCurrentVisible) {
            if (isNextNotYetVisible) {
            if (isNextNotYetVisible || delayRemoval) {
                // Add this activity to the list of stopping activities. It will be processed and
                // Add this activity to the list of stopping activities. It will be processed and
                // destroyed when the next activity reports idle.
                // destroyed when the next activity reports idle.
                addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
                addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
Loading