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

Commit eb86759e authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Respect minimum dimensions for embedded Activities" into tm-dev

parents d10c6d8a fa3f9ca9
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -8260,6 +8260,11 @@ public class Activity extends ContextThemeWrapper
        return mMainThread;
    }

    /** @hide */
    public final ActivityInfo getActivityInfo() {
        return mActivityInfo;
    }

    final void performCreate(Bundle icicle) {
        performCreate(icicle, null);
    }
+42 −6
Original line number Diff line number Diff line
@@ -23,8 +23,10 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,7 +68,7 @@ public final class TaskFragmentInfo implements Parcelable {
    private final List<IBinder> mActivities = new ArrayList<>();

    /** Relative position of the fragment's top left corner in the parent container. */
    private final Point mPositionInParent;
    private final Point mPositionInParent = new Point();

    /**
     * Whether the last running activity in the TaskFragment was finished due to clearing task while
@@ -80,21 +82,31 @@ public final class TaskFragmentInfo implements Parcelable {
     */
    private final boolean mIsTaskFragmentClearedForPip;

    /**
     * The maximum {@link ActivityInfo.WindowLayout#minWidth} and
     * {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child
     * activities.
     */
    @NonNull
    private final Point mMinimumDimensions = new Point();

    /** @hide */
    public TaskFragmentInfo(
            @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
            @NonNull Configuration configuration, int runningActivityCount,
            boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip) {
            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
            @NonNull Point minimumDimensions) {
        mFragmentToken = requireNonNull(fragmentToken);
        mToken = requireNonNull(token);
        mConfiguration.setTo(configuration);
        mRunningActivityCount = runningActivityCount;
        mIsVisible = isVisible;
        mActivities.addAll(activities);
        mPositionInParent = requireNonNull(positionInParent);
        mPositionInParent.set(positionInParent);
        mIsTaskClearedForReuse = isTaskClearedForReuse;
        mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
        mMinimumDimensions.set(minimumDimensions);
    }

    @NonNull
@@ -153,6 +165,26 @@ public final class TaskFragmentInfo implements Parcelable {
        return mConfiguration.windowConfiguration.getWindowingMode();
    }

    /**
     * Returns the minimum width this TaskFragment can be resized to.
     * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
     * that {@link Rect#width()} is shorter than the reported value.
     * @hide pending unhide
     */
    public int getMinimumWidth() {
        return mMinimumDimensions.x;
    }

    /**
     * Returns the minimum width this TaskFragment can be resized to.
     * Client side must not {@link WindowContainerTransaction#setBounds(WindowContainerToken, Rect)}
     * that {@link Rect#height()} is shorter than the reported value.
     * @hide pending unhide
     */
    public int getMinimumHeight() {
        return mMinimumDimensions.y;
    }

    /**
     * Returns {@code true} if the parameters that are important for task fragment organizers are
     * equal between this {@link TaskFragmentInfo} and {@param that}.
@@ -170,7 +202,8 @@ public final class TaskFragmentInfo implements Parcelable {
                && mActivities.equals(that.mActivities)
                && mPositionInParent.equals(that.mPositionInParent)
                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip;
                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
                && mMinimumDimensions.equals(that.mMinimumDimensions);
    }

    private TaskFragmentInfo(Parcel in) {
@@ -180,9 +213,10 @@ public final class TaskFragmentInfo implements Parcelable {
        mRunningActivityCount = in.readInt();
        mIsVisible = in.readBoolean();
        in.readBinderList(mActivities);
        mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
        mPositionInParent.readFromParcel(in);
        mIsTaskClearedForReuse = in.readBoolean();
        mIsTaskFragmentClearedForPip = in.readBoolean();
        mMinimumDimensions.readFromParcel(in);
    }

    /** @hide */
@@ -194,9 +228,10 @@ public final class TaskFragmentInfo implements Parcelable {
        dest.writeInt(mRunningActivityCount);
        dest.writeBoolean(mIsVisible);
        dest.writeBinderList(mActivities);
        dest.writeTypedObject(mPositionInParent, flags);
        mPositionInParent.writeToParcel(dest, flags);
        dest.writeBoolean(mIsTaskClearedForReuse);
        dest.writeBoolean(mIsTaskFragmentClearedForPip);
        mMinimumDimensions.writeToParcel(dest, flags);
    }

    @NonNull
@@ -224,6 +259,7 @@ public final class TaskFragmentInfo implements Parcelable {
                + " positionInParent=" + mPositionInParent
                + " isTaskClearedForReuse=" + mIsTaskClearedForReuse
                + " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip
                + " minimumDimensions" + mMinimumDimensions
                + "}";
    }

+10 −2
Original line number Diff line number Diff line
@@ -36,8 +36,7 @@ public class Point implements Parcelable {
    }

    public Point(@NonNull Point src) {
        this.x = src.x;
        this.y = src.y;
        set(src);
    }

    /**
@@ -48,6 +47,15 @@ public class Point implements Parcelable {
        this.y = y;
    }

    /**
     * Sets the point's from {@code src}'s coordinates
     * @hide
     */
    public void set(@NonNull Point src) {
        this.x = src.x;
        this.y = src.y;
    }

    /**
     * Negate the point's coordinates
     */
+9 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;

import android.annotation.NonNull;
import android.app.Activity;
import android.util.Pair;
import android.util.Size;

/**
 * Client-side descriptor of a split that holds two containers.
@@ -66,6 +68,13 @@ class SplitContainer {
        return mSplitRule;
    }

    /** Returns the minimum dimension pair of primary container and secondary container. */
    @NonNull
    Pair<Size, Size> getMinDimensionsPair() {
        return new Pair<>(mPrimaryContainer.getMinDimensions(),
                mSecondaryContainer.getMinDimensions());
    }

    boolean isPlaceholderContainer() {
        return (mSplitRule instanceof SplitPlaceholderRule);
    }
+30 −10
Original line number Diff line number Diff line
@@ -24,9 +24,11 @@ import static androidx.window.extensions.embedding.SplitContainer.getFinishSecon
import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
import static androidx.window.extensions.embedding.SplitPresenter.boundsSmallerThanMinDimensions;
import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityOptions;
@@ -43,11 +45,15 @@ import android.os.IBinder;
import android.os.Looper;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;

import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;

import com.android.internal.annotations.VisibleForTesting;
@@ -63,7 +69,7 @@ import java.util.function.Consumer;
 */
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
        ActivityEmbeddingComponent {
    private static final String TAG = "SplitController";
    static final String TAG = "SplitController";

    @VisibleForTesting
    @GuardedBy("mLock")
@@ -350,7 +356,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            if (!(rule instanceof SplitRule)) {
                continue;
            }
            if (mPresenter.shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
            if (shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
                return true;
            }
        }
@@ -614,12 +620,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            // Can launch in the existing secondary container if the rules share the same
            // presentation.
            final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
            if (secondaryContainer == getContainerWithActivity(secondaryActivity)) {
            if (secondaryContainer == getContainerWithActivity(secondaryActivity)
                    && !boundsSmallerThanMinDimensions(secondaryContainer.getLastRequestedBounds(),
                            getMinDimensions(secondaryActivity))) {
                // The activity is already in the target TaskFragment.
                return true;
            }
            secondaryContainer.addPendingAppearedActivity(secondaryActivity);
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
                    secondaryActivity, null /* secondaryIntent */);
            wct.reparentActivityToTaskFragment(
                    secondaryContainer.getTaskFragmentToken(),
                    secondaryActivity.getActivityToken());
@@ -791,6 +801,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                && (canReuseContainer(splitRule, splitContainer.getSplitRule())
                // TODO(b/231845476) we should always respect clearTop.
                || !respectClearTop)) {
            mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
                    null /* secondaryActivity */, intent);
            // Can launch in the existing secondary container if the rules share the same
            // presentation.
            return splitContainer.getSecondaryContainer();
@@ -1117,8 +1129,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen

        // Check if there is enough space for launch
        final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
        if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
                mPresenter.getParentContainerBounds(activity), placeholderRule)) {

        if (placeholderRule == null) {
            return false;
        }

        final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(activity,
                placeholderRule.getPlaceholderIntent());
        if (!shouldShowSideBySide(
                mPresenter.getParentContainerBounds(activity), placeholderRule,
                minDimensionsPair)) {
            return false;
        }

@@ -1161,7 +1181,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return false;
        }

        if (mPresenter.shouldShowSideBySide(splitContainer)) {
        if (shouldShowSideBySide(splitContainer)) {
            return false;
        }

@@ -1233,7 +1253,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                        // Splits that are not showing side-by-side are reported as having 0 split
                        // ratio, since by definition in the API the primary container occupies no
                        // width of the split when covered by the secondary.
                        mPresenter.shouldShowSideBySide(container)
                        shouldShowSideBySide(container)
                                ? container.getSplitRule().getSplitRatio()
                                : 0.0f);
                splitStates.add(splitState);
@@ -1402,7 +1422,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        }
        // Decide whether the associated container should be retained based on the current
        // presentation mode.
        if (mPresenter.shouldShowSideBySide(splitContainer)) {
        if (shouldShowSideBySide(splitContainer)) {
            return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
        } else {
            return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
Loading