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 Original line Diff line number Diff line
@@ -8260,6 +8260,11 @@ public class Activity extends ContextThemeWrapper
        return mMainThread;
        return mMainThread;
    }
    }


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

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


    /** Relative position of the fragment's top left corner in the parent container. */
    /** 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
     * 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;
    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 */
    /** @hide */
    public TaskFragmentInfo(
    public TaskFragmentInfo(
            @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
            @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
            @NonNull Configuration configuration, int runningActivityCount,
            @NonNull Configuration configuration, int runningActivityCount,
            boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
            boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip) {
            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
            @NonNull Point minimumDimensions) {
        mFragmentToken = requireNonNull(fragmentToken);
        mFragmentToken = requireNonNull(fragmentToken);
        mToken = requireNonNull(token);
        mToken = requireNonNull(token);
        mConfiguration.setTo(configuration);
        mConfiguration.setTo(configuration);
        mRunningActivityCount = runningActivityCount;
        mRunningActivityCount = runningActivityCount;
        mIsVisible = isVisible;
        mIsVisible = isVisible;
        mActivities.addAll(activities);
        mActivities.addAll(activities);
        mPositionInParent = requireNonNull(positionInParent);
        mPositionInParent.set(positionInParent);
        mIsTaskClearedForReuse = isTaskClearedForReuse;
        mIsTaskClearedForReuse = isTaskClearedForReuse;
        mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
        mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
        mMinimumDimensions.set(minimumDimensions);
    }
    }


    @NonNull
    @NonNull
@@ -153,6 +165,26 @@ public final class TaskFragmentInfo implements Parcelable {
        return mConfiguration.windowConfiguration.getWindowingMode();
        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
     * Returns {@code true} if the parameters that are important for task fragment organizers are
     * equal between this {@link TaskFragmentInfo} and {@param that}.
     * equal between this {@link TaskFragmentInfo} and {@param that}.
@@ -170,7 +202,8 @@ public final class TaskFragmentInfo implements Parcelable {
                && mActivities.equals(that.mActivities)
                && mActivities.equals(that.mActivities)
                && mPositionInParent.equals(that.mPositionInParent)
                && mPositionInParent.equals(that.mPositionInParent)
                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip;
                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
                && mMinimumDimensions.equals(that.mMinimumDimensions);
    }
    }


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


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


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


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


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


    /**
    /**
@@ -48,6 +47,15 @@ public class Point implements Parcelable {
        this.y = y;
        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
     * Negate the point's coordinates
     */
     */
+9 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@ package androidx.window.extensions.embedding;


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


/**
/**
 * Client-side descriptor of a split that holds two containers.
 * Client-side descriptor of a split that holds two containers.
@@ -66,6 +68,13 @@ class SplitContainer {
        return mSplitRule;
        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() {
    boolean isPlaceholderContainer() {
        return (mSplitRule instanceof SplitPlaceholderRule);
        return (mSplitRule instanceof SplitPlaceholderRule);
    }
    }
+30 −10
Original line number Original line 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.isStickyPlaceholderRule;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
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.Activity;
import android.app.ActivityClient;
import android.app.ActivityClient;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
@@ -43,11 +45,15 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
import android.util.SparseArray;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;


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


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


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


        // Check if there is enough space for launch
        // Check if there is enough space for launch
        final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
        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;
            return false;
        }
        }


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


        if (mPresenter.shouldShowSideBySide(splitContainer)) {
        if (shouldShowSideBySide(splitContainer)) {
            return false;
            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
                        // 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
                        // ratio, since by definition in the API the primary container occupies no
                        // width of the split when covered by the secondary.
                        // width of the split when covered by the secondary.
                        mPresenter.shouldShowSideBySide(container)
                        shouldShowSideBySide(container)
                                ? container.getSplitRule().getSplitRatio()
                                ? container.getSplitRule().getSplitRatio()
                                : 0.0f);
                                : 0.0f);
                splitStates.add(splitState);
                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
        // Decide whether the associated container should be retained based on the current
        // presentation mode.
        // presentation mode.
        if (mPresenter.shouldShowSideBySide(splitContainer)) {
        if (shouldShowSideBySide(splitContainer)) {
            return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
            return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
        } else {
        } else {
            return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
            return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
Loading