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

Commit b777d358 authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Add support for sticky placeholders

Normally placeholders are finished when there is not enough space
to show them by the side of the primary activity. However, in some
cases it makes sense to continue showing the placeholder stacked
on top when the window is small after it first appeared in a split
with a larger window size.

This CL introduces an option to make placeholders sticky and behave
similar to regular split rules in stacked case for consistency.

Bug: 202810486
Test: New option in the demo app
Change-Id: I60e8973679d95f52aaa231581a3063d9f30d4be3
parent db38b7fa
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -84,6 +84,13 @@ class SplitContainer {
        return shouldFinishSecondaryWithPrimary || isPlaceholderContainer;
    }

    static boolean isStickyPlaceholderRule(@NonNull SplitRule splitRule) {
        if (!(splitRule instanceof SplitPlaceholderRule)) {
            return false;
        }
        return ((SplitPlaceholderRule) splitRule).isSticky();
    }

    @Override
    public String toString() {
        return "SplitContainer{"
+47 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package androidx.window.extensions.embedding;

import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -460,6 +462,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return false;
        }

        if (isStickyPlaceholderRule(splitContainer.getSplitRule())) {
            // The placeholder should remain after it was first shown.
            return false;
        }

        if (mPresenter.shouldShowSideBySide(splitContainer)) {
            return false;
        }
@@ -643,6 +650,46 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        return false;
    }

    /**
     * Checks whether the associated container should be destroyed together with a finishing
     * container. There is a case when primary containers for placeholders should be retained
     * despite the rule configuration to finish primary with secondary - if they are marked as
     * '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).
     */
    boolean shouldRetainAssociatedContainer(@NonNull TaskFragmentContainer finishingContainer,
            @NonNull TaskFragmentContainer associatedContainer) {
        SplitContainer splitContainer = getActiveSplitForContainers(associatedContainer,
                finishingContainer);
        if (splitContainer == null) {
            // Containers are not in the same split, no need to retain.
            return false;
        }

        if (!isStickyPlaceholderRule(splitContainer.getSplitRule())) {
            // Currently only the containers associated with sticky placeholders can be retained.
            return false;
        }

        // When sticky placeholder is stacked on top of the main container it should not cause the
        // destruction of the primary one.
        return !mPresenter.shouldShowSideBySide(splitContainer);
    }

    /**
     * @see #shouldRetainAssociatedContainer(TaskFragmentContainer, TaskFragmentContainer)
     */
    boolean shouldRetainAssociatedActivity(@NonNull TaskFragmentContainer finishingContainer,
            @NonNull Activity associatedActivity) {
        TaskFragmentContainer associatedContainer = getContainerWithActivity(
                associatedActivity.getActivityToken());
        if (associatedContainer == null) {
            return false;
        }

        return shouldRetainAssociatedContainer(finishingContainer, associatedContainer);
    }

    private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {

        @Override
+6 −0
Original line number Diff line number Diff line
@@ -228,6 +228,9 @@ class TaskFragmentContainer {

        // Finish dependent containers
        for (TaskFragmentContainer container : mContainersToFinishOnExit) {
            if (controller.shouldRetainAssociatedContainer(this, container)) {
                continue;
            }
            container.finish(true /* shouldFinishDependent */, presenter,
                    wct, controller);
        }
@@ -235,6 +238,9 @@ class TaskFragmentContainer {

        // Finish associated activities
        for (Activity activity : mActivitiesToFinishOnExit) {
            if (controller.shouldRetainAssociatedActivity(this, activity)) {
                continue;
            }
            activity.finish();
        }
        mActivitiesToFinishOnExit.clear();