Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +20 −0 Original line number Diff line number Diff line Loading @@ -126,12 +126,22 @@ public class PipBoundsState { private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); // the size of the current bounds relative to the max size spec private float mBoundsScale; public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource, @NonNull PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; reloadResources(); mSizeSpecSource = sizeSpecSource; mPipDisplayLayoutState = pipDisplayLayoutState; // Update the relative proportion of the bounds compared to max possible size. Max size // spec takes the aspect ratio of the bounds into account, so both width and height // scale by the same factor. addPipExclusionBoundsChangeCallback((bounds) -> { mBoundsScale = Math.min((float) bounds.width() / mMaxSize.x, 1.0f); }); } /** Reloads the resources. */ Loading Loading @@ -160,6 +170,15 @@ public class PipBoundsState { return new Rect(mBounds); } /** * Get the scale of the current bounds relative to the maximum size possible. * * @return 1.0 if {@link PipBoundsState#getBounds()} equals {@link PipBoundsState#getMaxSize()}. */ public float getBoundsScale() { return mBoundsScale; } /** Returns the current movement bounds. */ @NonNull public Rect getMovementBounds() { Loading Loading @@ -624,6 +643,7 @@ public class PipBoundsState { pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip); pw.println(innerPrefix + "mMinSize=" + mMinSize); pw.println(innerPrefix + "mMaxSize=" + mMaxSize); pw.println(innerPrefix + "mBoundsScale" + mBoundsScale); if (mPipReentryState == null) { pw.println(innerPrefix + "mPipReentryState=null"); } else { Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +16 −22 Original line number Diff line number Diff line Loading @@ -797,21 +797,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsAlgorithm.getMovementBounds(postChangeBounds), mPipBoundsState.getStashedState()); // Scale PiP on density dpi change, so it appears to be the same size physically. final boolean densityDpiChanged = mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0 && (mPipDisplayLayoutState.getDisplayLayout().densityDpi() != layout.densityDpi()); if (densityDpiChanged) { final float scale = (float) layout.densityDpi() / mPipDisplayLayoutState.getDisplayLayout().densityDpi(); postChangeBounds.set(0, 0, (int) (postChangeBounds.width() * scale), (int) (postChangeBounds.height() * scale)); } updateDisplayLayout.run(); // Resize the PiP bounds to be at the same scale relative to the new size spec. For // example, if PiP was resized to 90% of the maximum size on the previous layout, // make sure it is 90% of the new maximum size spec. postChangeBounds.set(0, 0, (int) (mPipBoundsState.getMaxSize().x * mPipBoundsState.getBoundsScale()), (int) (mPipBoundsState.getMaxSize().y * mPipBoundsState.getBoundsScale())); // Calculate the PiP bounds in the new orientation based on same fraction along the // rotated movement bounds. final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds( Loading @@ -822,6 +816,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipDisplayLayoutState.getDisplayBounds(), mPipDisplayLayoutState.getDisplayLayout().stableInsets()); // make sure we user resize to the updated bounds to avoid animating to any outdated // sizes from the previous layout upon double tap CUJ mPipBoundsState.setHasUserResizedPip(true); mTouchHandler.setUserResizeBounds(postChangeBounds); final boolean densityDpiChanged = mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0 && (mPipDisplayLayoutState.getDisplayLayout().densityDpi() != layout.densityDpi()); if (densityDpiChanged) { // Using PipMotionHelper#movePip directly here may cause race condition since // the app content in PiP mode may or may not be updated for the new density dpi. Loading @@ -833,15 +836,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Directly move PiP to its final destination bounds without animation. mPipTaskOrganizer.scheduleFinishResizePip(postChangeBounds); } // if the pip window size is beyond allowed bounds user resize to normal bounds if (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x || mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y) { mTouchHandler.userResizeTo(mPipBoundsState.getNormalBounds(), snapFraction); } } else { updateDisplayLayout.run(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +3 −6 Original line number Diff line number Diff line Loading @@ -779,13 +779,10 @@ public class PipTouchHandler { } /** * Resizes the pip window and updates user resized bounds * * @param bounds target bounds to resize to * @param snapFraction snap fraction to apply after resizing * Sets the user resize bounds tracked by {@link PipResizeGestureHandler} */ void userResizeTo(Rect bounds, float snapFraction) { mPipResizeGestureHandler.userResizeTo(bounds, snapFraction); void setUserResizeBounds(Rect bounds) { mPipResizeGestureHandler.setUserResizeBounds(bounds); } /** Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.graphics.Point; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -60,6 +61,9 @@ public class PipBoundsStateTest extends ShellTestCase { /** The minimum possible size of the override min size's width or height */ private static final int OVERRIDABLE_MIN_SIZE = 40; /** The margin of error for floating point results. */ private static final float MARGIN_OF_ERROR = 0.05f; private PipBoundsState mPipBoundsState; private SizeSpecSource mSizeSpecSource; private ComponentName mTestComponentName1; Loading Loading @@ -87,6 +91,27 @@ public class PipBoundsStateTest extends ShellTestCase { assertEquals(bounds, mPipBoundsState.getBounds()); } @Test public void testBoundsScale() { mPipBoundsState.setMaxSize(300, 300); mPipBoundsState.setBounds(new Rect(0, 0, 100, 100)); final int currentWidth = mPipBoundsState.getBounds().width(); final Point maxSize = mPipBoundsState.getMaxSize(); final float expectedBoundsScale = Math.min((float) currentWidth / maxSize.x, 1.0f); // test for currentWidth < maxWidth assertEquals(expectedBoundsScale, mPipBoundsState.getBoundsScale(), MARGIN_OF_ERROR); // reset the bounds to be at the maximum size spec mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x, maxSize.y)); assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f); // reset the bounds to be over the maximum size spec mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x * 2, maxSize.y * 2)); assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f); } @Test public void testSetReentryState() { final Size size = new Size(100, 100); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +20 −0 Original line number Diff line number Diff line Loading @@ -126,12 +126,22 @@ public class PipBoundsState { private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); // the size of the current bounds relative to the max size spec private float mBoundsScale; public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource, @NonNull PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; reloadResources(); mSizeSpecSource = sizeSpecSource; mPipDisplayLayoutState = pipDisplayLayoutState; // Update the relative proportion of the bounds compared to max possible size. Max size // spec takes the aspect ratio of the bounds into account, so both width and height // scale by the same factor. addPipExclusionBoundsChangeCallback((bounds) -> { mBoundsScale = Math.min((float) bounds.width() / mMaxSize.x, 1.0f); }); } /** Reloads the resources. */ Loading Loading @@ -160,6 +170,15 @@ public class PipBoundsState { return new Rect(mBounds); } /** * Get the scale of the current bounds relative to the maximum size possible. * * @return 1.0 if {@link PipBoundsState#getBounds()} equals {@link PipBoundsState#getMaxSize()}. */ public float getBoundsScale() { return mBoundsScale; } /** Returns the current movement bounds. */ @NonNull public Rect getMovementBounds() { Loading Loading @@ -624,6 +643,7 @@ public class PipBoundsState { pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip); pw.println(innerPrefix + "mMinSize=" + mMinSize); pw.println(innerPrefix + "mMaxSize=" + mMaxSize); pw.println(innerPrefix + "mBoundsScale" + mBoundsScale); if (mPipReentryState == null) { pw.println(innerPrefix + "mPipReentryState=null"); } else { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +16 −22 Original line number Diff line number Diff line Loading @@ -797,21 +797,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsAlgorithm.getMovementBounds(postChangeBounds), mPipBoundsState.getStashedState()); // Scale PiP on density dpi change, so it appears to be the same size physically. final boolean densityDpiChanged = mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0 && (mPipDisplayLayoutState.getDisplayLayout().densityDpi() != layout.densityDpi()); if (densityDpiChanged) { final float scale = (float) layout.densityDpi() / mPipDisplayLayoutState.getDisplayLayout().densityDpi(); postChangeBounds.set(0, 0, (int) (postChangeBounds.width() * scale), (int) (postChangeBounds.height() * scale)); } updateDisplayLayout.run(); // Resize the PiP bounds to be at the same scale relative to the new size spec. For // example, if PiP was resized to 90% of the maximum size on the previous layout, // make sure it is 90% of the new maximum size spec. postChangeBounds.set(0, 0, (int) (mPipBoundsState.getMaxSize().x * mPipBoundsState.getBoundsScale()), (int) (mPipBoundsState.getMaxSize().y * mPipBoundsState.getBoundsScale())); // Calculate the PiP bounds in the new orientation based on same fraction along the // rotated movement bounds. final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds( Loading @@ -822,6 +816,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipDisplayLayoutState.getDisplayBounds(), mPipDisplayLayoutState.getDisplayLayout().stableInsets()); // make sure we user resize to the updated bounds to avoid animating to any outdated // sizes from the previous layout upon double tap CUJ mPipBoundsState.setHasUserResizedPip(true); mTouchHandler.setUserResizeBounds(postChangeBounds); final boolean densityDpiChanged = mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0 && (mPipDisplayLayoutState.getDisplayLayout().densityDpi() != layout.densityDpi()); if (densityDpiChanged) { // Using PipMotionHelper#movePip directly here may cause race condition since // the app content in PiP mode may or may not be updated for the new density dpi. Loading @@ -833,15 +836,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Directly move PiP to its final destination bounds without animation. mPipTaskOrganizer.scheduleFinishResizePip(postChangeBounds); } // if the pip window size is beyond allowed bounds user resize to normal bounds if (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x || mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y) { mTouchHandler.userResizeTo(mPipBoundsState.getNormalBounds(), snapFraction); } } else { updateDisplayLayout.run(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +3 −6 Original line number Diff line number Diff line Loading @@ -779,13 +779,10 @@ public class PipTouchHandler { } /** * Resizes the pip window and updates user resized bounds * * @param bounds target bounds to resize to * @param snapFraction snap fraction to apply after resizing * Sets the user resize bounds tracked by {@link PipResizeGestureHandler} */ void userResizeTo(Rect bounds, float snapFraction) { mPipResizeGestureHandler.userResizeTo(bounds, snapFraction); void setUserResizeBounds(Rect bounds) { mPipResizeGestureHandler.setUserResizeBounds(bounds); } /** Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.graphics.Point; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading Loading @@ -60,6 +61,9 @@ public class PipBoundsStateTest extends ShellTestCase { /** The minimum possible size of the override min size's width or height */ private static final int OVERRIDABLE_MIN_SIZE = 40; /** The margin of error for floating point results. */ private static final float MARGIN_OF_ERROR = 0.05f; private PipBoundsState mPipBoundsState; private SizeSpecSource mSizeSpecSource; private ComponentName mTestComponentName1; Loading Loading @@ -87,6 +91,27 @@ public class PipBoundsStateTest extends ShellTestCase { assertEquals(bounds, mPipBoundsState.getBounds()); } @Test public void testBoundsScale() { mPipBoundsState.setMaxSize(300, 300); mPipBoundsState.setBounds(new Rect(0, 0, 100, 100)); final int currentWidth = mPipBoundsState.getBounds().width(); final Point maxSize = mPipBoundsState.getMaxSize(); final float expectedBoundsScale = Math.min((float) currentWidth / maxSize.x, 1.0f); // test for currentWidth < maxWidth assertEquals(expectedBoundsScale, mPipBoundsState.getBoundsScale(), MARGIN_OF_ERROR); // reset the bounds to be at the maximum size spec mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x, maxSize.y)); assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f); // reset the bounds to be over the maximum size spec mPipBoundsState.setBounds(new Rect(0, 0, maxSize.x * 2, maxSize.y * 2)); assertEquals(1.0f, mPipBoundsState.getBoundsScale(), /* delta */ 0f); } @Test public void testSetReentryState() { final Size size = new Size(100, 100); Loading