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

Commit eaeeaa56 authored by Charles Chen's avatar Charles Chen
Browse files

Extend bounds computation to support horizontal layout

This CL introduces SplitLayout and update bounds computation methods
to support horizontal layout. It also introduces #computeSplitLayout
to compute the current split layout, which always returns the default
splitLayout currently. #computeSplitLayout will extend to consider
SplitLayoutCalculator in later CL.

fixes: 241042437
Bug: 241043028
Bug: 207494880
Test: atest SplitPresenterTest
Change-Id: I037a2b2fa38d05c4fe97e4734cc044148ad15806
parent fe23ec48
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import android.window.TaskFragmentOrganizer;
import android.window.TaskFragmentTransaction;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;


import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;


@@ -93,6 +94,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
    }
    }


    /** No longer overrides the animation if the transition is on the given Task. */
    /** No longer overrides the animation if the transition is on the given Task. */
    @GuardedBy("mLock")
    void stopOverrideSplitAnimation(int taskId) {
    void stopOverrideSplitAnimation(int taskId) {
        if (mAnimationController != null) {
        if (mAnimationController != null) {
            mAnimationController.unregisterRemoteAnimations(taskId);
            mAnimationController.unregisterRemoteAnimations(taskId);
+28 −1
Original line number Original line Diff line number Diff line
@@ -17,8 +17,10 @@
package androidx.window.extensions.embedding;
package androidx.window.extensions.embedding;


import android.app.Activity;
import android.app.Activity;
import android.content.res.Configuration;
import android.util.Pair;
import android.util.Pair;
import android.util.Size;
import android.util.Size;
import android.window.WindowContainerTransaction;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;


@@ -32,14 +34,18 @@ class SplitContainer {
    private final TaskFragmentContainer mSecondaryContainer;
    private final TaskFragmentContainer mSecondaryContainer;
    @NonNull
    @NonNull
    private final SplitRule mSplitRule;
    private final SplitRule mSplitRule;
    @NonNull
    private SplitAttributes mSplitAttributes;


    SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
    SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
            @NonNull Activity primaryActivity,
            @NonNull Activity primaryActivity,
            @NonNull TaskFragmentContainer secondaryContainer,
            @NonNull TaskFragmentContainer secondaryContainer,
            @NonNull SplitRule splitRule) {
            @NonNull SplitRule splitRule,
            @NonNull SplitAttributes splitAttributes) {
        mPrimaryContainer = primaryContainer;
        mPrimaryContainer = primaryContainer;
        mSecondaryContainer = secondaryContainer;
        mSecondaryContainer = secondaryContainer;
        mSplitRule = splitRule;
        mSplitRule = splitRule;
        mSplitAttributes = splitAttributes;


        if (shouldFinishPrimaryWithSecondary(splitRule)) {
        if (shouldFinishPrimaryWithSecondary(splitRule)) {
            if (mPrimaryContainer.getRunningActivityCount() == 1
            if (mPrimaryContainer.getRunningActivityCount() == 1
@@ -72,6 +78,26 @@ class SplitContainer {
        return mSplitRule;
        return mSplitRule;
    }
    }


    @NonNull
    SplitAttributes getSplitAttributes() {
        return mSplitAttributes;
    }

    /**
     * Updates the {@link SplitAttributes} to this container.
     * It is usually used when there's a folding state change or
     * {@link SplitController#onTaskFragmentParentInfoChanged(WindowContainerTransaction, int,
     * Configuration)}.
     */
    void setSplitAttributes(@NonNull SplitAttributes splitAttributes) {
        mSplitAttributes = splitAttributes;
    }

    @NonNull
    TaskContainer getTaskContainer() {
        return getPrimaryContainer().getTaskContainer();
    }

    /** Returns the minimum dimension pair of primary container and secondary container. */
    /** Returns the minimum dimension pair of primary container and secondary container. */
    @NonNull
    @NonNull
    Pair<Size, Size> getMinDimensionsPair() {
    Pair<Size, Size> getMinDimensionsPair() {
@@ -141,6 +167,7 @@ class SplitContainer {
                + " primaryContainer=" + mPrimaryContainer
                + " primaryContainer=" + mPrimaryContainer
                + " secondaryContainer=" + mSecondaryContainer
                + " secondaryContainer=" + mSecondaryContainer
                + " splitRule=" + mSplitRule
                + " splitRule=" + mSplitRule
                + " splitAttributes" + mSplitAttributes
                + "}";
                + "}";
    }
    }
}
}
+78 −41
Original line number Original line Diff line number Diff line
@@ -41,7 +41,7 @@ import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAs
import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO;
import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO;
import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
import static androidx.window.extensions.embedding.SplitPresenter.getNonEmbeddedActivityBounds;
import static androidx.window.extensions.embedding.SplitPresenter.getNonEmbeddedActivityBounds;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;


import android.app.Activity;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityClient;
@@ -64,6 +64,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Pair;
import android.util.Size;
import android.util.Size;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.WindowMetrics;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.TaskFragmentTransaction;
@@ -582,6 +583,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * Updates if we should override transition animation. We only want to override if the Task
     * Updates if we should override transition animation. We only want to override if the Task
     * bounds is large enough for at least one split rule.
     * bounds is large enough for at least one split rule.
     */
     */
    @GuardedBy("mLock")
    private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
    private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
        if (ENABLE_SHELL_TRANSITIONS) {
        if (ENABLE_SHELL_TRANSITIONS) {
            // TODO(b/207070762): cleanup with legacy app transition
            // TODO(b/207070762): cleanup with legacy app transition
@@ -593,15 +595,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return;
            return;
        }
        }


        // We only want to override if it supports split.
        // We only want to override if the TaskContainer may show split.
        if (supportSplit(taskContainer)) {
        if (mayShowSplit(taskContainer)) {
            mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
            mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
        } else {
        } else {
            mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
            mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
        }
        }
    }
    }


    private boolean supportSplit(@NonNull TaskContainer taskContainer) {
    /** Returns whether the given {@link TaskContainer} may show in split. */
    // Suppress GuardedBy warning because lint asks to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    private boolean mayShowSplit(@NonNull TaskContainer taskContainer) {
        // No split inside PIP.
        // No split inside PIP.
        if (taskContainer.isInPictureInPicture()) {
        if (taskContainer.isInPictureInPicture()) {
            return false;
            return false;
@@ -611,7 +618,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            if (!(rule instanceof SplitRule)) {
            if (!(rule instanceof SplitRule)) {
                continue;
                continue;
            }
            }
            if (shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
            final SplitRule splitRule = (SplitRule) rule;
            final SplitAttributes splitAttributes = mPresenter.computeSplitAttributes(
                    taskContainer.getTaskProperties(), splitRule, null /* minDimensionsPair */);
            if (shouldShowSplit(splitAttributes)) {
                return true;
                return true;
            }
            }
        }
        }
@@ -755,14 +765,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    /**
    /**
     * Starts an activity to side of the launchingActivity with the provided split config.
     * Starts an activity to side of the launchingActivity with the provided split config.
     */
     */
    // Suppress GuardedBy warning because lint ask to mark this method as
    // @GuardedBy(container.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private void startActivityToSide(@NonNull WindowContainerTransaction wct,
    private void startActivityToSide(@NonNull WindowContainerTransaction wct,
            @NonNull Activity launchingActivity, @NonNull Intent intent,
            @NonNull Activity launchingActivity, @NonNull Intent intent,
            @Nullable Bundle options, @NonNull SplitRule sideRule,
            @Nullable Bundle options, @NonNull SplitRule sideRule,
            @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) {
            @NonNull SplitAttributes splitAttributes, @Nullable Consumer<Exception> failureCallback,
            boolean isPlaceholder) {
        try {
        try {
            mPresenter.startActivityToSide(wct, launchingActivity, intent, options, sideRule,
            mPresenter.startActivityToSide(wct, launchingActivity, intent, options, sideRule,
                    isPlaceholder);
                    splitAttributes, isPlaceholder);
        } catch (Exception e) {
        } catch (Exception e) {
            if (failureCallback != null) {
            if (failureCallback != null) {
                failureCallback.accept(e);
                failureCallback.accept(e);
@@ -789,6 +803,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    }
    }


    /** Whether the given new launched activity is in a split with a rule matched. */
    /** Whether the given new launched activity is in a split with a rule matched. */
    // Suppress GuardedBy warning because lint asks to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    private boolean isNewActivityInSplitWithRuleMatched(@NonNull Activity launchedActivity) {
    private boolean isNewActivityInSplitWithRuleMatched(@NonNull Activity launchedActivity) {
        final TaskFragmentContainer container = getContainerWithActivity(launchedActivity);
        final TaskFragmentContainer container = getContainerWithActivity(launchedActivity);
        final SplitContainer splitContainer = getActiveSplitForContainer(container);
        final SplitContainer splitContainer = getActiveSplitForContainer(container);
@@ -882,8 +900,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        final TaskFragmentContainer primaryContainer = getContainerWithActivity(
        final TaskFragmentContainer primaryContainer = getContainerWithActivity(
                primaryActivity);
                primaryActivity);
        final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
        final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
        final WindowMetrics taskWindowMetrics = mPresenter.getTaskWindowMetrics(primaryActivity);
        if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
        if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
                && canReuseContainer(splitRule, splitContainer.getSplitRule())) {
                && canReuseContainer(splitRule, splitContainer.getSplitRule(), taskWindowMetrics)) {
            // Can launch in the existing secondary container if the rules share the same
            // Can launch in the existing secondary container if the rules share the same
            // presentation.
            // presentation.
            final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
            final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
@@ -1013,6 +1032,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    @Nullable
    @Nullable
    @GuardedBy("mLock")
    TaskFragmentContainer resolveStartActivityIntent(@NonNull WindowContainerTransaction wct,
    TaskFragmentContainer resolveStartActivityIntent(@NonNull WindowContainerTransaction wct,
            int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
            int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
        /*
        /*
@@ -1117,8 +1137,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        }
        }
        final TaskFragmentContainer existingContainer = getContainerWithActivity(primaryActivity);
        final TaskFragmentContainer existingContainer = getContainerWithActivity(primaryActivity);
        final SplitContainer splitContainer = getActiveSplitForContainer(existingContainer);
        final SplitContainer splitContainer = getActiveSplitForContainer(existingContainer);
        final WindowMetrics taskWindowMetrics = mPresenter.getTaskWindowMetrics(primaryActivity);
        if (splitContainer != null && existingContainer == splitContainer.getPrimaryContainer()
        if (splitContainer != null && existingContainer == splitContainer.getPrimaryContainer()
                && (canReuseContainer(splitRule, splitContainer.getSplitRule())
                && (canReuseContainer(splitRule, splitContainer.getSplitRule(), taskWindowMetrics)
                // TODO(b/231845476) we should always respect clearTop.
                // TODO(b/231845476) we should always respect clearTop.
                || !respectClearTop)
                || !respectClearTop)
                && mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
                && mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
@@ -1208,12 +1229,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * Creates and registers a new split with the provided containers and configuration. Finishes
     * Creates and registers a new split with the provided containers and configuration. Finishes
     * existing secondary containers if found for the given primary container.
     * existing secondary containers if found for the given primary container.
     */
     */
    // Suppress GuardedBy warning because lint ask to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    void registerSplit(@NonNull WindowContainerTransaction wct,
    void registerSplit(@NonNull WindowContainerTransaction wct,
            @NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
            @NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
            @NonNull TaskFragmentContainer secondaryContainer,
            @NonNull TaskFragmentContainer secondaryContainer,
            @NonNull SplitRule splitRule) {
            @NonNull SplitRule splitRule, @NonNull SplitAttributes splitAttributes) {
        final SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
        final SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
                secondaryContainer, splitRule);
                secondaryContainer, splitRule, splitAttributes);
        // Remove container later to prevent pinning escaping toast showing in lock task mode.
        // Remove container later to prevent pinning escaping toast showing in lock task mode.
        if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
        if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
            removeExistingSecondaryContainers(wct, primaryContainer);
            removeExistingSecondaryContainers(wct, primaryContainer);
@@ -1364,6 +1389,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            // Skip position update - one or both containers are finished.
            // Skip position update - one or both containers are finished.
            return;
            return;
        }
        }
        final TaskContainer taskContainer = splitContainer.getTaskContainer();
        final SplitRule splitRule = splitContainer.getSplitRule();
        final Pair<Size, Size> minDimensionsPair = splitContainer.getMinDimensionsPair();
        final SplitAttributes splitAttributes = mPresenter.computeSplitAttributes(
                taskContainer.getTaskProperties(), splitRule, minDimensionsPair);
        splitContainer.setSplitAttributes(splitAttributes);
        if (dismissPlaceholderIfNecessary(wct, splitContainer)) {
        if (dismissPlaceholderIfNecessary(wct, splitContainer)) {
            // Placeholder was finished, the positions will be updated when its container is emptied
            // Placeholder was finished, the positions will be updated when its container is emptied
            return;
            return;
@@ -1437,6 +1468,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        return launchPlaceholderIfNecessary(wct, topActivity, false /* isOnCreated */);
        return launchPlaceholderIfNecessary(wct, topActivity, false /* isOnCreated */);
    }
    }


    // Suppress GuardedBy warning because lint ask to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    boolean launchPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
    boolean launchPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
            @NonNull Activity activity, boolean isOnCreated) {
            @NonNull Activity activity, boolean isOnCreated) {
@@ -1463,18 +1497,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return false;
            return false;
        }
        }


        final TaskContainer.TaskProperties taskProperties = mPresenter.getTaskProperties(activity);
        final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(activity,
        final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(activity,
                placeholderRule.getPlaceholderIntent());
                placeholderRule.getPlaceholderIntent());
        if (!shouldShowSideBySide(
        final SplitAttributes splitAttributes = mPresenter.computeSplitAttributes(taskProperties,
                mPresenter.getParentContainerBounds(activity), placeholderRule,
                placeholderRule, minDimensionsPair);
                minDimensionsPair)) {
        if (!SplitPresenter.shouldShowSplit(splitAttributes)) {
            return false;
            return false;
        }
        }


        // TODO(b/190433398): Handle failed request
        // TODO(b/190433398): Handle failed request
        final Bundle options = getPlaceholderOptions(activity, isOnCreated);
        final Bundle options = getPlaceholderOptions(activity, isOnCreated);
        startActivityToSide(wct, activity, placeholderRule.getPlaceholderIntent(), options,
        startActivityToSide(wct, activity, placeholderRule.getPlaceholderIntent(), options,
                placeholderRule, null /* failureCallback */, true /* isPlaceholder */);
                placeholderRule, splitAttributes, null /* failureCallback */,
                true /* isPlaceholder */);
        return true;
        return true;
    }
    }


@@ -1499,6 +1535,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        return options.toBundle();
        return options.toBundle();
    }
    }


    // Suppress GuardedBy warning because lint ask to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @VisibleForTesting
    @VisibleForTesting
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    boolean dismissPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
    boolean dismissPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
@@ -1511,11 +1550,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            // The placeholder should remain after it was first shown.
            // The placeholder should remain after it was first shown.
            return false;
            return false;
        }
        }

        final SplitAttributes splitAttributes = splitContainer.getSplitAttributes();
        if (shouldShowSideBySide(splitContainer)) {
        if (SplitPresenter.shouldShowSplit(splitAttributes)) {
            return false;
            return false;
        }
        }

        mPresenter.cleanupContainer(wct, splitContainer.getSecondaryContainer(),
        mPresenter.cleanupContainer(wct, splitContainer.getSecondaryContainer(),
                false /* shouldFinishDependent */);
                false /* shouldFinishDependent */);
        return true;
        return true;
@@ -1525,6 +1563,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * Returns the rule to launch a placeholder for the activity with the provided component name
     * Returns the rule to launch a placeholder for the activity with the provided component name
     * if it is configured in the split config.
     * if it is configured in the split config.
     */
     */
    @GuardedBy("mLock")
    private SplitPlaceholderRule getPlaceholderRule(@NonNull Activity activity) {
    private SplitPlaceholderRule getPlaceholderRule(@NonNull Activity activity) {
        for (EmbeddingRule rule : mSplitRules) {
        for (EmbeddingRule rule : mSplitRules) {
            if (!(rule instanceof SplitPlaceholderRule)) {
            if (!(rule instanceof SplitPlaceholderRule)) {
@@ -1541,6 +1580,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    /**
    /**
     * Notifies listeners about changes to split states if necessary.
     * Notifies listeners about changes to split states if necessary.
     */
     */
    @GuardedBy("mLock")
    private void updateCallbackIfNecessary() {
    private void updateCallbackIfNecessary() {
        if (mEmbeddingCallback == null) {
        if (mEmbeddingCallback == null) {
            return;
            return;
@@ -1562,6 +1602,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * null, that indicates that the active split states are in an intermediate state and should
     * null, that indicates that the active split states are in an intermediate state and should
     * not be reported.
     * not be reported.
     */
     */
    @GuardedBy("mLock")
    @Nullable
    @Nullable
    private List<SplitInfo> getActiveSplitStates() {
    private List<SplitInfo> getActiveSplitStates() {
        List<SplitInfo> splitStates = new ArrayList<>();
        List<SplitInfo> splitStates = new ArrayList<>();
@@ -1580,20 +1621,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                        .toActivityStack();
                        .toActivityStack();
                final ActivityStack secondaryContainer = container.getSecondaryContainer()
                final ActivityStack secondaryContainer = container.getSecondaryContainer()
                        .toActivityStack();
                        .toActivityStack();
                final SplitAttributes.SplitType splitType = shouldShowSideBySide(container)
                        ? new SplitAttributes.SplitType.RatioSplitType(
                                container.getSplitRule().getSplitRatio())
                        : new SplitAttributes.SplitType.ExpandContainersSplitType();
                final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
                final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
                        // Splits that are not showing side-by-side are reported as having 0 split
                        container.getSplitAttributes());
                        // ratio, since by definition in the API the primary container occupies no
                        // width of the split when covered by the secondary.
                        // TODO(b/241042437): use v2 APIs for splitAttributes
                        new SplitAttributes.Builder()
                                .setSplitType(splitType)
                                .setLayoutDirection(container.getSplitRule().getLayoutDirection())
                                .build()
                        );
                splitStates.add(splitState);
                splitStates.add(splitState);
            }
            }
        }
        }
@@ -1631,6 +1660,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * Returns a split rule for the provided pair of primary activity and secondary activity intent
     * Returns a split rule for the provided pair of primary activity and secondary activity intent
     * if available.
     * if available.
     */
     */
    @GuardedBy("mLock")
    @Nullable
    @Nullable
    private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
    private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
            @NonNull Intent secondaryActivityIntent) {
            @NonNull Intent secondaryActivityIntent) {
@@ -1649,6 +1679,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    /**
    /**
     * Returns a split rule for the provided pair of primary and secondary activities if available.
     * Returns a split rule for the provided pair of primary and secondary activities if available.
     */
     */
    @GuardedBy("mLock")
    @Nullable
    @Nullable
    private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
    private SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
            @NonNull Activity secondaryActivity) {
            @NonNull Activity secondaryActivity) {
@@ -1723,6 +1754,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * Returns {@code true} if an Activity with the provided component name should always be
     * Returns {@code true} if an Activity with the provided component name should always be
     * expanded to occupy full task bounds. Such activity must not be put in a split.
     * expanded to occupy full task bounds. Such activity must not be put in a split.
     */
     */
    @GuardedBy("mLock")
    private boolean shouldExpand(@Nullable Activity activity, @Nullable Intent intent) {
    private boolean shouldExpand(@Nullable Activity activity, @Nullable Intent intent) {
        for (EmbeddingRule rule : mSplitRules) {
        for (EmbeddingRule rule : mSplitRules) {
            if (!(rule instanceof ActivityRule)) {
            if (!(rule instanceof ActivityRule)) {
@@ -1748,6 +1780,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * 'sticky' and the placeholder was finished when fully overlapping the primary container.
     * 'sticky' and the placeholder was finished when fully overlapping the primary container.
     * @return {@code true} if the associated container should be retained (and not be finished).
     * @return {@code true} if the associated container should be retained (and not be finished).
     */
     */
    // Suppress GuardedBy warning because lint ask to mark this method as
    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
    @SuppressWarnings("GuardedBy")
    @GuardedBy("mLock")
    boolean shouldRetainAssociatedContainer(@NonNull TaskFragmentContainer finishingContainer,
    boolean shouldRetainAssociatedContainer(@NonNull TaskFragmentContainer finishingContainer,
            @NonNull TaskFragmentContainer associatedContainer) {
            @NonNull TaskFragmentContainer associatedContainer) {
        SplitContainer splitContainer = getActiveSplitForContainers(associatedContainer,
        SplitContainer splitContainer = getActiveSplitForContainers(associatedContainer,
@@ -1766,7 +1802,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        }
        }
        // Decide whether the associated container should be retained based on the current
        // Decide whether the associated container should be retained based on the current
        // presentation mode.
        // presentation mode.
        if (shouldShowSideBySide(splitContainer)) {
        if (shouldShowSplit(splitContainer)) {
            return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
            return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
        } else {
        } else {
            return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
            return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
@@ -1959,23 +1995,24 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
     * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
     * there is any.
     * there is any.
     */
     */
    private static boolean canReuseContainer(@NonNull SplitRule rule1, @NonNull SplitRule rule2) {
    private static boolean canReuseContainer(@NonNull SplitRule rule1, @NonNull SplitRule rule2,
            @NonNull WindowMetrics parentWindowMetrics) {
        if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
        if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
            return false;
            return false;
        }
        }
        return haveSamePresentation((SplitPairRule) rule1, (SplitPairRule) rule2);
        return haveSamePresentation((SplitPairRule) rule1, (SplitPairRule) rule2,
                parentWindowMetrics);
    }
    }


    /** Whether the two rules have the same presentation. */
    /** Whether the two rules have the same presentation. */
    private static boolean haveSamePresentation(@NonNull SplitPairRule rule1,
    private static boolean haveSamePresentation(@NonNull SplitPairRule rule1,
            @NonNull SplitPairRule rule2) {
            @NonNull SplitPairRule rule2, @NonNull WindowMetrics parentWindowMetrics) {
        // TODO(b/231655482): add util method to do the comparison in SplitPairRule.
        // TODO(b/231655482): add util method to do the comparison in SplitPairRule.
        return rule1.getSplitRatio() == rule2.getSplitRatio()
        return rule1.getDefaultSplitAttributes().equals(rule2.getDefaultSplitAttributes())
                && rule1.getLayoutDirection() == rule2.getLayoutDirection()
                && rule1.checkParentMetrics(parentWindowMetrics)
                && rule1.getFinishPrimaryWithSecondary()
                == rule2.checkParentMetrics(parentWindowMetrics)
                == rule2.getFinishPrimaryWithSecondary()
                && rule1.getFinishPrimaryWithSecondary() == rule2.getFinishPrimaryWithSecondary()
                && rule1.getFinishSecondaryWithPrimary()
                && rule1.getFinishSecondaryWithPrimary() == rule2.getFinishSecondaryWithPrimary();
                == rule2.getFinishSecondaryWithPrimary();
    }
    }


    /**
    /**
Loading