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

Commit 3ef8a24a authored by Ikram Gabiyev's avatar Ikram Gabiyev Committed by Android (Google) Code Review
Browse files

Merge changes from topic "new-size-spec" into tm-qpr-dev

* changes:
  Fix getOverrideMinSize to not go beyond min bounds
  Update the pip size spec logic
parents fee1295f 9bd7f625
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@
        1.777778
    </item>

    <!-- The aspect ratio that by which optimizations to large screen sizes are made.
         Needs to be less that or equal to 1. -->
    <item name="config_pipLargeScreenOptimizedAspectRatio" format="float" type="dimen">0.5625</item>

    <!-- The default gravity for the picture-in-picture window.
         Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
    <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+16 −4
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
@@ -69,6 +70,7 @@ public abstract class TvPipModule {
            ShellInit shellInit,
            ShellController shellController,
            TvPipBoundsState tvPipBoundsState,
            PipSizeSpecHandler pipSizeSpecHandler,
            TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
            TvPipBoundsController tvPipBoundsController,
            PipAppOpsListener pipAppOpsListener,
@@ -88,6 +90,7 @@ public abstract class TvPipModule {
                        shellInit,
                        shellController,
                        tvPipBoundsState,
                        pipSizeSpecHandler,
                        tvPipBoundsAlgorithm,
                        tvPipBoundsController,
                        pipAppOpsListener,
@@ -127,14 +130,23 @@ public abstract class TvPipModule {
    @WMSingleton
    @Provides
    static TvPipBoundsAlgorithm provideTvPipBoundsAlgorithm(Context context,
            TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
        return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm);
            TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
            PipSizeSpecHandler pipSizeSpecHandler) {
        return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm,
                pipSizeSpecHandler);
    }

    @WMSingleton
    @Provides
    static TvPipBoundsState provideTvPipBoundsState(Context context) {
        return new TvPipBoundsState(context);
    static TvPipBoundsState provideTvPipBoundsState(Context context,
            PipSizeSpecHandler pipSizeSpecHandler) {
        return new TvPipBoundsState(context, pipSizeSpecHandler);
    }

    @WMSingleton
    @Provides
    static PipSizeSpecHandler providePipSizeSpecHelper(Context context) {
        return new PipSizeSpecHandler(context);
    }

    // Handler needed for loadDrawableAsync() in PipControlsViewController
+21 −10
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -338,6 +339,7 @@ public abstract class WMShellModule {
            PipBoundsAlgorithm pipBoundsAlgorithm,
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
            PipBoundsState pipBoundsState,
            PipSizeSpecHandler pipSizeSpecHandler,
            PipMotionHelper pipMotionHelper,
            PipMediaController pipMediaController,
            PhonePipMenuController phonePipMenuController,
@@ -354,17 +356,18 @@ public abstract class WMShellModule {
        return Optional.ofNullable(PipController.create(
                context, shellInit, shellCommandHandler, shellController,
                displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm,
                pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
                phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler,
                pipTransitionController, windowManagerShellWrapper, taskStackListener,
                pipParamsChangedForwarder, displayInsetsController, oneHandedController,
                mainExecutor));
                pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, pipMotionHelper,
                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
                taskStackListener, pipParamsChangedForwarder, displayInsetsController,
                oneHandedController, mainExecutor));
    }

    @WMSingleton
    @Provides
    static PipBoundsState providePipBoundsState(Context context) {
        return new PipBoundsState(context);
    static PipBoundsState providePipBoundsState(Context context,
            PipSizeSpecHandler pipSizeSpecHandler) {
        return new PipBoundsState(context, pipSizeSpecHandler);
    }

    @WMSingleton
@@ -379,13 +382,20 @@ public abstract class WMShellModule {
        return new PhonePipKeepClearAlgorithm(context);
    }

    @WMSingleton
    @Provides
    static PipSizeSpecHandler providePipSizeSpecHelper(Context context) {
        return new PipSizeSpecHandler(context);
    }

    @WMSingleton
    @Provides
    static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
            PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm) {
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
            PipSizeSpecHandler pipSizeSpecHandler) {
        return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
                pipKeepClearAlgorithm);
                pipKeepClearAlgorithm, pipSizeSpecHandler);
    }

    // Handler is used by Icon.loadDrawableAsync
