Loading libs/WindowManager/Shell/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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> Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +18 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -52,11 +53,11 @@ import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import java.util.Optional; import dagger.Module; import dagger.Provides; import java.util.Optional; /** * Provides TV specific dependencies for Pip. */ Loading @@ -69,6 +70,7 @@ public abstract class TvPipModule { ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, PipAppOpsListener pipAppOpsListener, Loading @@ -89,6 +91,7 @@ public abstract class TvPipModule { shellInit, shellController, tvPipBoundsState, pipSizeSpecHandler, tvPipBoundsAlgorithm, tvPipBoundsController, pipAppOpsListener, Loading Loading @@ -129,14 +132,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, PipSizeSpecHandler pipSizeSpecHandler) { return new TvPipBoundsState(context, pipSizeSpecHandler); } @WMSingleton @Provides static TvPipBoundsState provideTvPipBoundsState(Context context) { return new TvPipBoundsState(context); static PipSizeSpecHandler providePipSizeSpecHelper(Context context) { return new PipSizeSpecHandler(context); } // Handler needed for loadDrawableAsync() in PipControlsViewController Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +25 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -98,15 +99,15 @@ import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel; import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel; import com.android.wm.shell.windowdecor.WindowDecorViewModel; import java.util.ArrayList; import java.util.List; import java.util.Optional; import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; import java.util.ArrayList; import java.util.List; import java.util.Optional; /** * Provides dependencies from {@link com.android.wm.shell}, these dependencies are only * accessible from components within the WM subcomponent (can be explicitly exposed to the Loading Loading @@ -338,6 +339,7 @@ public abstract class WMShellModule { PipBoundsAlgorithm pipBoundsAlgorithm, PhonePipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, Loading @@ -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 Loading @@ -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 Loading @@ -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); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +18 −138 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } /** Loading @@ -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; } /** Loading Loading @@ -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; } Loading Loading @@ -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); Loading @@ -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. Loading @@ -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. Loading @@ -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()); } /** Loading Loading @@ -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); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +8 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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(); } Loading @@ -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. */ Loading Loading @@ -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 Loading
libs/WindowManager/Shell/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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> Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +18 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -52,11 +53,11 @@ import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import java.util.Optional; import dagger.Module; import dagger.Provides; import java.util.Optional; /** * Provides TV specific dependencies for Pip. */ Loading @@ -69,6 +70,7 @@ public abstract class TvPipModule { ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, PipAppOpsListener pipAppOpsListener, Loading @@ -89,6 +91,7 @@ public abstract class TvPipModule { shellInit, shellController, tvPipBoundsState, pipSizeSpecHandler, tvPipBoundsAlgorithm, tvPipBoundsController, pipAppOpsListener, Loading Loading @@ -129,14 +132,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, PipSizeSpecHandler pipSizeSpecHandler) { return new TvPipBoundsState(context, pipSizeSpecHandler); } @WMSingleton @Provides static TvPipBoundsState provideTvPipBoundsState(Context context) { return new TvPipBoundsState(context); static PipSizeSpecHandler providePipSizeSpecHelper(Context context) { return new PipSizeSpecHandler(context); } // Handler needed for loadDrawableAsync() in PipControlsViewController Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +25 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -98,15 +99,15 @@ import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel; import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel; import com.android.wm.shell.windowdecor.WindowDecorViewModel; import java.util.ArrayList; import java.util.List; import java.util.Optional; import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; import java.util.ArrayList; import java.util.List; import java.util.Optional; /** * Provides dependencies from {@link com.android.wm.shell}, these dependencies are only * accessible from components within the WM subcomponent (can be explicitly exposed to the Loading Loading @@ -338,6 +339,7 @@ public abstract class WMShellModule { PipBoundsAlgorithm pipBoundsAlgorithm, PhonePipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, Loading @@ -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 Loading @@ -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 Loading @@ -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); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +18 −138 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } /** Loading @@ -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; } /** Loading Loading @@ -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; } Loading Loading @@ -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); Loading @@ -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. Loading @@ -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. Loading @@ -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()); } /** Loading Loading @@ -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); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +8 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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(); } Loading @@ -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. */ Loading Loading @@ -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