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

Commit 13402046 authored by Charles Chen's avatar Charles Chen Committed by Automerger Merge Worker
Browse files

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

parents e05f86e5 eb86759e
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