@@ -409,13 +419,14 @@ public abstract class WMShellModule {
            PhonePipMenuController menuPhoneController,
            PipBoundsAlgorithm pipBoundsAlgorithm,
            PipBoundsState pipBoundsState,
            PipSizeSpecHandler pipSizeSpecHandler,
            PipTaskOrganizer pipTaskOrganizer,
            PipMotionHelper pipMotionHelper,
            FloatingContentCoordinator floatingContentCoordinator,
            PipUiEventLogger pipUiEventLogger,
            @ShellMainThread ShellExecutor mainExecutor) {
        return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
                pipBoundsState, pipTaskOrganizer, pipMotionHelper,
                pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
                floatingContentCoordinator, pipUiEventLogger, mainExecutor);
    }

+18 −138
Original line number Diff line number Diff line
@@ -16,24 +16,19 @@

package com.android.wm.shell.pip;

import static android.util.TypedValue.COMPLEX_UNIT_DIP;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.TypedValue;
import android.view.Gravity;

import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;

import java.io.PrintWriter;

@@ -45,33 +40,29 @@ public class PipBoundsAlgorithm {
    private static final String TAG = PipBoundsAlgorithm.class.getSimpleName();
    private static final float INVALID_SNAP_FRACTION = -1f;

    private final @NonNull PipBoundsState mPipBoundsState;
    @NonNull private final PipBoundsState mPipBoundsState;
    @NonNull protected final PipSizeSpecHandler mPipSizeSpecHandler;
    private final PipSnapAlgorithm mSnapAlgorithm;
    private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;

    private float mDefaultSizePercent;
    private float mMinAspectRatioForMinSize;
    private float mMaxAspectRatioForMinSize;
    private float mDefaultAspectRatio;
    private float mMinAspectRatio;
    private float mMaxAspectRatio;
    private int mDefaultStackGravity;
    private int mDefaultMinSize;
    private int mOverridableMinSize;
    protected Point mScreenEdgeInsets;

    public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
            @NonNull PipSnapAlgorithm pipSnapAlgorithm,
            @NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm) {
            @NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
            @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
        mPipBoundsState = pipBoundsState;
        mSnapAlgorithm = pipSnapAlgorithm;
        mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
        mPipSizeSpecHandler = pipSizeSpecHandler;
        reloadResources(context);
        // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
        // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
        // triggers a configuration change and the resources to be reloaded.
        mPipBoundsState.setAspectRatio(mDefaultAspectRatio);
        mPipBoundsState.setMinEdgeSize(mDefaultMinSize);
    }

    /**
@@ -83,27 +74,15 @@ public class PipBoundsAlgorithm {
                R.dimen.config_pictureInPictureDefaultAspectRatio);
        mDefaultStackGravity = res.getInteger(
                R.integer.config_defaultPictureInPictureGravity);
        mDefaultMinSize = res.getDimensionPixelSize(
                R.dimen.default_minimal_size_pip_resizable_task);
        mOverridableMinSize = res.getDimensionPixelSize(
                R.dimen.overridable_minimal_size_pip_resizable_task);
        final String screenEdgeInsetsDpString = res.getString(
                R.string.config_defaultPictureInPictureScreenEdgeInsets);
        final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
                ? Size.parseSize(screenEdgeInsetsDpString)
                : null;
        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
                        dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
        mMinAspectRatio = res.getFloat(
                com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
        mMaxAspectRatio = res.getFloat(
                com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
        mDefaultSizePercent = res.getFloat(
                R.dimen.config_pictureInPictureDefaultSizePercent);
        mMaxAspectRatioForMinSize = res.getFloat(
                R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
        mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
    }

    /**
@@ -180,8 +159,9 @@ public class PipBoundsAlgorithm {
        if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
            // If either dimension is smaller than the allowed minimum, adjust them
            // according to mOverridableMinSize
            return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize),
                    Math.max(windowLayout.minHeight, mOverridableMinSize));
            return new Size(
                    Math.max(windowLayout.minWidth, mPipSizeSpecHandler.getOverrideMinEdgeSize()),
                    Math.max(windowLayout.minHeight, mPipSizeSpecHandler.getOverrideMinEdgeSize()));
        }
        return null;
    }
@@ -243,28 +223,13 @@ public class PipBoundsAlgorithm {
        final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                getMovementBounds(stackBounds), mPipBoundsState.getStashedState());

        final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
        final Size size;
        if (useCurrentMinEdgeSize || useCurrentSize) {
            // The default minimum edge size, or the override min edge size if set.
            final int defaultMinEdgeSize = overrideMinSize == null ? mDefaultMinSize
                    : mPipBoundsState.getOverrideMinEdgeSize();
            final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize()
                    : defaultMinEdgeSize;
            // Use the existing size but adjusted to the aspect ratio and min edge size.
            size = getSizeForAspectRatio(
                    new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
        } else {
            if (overrideMinSize != null) {
                // The override minimal size is set, use that as the default size making sure it's
                // adjusted to the aspect ratio.
                size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio);
            // Use the existing size but adjusted to the new aspect ratio.
            size = mPipSizeSpecHandler.getSizeForAspectRatio(
                    new Size(stackBounds.width(), stackBounds.height()), aspectRatio);
        } else {
                // Calculate the default size using the display size and default min edge size.
                final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
                size = getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
                        displayLayout.width(), displayLayout.height());
            }
            size = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
        }

        final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
@@ -273,18 +238,6 @@ public class PipBoundsAlgorithm {
        mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
    }

    /** Adjusts the given size to conform to the given aspect ratio. */
    private Size adjustSizeToAspectRatio(@NonNull Size size, float aspectRatio) {
        final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
        if (sizeAspectRatio > aspectRatio) {
            // Size is wider, fix the width and increase the height
            return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
        } else {
            // Size is taller, fix the height and adjust the width.
            return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
        }
    }

    /**
     * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
     * provided, then it will apply the default bounds to the provided snap fraction and size.
@@ -303,17 +256,9 @@ public class PipBoundsAlgorithm {
        final Size defaultSize;
        final Rect insetBounds = new Rect();
        getInsetBounds(insetBounds);
        final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
        final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
        if (overrideMinSize != null) {
            // The override minimal size is set, use that as the default size making sure it's
            // adjusted to the aspect ratio.
            defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio);
        } else {
            // Calculate the default size using the display size and default min edge size.
            defaultSize = getSizeForAspectRatio(mDefaultAspectRatio,
                    mDefaultMinSize, displayLayout.width(), displayLayout.height());
        }

        // Calculate the default size
        defaultSize = mPipSizeSpecHandler.getDefaultSize(mDefaultAspectRatio);

        // Now that we have the default size, apply the snap fraction if valid or position the
        // bounds using the default gravity.
@@ -335,12 +280,7 @@ public class PipBoundsAlgorithm {
     * Populates the bounds on the screen that the PIP can be visible in.
     */
    public void getInsetBounds(Rect outRect) {
        final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
        Rect insets = mPipBoundsState.getDisplayLayout().stableInsets();
        outRect.set(insets.left + mScreenEdgeInsets.x,
                insets.top + mScreenEdgeInsets.y,
                displayLayout.width() - insets.right - mScreenEdgeInsets.x,
                displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
        outRect.set(mPipSizeSpecHandler.getInsetBounds());
    }

    /**
@@ -405,71 +345,11 @@ public class PipBoundsAlgorithm {
        mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
    }

    public int getDefaultMinSize() {
        return mDefaultMinSize;
    }

    /**
     * @return the pixels for a given dp value.
     */
    private int dpToPx(float dpValue, DisplayMetrics dm) {
        return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
    }

    /**
     * @return the size of the PiP at the given aspectRatio, ensuring that the minimum edge
     * is at least minEdgeSize.
     */
    public Size getSizeForAspectRatio(float aspectRatio, float minEdgeSize, int displayWidth,
            int displayHeight) {
        final int smallestDisplaySize = Math.min(displayWidth, displayHeight);
        final int minSize = (int) Math.max(minEdgeSize, smallestDisplaySize * mDefaultSizePercent);

        final int width;
        final int height;
        if (aspectRatio <= mMinAspectRatioForMinSize || aspectRatio > mMaxAspectRatioForMinSize) {
            // Beyond these points, we can just use the min size as the shorter edge
            if (aspectRatio <= 1) {
                // Portrait, width is the minimum size
                width = minSize;
                height = Math.round(width / aspectRatio);
            } else {
                // Landscape, height is the minimum size
                height = minSize;
                width = Math.round(height * aspectRatio);
            }
        } else {
            // Within these points, we ensure that the bounds fit within the radius of the limits
            // at the points
            final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
            final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
            height = (int) Math.round(Math.sqrt((radius * radius)
                    / (aspectRatio * aspectRatio + 1)));
            width = Math.round(height * aspectRatio);
        }
        return new Size(width, height);
    }

    /**
     * @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
     * minimum edge is at least minEdgeSize.
     */
    public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
        final int smallestSize = Math.min(size.getWidth(), size.getHeight());
        final int minSize = (int) Math.max(minEdgeSize, smallestSize);

        final int width;
        final int height;
        if (aspectRatio <= 1) {
            // Portrait, width is the minimum size.
            width = minSize;
            height = Math.round(width / aspectRatio);
        } else {
            // Landscape, height is the minimum size
            height = minSize;
            width = Math.round(height * aspectRatio);
        }
        return new Size(width, height);
        return PipUtils.dpToPx(dpValue, dm);
    }

    /**
+8 −23
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;

import java.io.PrintWriter;
@@ -83,13 +84,10 @@ public class PipBoundsState {
    private int mStashedState = STASH_TYPE_NONE;
    private int mStashOffset;
    private @Nullable PipReentryState mPipReentryState;
    private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler;
    private @Nullable ComponentName mLastPipComponentName;
    private int mDisplayId = Display.DEFAULT_DISPLAY;
    private final @NonNull DisplayLayout mDisplayLayout = new DisplayLayout();
    /** The current minimum edge size of PIP. */
    private int mMinEdgeSize;
    /** The preferred minimum (and default) size specified by apps. */
    private @Nullable Size mOverrideMinSize;
    private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState();
    private boolean mIsImeShowing;
    private int mImeHeight;
