diff options
| author | 2020-12-08 10:11:57 -0800 | |
|---|---|---|
| committer | 2020-12-08 12:27:49 -0800 | |
| commit | 2c0e01b2407b3e7f808f4029e64b36f5287ae244 (patch) | |
| tree | efd942a95d9d10b41fccf1aeaa5ac4581f3b39a0 | |
| parent | 7344dac2f3be2cb6c5c89ce10d54b322db8b33fd (diff) | |
Don't save the default size as reentry state
Fixes issue where the "default" bounds of PIP can be calculated
differently even though the PIP has never been resized. This is
caused by a combination of changing the aspect ratio of PIP and
trying to restore the "reentry" state that is just the default
state.
Instead, we'll only calculate the PIP bounds using the reentry
size if the size was actually changed by the user, otherwise
we'll always calculate using the default size.
Bug: 169379707
Test: atest com.android.wm.shell.pip
Change-Id: I724b167870407f7f37eb9c8a587a98c7972441a4
7 files changed, 103 insertions, 47 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java index 1bb5eda25058..b01961413fea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java @@ -125,15 +125,16 @@ public class PipBoundsAlgorithm { /** Returns the destination bounds to place the PIP window on entry. */ public Rect getEntryDestinationBounds() { final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState(); - final boolean shouldRestoreReentryBounds = reentryState != null; - final Rect destinationBounds = shouldRestoreReentryBounds + final Rect destinationBounds = reentryState != null ? getDefaultBounds(reentryState.getSnapFraction(), reentryState.getSize()) : getDefaultBounds(); - return transformBoundsToAspectRatioIfValid(destinationBounds, + final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null; + final Rect r = transformBoundsToAspectRatioIfValid(destinationBounds, mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */, - shouldRestoreReentryBounds); + useCurrentSize); + return r; } /** Returns the current bounds adjusted to the new aspect ratio, if valid. */ @@ -223,24 +224,36 @@ public class PipBoundsAlgorithm { private Rect getDefaultBounds(float snapFraction, Size size) { final Rect defaultBounds = new Rect(); if (snapFraction != INVALID_SNAP_FRACTION && size != null) { + // The default bounds are the given size positioned at the given snap fraction. defaultBounds.set(0, 0, size.getWidth(), size.getHeight()); final Rect movementBounds = getMovementBounds(defaultBounds); mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction); + return defaultBounds; + } + + // Calculate the default size. + final Size defaultSize; + final Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo(); + 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, displayInfo.logicalWidth, displayInfo.logicalHeight); + } + + // Now that we have the default size, apply the snap fraction if valid or position the + // bounds using the default gravity. + if (snapFraction != INVALID_SNAP_FRACTION) { + defaultBounds.set(0, 0, defaultSize.getWidth(), defaultSize.getHeight()); + final Rect movementBounds = getMovementBounds(defaultBounds); + mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction); } else { - final Rect insetBounds = new Rect(); - getInsetBounds(insetBounds); - final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo(); - final Size defaultSize; - 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, displayInfo.logicalWidth, displayInfo.logicalHeight); - } Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(), insetBounds, 0, Math.max( mPipBoundsState.isImeShowing() ? mPipBoundsState.getImeHeight() : 0, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index 53aa61477483..4493d38d2144 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -76,6 +76,8 @@ public final class PipBoundsState { private int mImeHeight; private boolean mIsShelfShowing; private int mShelfHeight; + /** Whether the user has resized the PIP manually. */ + private boolean mHasUserResizedPip; private @Nullable Runnable mOnMinimalSizeChangeCallback; private @Nullable BiConsumer<Boolean, Integer> mOnShelfVisibilityChangeCallback; @@ -189,8 +191,8 @@ public final class PipBoundsState { } /** Save the reentry state to restore to when re-entering PIP mode. */ - public void saveReentryState(@NonNull Rect bounds, float fraction) { - mPipReentryState = new PipReentryState(new Size(bounds.width(), bounds.height()), fraction); + public void saveReentryState(Size size, float fraction) { + mPipReentryState = new PipReentryState(size, fraction); } /** Returns the saved reentry state. */ @@ -205,6 +207,7 @@ public final class PipBoundsState { mLastPipComponentName = lastPipComponentName; if (changed) { clearReentryState(); + setHasUserResizedPip(false); } } @@ -329,6 +332,16 @@ public final class PipBoundsState { return mShelfHeight; } + /** Returns whether the user has resized the PIP. */ + public boolean hasUserResizedPip() { + return mHasUserResizedPip; + } + + /** Set whether the user has resized the PIP. */ + public void setHasUserResizedPip(boolean hasUserResizedPip) { + mHasUserResizedPip = hasUserResizedPip; + } + /** * Registers a callback when the minimal size of PIP that is set by the app changes. */ @@ -397,15 +410,15 @@ public final class PipBoundsState { static final class PipReentryState { private static final String TAG = PipReentryState.class.getSimpleName(); - private final @NonNull Size mSize; + private final @Nullable Size mSize; private final float mSnapFraction; - PipReentryState(@NonNull Size size, float snapFraction) { + PipReentryState(@Nullable Size size, float snapFraction) { mSize = size; mSnapFraction = snapFraction; } - @NonNull + @Nullable Size getSize() { return mSize; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 3234ef6ccf66..9c7fdf761d3f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -39,6 +39,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.util.Pair; +import android.util.Size; import android.util.Slog; import android.view.DisplayInfo; import android.view.WindowManagerGlobal; @@ -85,7 +86,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private final Rect mTmpInsetBounds = new Rect(); - protected final Rect mReentryBounds = new Rect(); private boolean mIsInFixedRotation; private Consumer<Boolean> mPinnedStackAnimationRecentsCallback; @@ -437,10 +437,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { if (isOutPipDirection(direction)) { - // Exiting PIP, save the reentry bounds to restore to when re-entering. - updateReentryBounds(pipBounds); - final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(mReentryBounds); - mPipBoundsState.saveReentryState(mReentryBounds, snapFraction); + // Exiting PIP, save the reentry state to restore to when re-entering. + saveReentryState(pipBounds); } // Disable touches while the animation is running mTouchHandler.setTouchEnabled(false); @@ -449,14 +447,16 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac } } - /** - * Update the bounds used to save the re-entry size and snap fraction when exiting PIP. - */ - public void updateReentryBounds(Rect bounds) { - final Rect reentryBounds = mTouchHandler.getUserResizeBounds(); - float snapFraction = mPipBoundsAlgorithm.getSnapFraction(bounds); - mPipBoundsAlgorithm.applySnapFraction(reentryBounds, snapFraction); - mReentryBounds.set(reentryBounds); + /** Save the state to restore to on re-entry. */ + public void saveReentryState(Rect pipBounds) { + float snapFraction = mPipBoundsAlgorithm.getSnapFraction(pipBounds); + if (mPipBoundsState.hasUserResizedPip()) { + final Rect reentryBounds = mTouchHandler.getUserResizeBounds(); + final Size reentrySize = new Size(reentryBounds.width(), reentryBounds.height()); + mPipBoundsState.saveReentryState(reentrySize, snapFraction); + } else { + mPipBoundsState.saveReentryState(null /* bounds */, snapFraction); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index 88a11689b90b..0649e58b9305 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -409,6 +409,7 @@ public class PipResizeGestureHandler { mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds, null); + mPipBoundsState.setHasUserResizedPip(true); } } } @@ -461,6 +462,7 @@ public class PipResizeGestureHandler { true /* useCurrentSize */); mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds, null); + mPipBoundsState.setHasUserResizedPip(true); } break; case MotionEvent.ACTION_UP: diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java index a65d832359d2..ef9923550fc5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java @@ -337,7 +337,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase { reentryBounds.scale(1.25f); final float reentrySnapFraction = mPipBoundsAlgorithm.getSnapFraction(reentryBounds); - mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction); + mPipBoundsState.saveReentryState( + new Size(reentryBounds.width(), reentryBounds.height()), reentrySnapFraction); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); assertEquals(reentryBounds.width(), destinationBounds.width()); @@ -351,7 +352,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase { reentryBounds.offset(0, -100); final float reentrySnapFraction = mPipBoundsAlgorithm.getSnapFraction(reentryBounds); - mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction); + mPipBoundsState.saveReentryState( + new Size(reentryBounds.width(), reentryBounds.height()), reentrySnapFraction); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java index 4bcca06b592f..8ba301a9ebfa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java @@ -47,7 +47,7 @@ import java.util.function.BiConsumer; @SmallTest public class PipBoundsStateTest extends ShellTestCase { - private static final Rect DEFAULT_BOUNDS = new Rect(0, 0, 10, 10); + private static final Size DEFAULT_SIZE = new Size(10, 10); private static final float DEFAULT_SNAP_FRACTION = 1.0f; private PipBoundsState mPipBoundsState; @@ -71,22 +71,22 @@ public class PipBoundsStateTest extends ShellTestCase { @Test public void testSetReentryState() { - final Rect bounds = new Rect(0, 0, 100, 100); + final Size size = new Size(100, 100); final float snapFraction = 0.5f; - mPipBoundsState.saveReentryState(bounds, snapFraction); + mPipBoundsState.saveReentryState(size, snapFraction); final PipBoundsState.PipReentryState state = mPipBoundsState.getReentryState(); - assertEquals(new Size(100, 100), state.getSize()); + assertEquals(size, state.getSize()); assertEquals(snapFraction, state.getSnapFraction(), 0.01); } @Test public void testClearReentryState() { - final Rect bounds = new Rect(0, 0, 100, 100); + final Size size = new Size(100, 100); final float snapFraction = 0.5f; - mPipBoundsState.saveReentryState(bounds, snapFraction); + mPipBoundsState.saveReentryState(size, snapFraction); mPipBoundsState.clearReentryState(); assertNull(mPipBoundsState.getReentryState()); @@ -95,20 +95,20 @@ public class PipBoundsStateTest extends ShellTestCase { @Test public void testSetLastPipComponentName_notChanged_doesNotClearReentryState() { mPipBoundsState.setLastPipComponentName(mTestComponentName1); - mPipBoundsState.saveReentryState(DEFAULT_BOUNDS, DEFAULT_SNAP_FRACTION); + mPipBoundsState.saveReentryState(DEFAULT_SIZE, DEFAULT_SNAP_FRACTION); mPipBoundsState.setLastPipComponentName(mTestComponentName1); final PipBoundsState.PipReentryState state = mPipBoundsState.getReentryState(); assertNotNull(state); - assertEquals(new Size(DEFAULT_BOUNDS.width(), DEFAULT_BOUNDS.height()), state.getSize()); + assertEquals(DEFAULT_SIZE, state.getSize()); assertEquals(DEFAULT_SNAP_FRACTION, state.getSnapFraction(), 0.01); } @Test public void testSetLastPipComponentName_changed_clearReentryState() { mPipBoundsState.setLastPipComponentName(mTestComponentName1); - mPipBoundsState.saveReentryState(DEFAULT_BOUNDS, DEFAULT_SNAP_FRACTION); + mPipBoundsState.saveReentryState(DEFAULT_SIZE, DEFAULT_SNAP_FRACTION); mPipBoundsState.setLastPipComponentName(mTestComponentName2); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index 4687d2d9667c..62ffac4fbd3f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -30,10 +30,12 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.Rect; import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Size; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.WindowManagerShellWrapper; @@ -135,4 +137,28 @@ public class PipControllerTest extends ShellTestCase { verify(mMockPipBoundsState, never()).setLastPipComponentName(null); } + + @Test + public void saveReentryState_noUserResize_doesNotSaveSize() { + final Rect bounds = new Rect(0, 0, 10, 10); + when(mMockPipBoundsAlgorithm.getSnapFraction(bounds)).thenReturn(1.0f); + when(mMockPipBoundsState.hasUserResizedPip()).thenReturn(false); + + mPipController.saveReentryState(bounds); + + verify(mMockPipBoundsState).saveReentryState(null, 1.0f); + } + + @Test + public void saveReentryState_userHasResized_savesSize() { + final Rect bounds = new Rect(0, 0, 10, 10); + final Rect resizedBounds = new Rect(0, 0, 30, 30); + when(mMockPipBoundsAlgorithm.getSnapFraction(bounds)).thenReturn(1.0f); + when(mMockPipTouchHandler.getUserResizeBounds()).thenReturn(resizedBounds); + when(mMockPipBoundsState.hasUserResizedPip()).thenReturn(true); + + mPipController.saveReentryState(bounds); + + verify(mMockPipBoundsState).saveReentryState(new Size(30, 30), 1.0f); + } } |