@@ -122,9 +120,10 @@ public class PipBoundsState {
    private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
    private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>();

    public PipBoundsState(@NonNull Context context) {
    public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler) {
        mContext = context;
        reloadResources();
        mPipSizeSpecHandler = pipSizeSpecHandler;
    }

    /** Reloads the resources. */
@@ -323,20 +322,10 @@ public class PipBoundsState {
        mPipReentryState = null;
    }

    /** Set the PIP minimum edge size. */
    public void setMinEdgeSize(int minEdgeSize) {
        mMinEdgeSize = minEdgeSize;
    }

    /** Returns the PIP's current minimum edge size. */
    public int getMinEdgeSize() {
        return mMinEdgeSize;
    }

    /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
    public void setOverrideMinSize(@Nullable Size overrideMinSize) {
        final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize);
        mOverrideMinSize = overrideMinSize;
        final boolean changed = !Objects.equals(overrideMinSize, getOverrideMinSize());
        mPipSizeSpecHandler.setOverrideMinSize(overrideMinSize);
        if (changed && mOnMinimalSizeChangeCallback != null) {
            mOnMinimalSizeChangeCallback.run();
        }
@@ -345,13 +334,12 @@ public class PipBoundsState {
    /** Returns the preferred minimal size specified by the activity in PIP. */
    @Nullable
    public Size getOverrideMinSize() {
        return mOverrideMinSize;
        return mPipSizeSpecHandler.getOverrideMinSize();
    }

    /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
    public int getOverrideMinEdgeSize() {
        if (mOverrideMinSize == null) return 0;
        return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight());
        return mPipSizeSpecHandler.getOverrideMinEdgeSize();
    }

    /** Get the state of the bounds in motion. */
@@ -581,11 +569,8 @@ public class PipBoundsState {
        pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
        pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
        pw.println(innerPrefix + "mDisplayId=" + mDisplayId);
        pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
        pw.println(innerPrefix + "mStashedState=" + mStashedState);
        pw.println(innerPrefix + "mStashOffset=" + mStashOffset);
        pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize);
        pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
        pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
        pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
        pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
Loading