diff options
Diffstat (limited to 'libs')
4 files changed, 80 insertions, 143 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java index 4cbb78f2dae2..d36201a4ac9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDoubleTapHelper.java @@ -52,24 +52,15 @@ public class PipDoubleTapHelper { public static final int SIZE_SPEC_MAX = 1; public static final int SIZE_SPEC_CUSTOM = 2; - /** - * Returns MAX or DEFAULT {@link PipSizeSpec} to toggle to/from. - * - * <p>Each double tap toggles back and forth between {@code PipSizeSpec.CUSTOM} and - * either {@code PipSizeSpec.MAX} or {@code PipSizeSpec.DEFAULT}. The choice between - * the latter two sizes is determined based on the current state of the pip screen.</p> - * - * @param mPipBoundsState current state of the pip screen - */ @PipSizeSpec - private static int getMaxOrDefaultPipSizeSpec(@NonNull PipBoundsState mPipBoundsState) { + private static int getMaxOrDefaultPipSizeSpec(@NonNull PipBoundsState pipBoundsState) { // determine the average pip screen width - int averageWidth = (mPipBoundsState.getMaxSize().x - + mPipBoundsState.getMinSize().x) / 2; + int averageWidth = (pipBoundsState.getMaxSize().x + + pipBoundsState.getMinSize().x) / 2; // If pip screen width is above average, DEFAULT is the size spec we need to // toggle to. Otherwise, we choose MAX. - return (mPipBoundsState.getBounds().width() > averageWidth) + return (pipBoundsState.getBounds().width() > averageWidth) ? SIZE_SPEC_DEFAULT : SIZE_SPEC_MAX; } @@ -77,35 +68,33 @@ public class PipDoubleTapHelper { /** * Determines the {@link PipSizeSpec} to toggle to on double tap. * - * @param mPipBoundsState current state of the pip screen + * @param pipBoundsState current state of the pip bounds * @param userResizeBounds latest user resized bounds (by pinching in/out) - * @return pip screen size to switch to */ @PipSizeSpec - public static int nextSizeSpec(@NonNull PipBoundsState mPipBoundsState, + public static int nextSizeSpec(@NonNull PipBoundsState pipBoundsState, @NonNull Rect userResizeBounds) { - // is pip screen at its maximum - boolean isScreenMax = mPipBoundsState.getBounds().width() - == mPipBoundsState.getMaxSize().x; - - // is pip screen at its normal default size - boolean isScreenDefault = (mPipBoundsState.getBounds().width() - == mPipBoundsState.getNormalBounds().width()) - && (mPipBoundsState.getBounds().height() - == mPipBoundsState.getNormalBounds().height()); + boolean isScreenMax = pipBoundsState.getBounds().width() == pipBoundsState.getMaxSize().x + && pipBoundsState.getBounds().height() == pipBoundsState.getMaxSize().y; + boolean isScreenDefault = (pipBoundsState.getBounds().width() + == pipBoundsState.getNormalBounds().width()) + && (pipBoundsState.getBounds().height() + == pipBoundsState.getNormalBounds().height()); // edge case 1 // if user hasn't resized screen yet, i.e. CUSTOM size does not exist yet // or if user has resized exactly to DEFAULT, then we just want to maximize if (isScreenDefault - && userResizeBounds.width() == mPipBoundsState.getNormalBounds().width()) { + && userResizeBounds.width() == pipBoundsState.getNormalBounds().width() + && userResizeBounds.height() == pipBoundsState.getNormalBounds().height()) { return SIZE_SPEC_MAX; } // edge case 2 - // if user has maximized, then we want to toggle to DEFAULT + // if user has resized to max, then we want to toggle to DEFAULT if (isScreenMax - && userResizeBounds.width() == mPipBoundsState.getMaxSize().x) { + && userResizeBounds.width() == pipBoundsState.getMaxSize().x + && userResizeBounds.height() == pipBoundsState.getMaxSize().y) { return SIZE_SPEC_DEFAULT; } @@ -113,9 +102,6 @@ public class PipDoubleTapHelper { if (isScreenDefault || isScreenMax) { return SIZE_SPEC_CUSTOM; } - - // if we are currently in user resized CUSTOM size state - // then we toggle either to MAX or DEFAULT depending on the current pip screen state - return getMaxOrDefaultPipSizeSpec(mPipBoundsState); + return getMaxOrDefaultPipSizeSpec(pipBoundsState); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index f81f330e50c4..a02a51f92b1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -180,10 +180,17 @@ public class PipScheduler implements PipTransitionState.PipTransitionStateChange return; } WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setBounds(pipTaskToken, toBounds); if (configAtEnd) { wct.deferConfigToTransitionEnd(pipTaskToken); + + if (mPipBoundsState.getBounds().width() == toBounds.width() + && mPipBoundsState.getBounds().height() == toBounds.height()) { + // TODO (b/393159816): Config-at-End causes a flicker without size change. + // If PiP size isn't changing enforce a minimal one-pixel change as a workaround. + --toBounds.bottom; + } } + wct.setBounds(pipTaskToken, toBounds); mPipTransitionController.startResizeTransition(wct, duration); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index 6fdfecaf15d5..d1bc450c3c4d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -934,6 +934,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha } // the size to toggle to after a double tap + mPipBoundsState.setNormalBounds(getAdjustedNormalBounds()); int nextSize = PipDoubleTapHelper .nextSizeSpec(mPipBoundsState, getUserResizeBounds()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java index 1756aad8fc9b..cc23d9a75fcd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDoubleTapHelperTest.java @@ -21,7 +21,6 @@ import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_DEFAU import static com.android.wm.shell.common.pip.PipDoubleTapHelper.SIZE_SPEC_MAX; import static com.android.wm.shell.common.pip.PipDoubleTapHelper.nextSizeSpec; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.graphics.Point; @@ -41,131 +40,75 @@ import org.mockito.Mock; */ @RunWith(AndroidTestingRunner.class) public class PipDoubleTapHelperTest extends ShellTestCase { - // represents the current pip window state and has information on current - // max, min, and normal sizes - @Mock private PipBoundsState mBoundStateMock; - // tied to boundsStateMock.getBounds() in setUp() - @Mock private Rect mBoundsMock; - - // represents the most recent manually resized bounds - // i.e. dimensions from the most recent pinch in/out - @Mock private Rect mUserResizeBoundsMock; - - // actual dimensions of the pip screen bounds - private static final int MAX_WIDTH = 100; - private static final int DEFAULT_WIDTH = 40; - private static final int MIN_WIDTH = 10; - - private static final int AVERAGE_WIDTH = (MAX_WIDTH + MIN_WIDTH) / 2; - - /** - * Initializes mocks and assigns values for different pip screen bounds. - */ + @Mock private PipBoundsState mMockPipBoundsState; + + // Actual dimension guidelines of the PiP bounds. + private static final int MAX_EDGE_SIZE = 100; + private static final int DEFAULT_EDGE_SIZE = 60; + private static final int MIN_EDGE_SIZE = 50; + private static final int AVERAGE_EDGE_SIZE = (MAX_EDGE_SIZE + MIN_EDGE_SIZE) / 2; + @Before public void setUp() { // define pip bounds - when(mBoundStateMock.getMaxSize()).thenReturn(new Point(MAX_WIDTH, 20)); - when(mBoundStateMock.getMinSize()).thenReturn(new Point(MIN_WIDTH, 2)); + when(mMockPipBoundsState.getMaxSize()).thenReturn(new Point(MAX_EDGE_SIZE, MAX_EDGE_SIZE)); + when(mMockPipBoundsState.getMinSize()).thenReturn(new Point(MIN_EDGE_SIZE, MIN_EDGE_SIZE)); - Rect rectMock = mock(Rect.class); - when(rectMock.width()).thenReturn(DEFAULT_WIDTH); - when(mBoundStateMock.getNormalBounds()).thenReturn(rectMock); + final Rect normalBounds = new Rect(0, 0, DEFAULT_EDGE_SIZE, DEFAULT_EDGE_SIZE); + when(mMockPipBoundsState.getNormalBounds()).thenReturn(normalBounds); + } - when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH); - when(mBoundStateMock.getBounds()).thenReturn(mBoundsMock); + @Test + public void nextSizeSpec_resizedWiderThanAverage_returnDefaultThenCustom() { + final int resizeEdgeSize = (MAX_EDGE_SIZE + AVERAGE_EDGE_SIZE) / 2; + final Rect userResizeBounds = new Rect(0, 0, resizeEdgeSize, resizeEdgeSize); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_DEFAULT); + + // once we toggle to DEFAULT only PiP bounds state gets updated - not the user resize bounds + when(mMockPipBoundsState.getBounds()).thenReturn( + new Rect(0, 0, DEFAULT_EDGE_SIZE, DEFAULT_EDGE_SIZE)); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_CUSTOM); + } + + @Test + public void nextSizeSpec_resizedSmallerThanAverage_returnMaxThenCustom() { + final int resizeEdgeSize = (AVERAGE_EDGE_SIZE + MIN_EDGE_SIZE) / 2; + final Rect userResizeBounds = new Rect(0, 0, resizeEdgeSize, resizeEdgeSize); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_MAX); + + // Once we toggle to MAX our screen size gets updated but not the user resize bounds + when(mMockPipBoundsState.getBounds()).thenReturn( + new Rect(0, 0, MAX_EDGE_SIZE, MAX_EDGE_SIZE)); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_CUSTOM); } - /** - * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}. - * - * <p>when the user resizes the screen to a larger than the average but not the maximum width, - * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.DEFAULT} - */ @Test - public void testNextScreenSize_resizedWiderThanAverage_returnDefaultThenCustom() { - // make the user resize width in between MAX and average - when(mUserResizeBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2); - // make current bounds same as resized bound since no double tap yet - when(mBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2); - - // then nextScreenSize() i.e. double tapping should - // toggle to DEFAULT state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_DEFAULT); - - // once we toggle to DEFAULT our screen size gets updated - // but not the user resize bounds - when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH); - - // then nextScreenSize() i.e. double tapping should - // toggle to CUSTOM state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_CUSTOM); + public void nextSizeSpec_resizedToMax_returnDefault() { + final Rect userResizeBounds = new Rect(0, 0, MAX_EDGE_SIZE, MAX_EDGE_SIZE); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_DEFAULT); } - /** - * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}. - * - * <p>when the user resizes the screen to a smaller than the average but not the default width, - * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.MAX} - */ @Test - public void testNextScreenSize_resizedNarrowerThanAverage_returnMaxThenCustom() { - // make the user resize width in between MIN and average - when(mUserResizeBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2); - // make current bounds same as resized bound since no double tap yet - when(mBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2); - - // then nextScreenSize() i.e. double tapping should - // toggle to MAX state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_MAX); - - // once we toggle to MAX our screen size gets updated - // but not the user resize bounds - when(mBoundsMock.width()).thenReturn(MAX_WIDTH); - - // then nextScreenSize() i.e. double tapping should - // toggle to CUSTOM state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_CUSTOM); + public void nextSizeSpec_resizedToDefault_returnMax() { + final Rect userResizeBounds = new Rect(0, 0, DEFAULT_EDGE_SIZE, DEFAULT_EDGE_SIZE); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_MAX); } - /** - * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}. - * - * <p>when the user resizes the screen to exactly the maximum width - * then we toggle to {@code PipSizeSpec.DEFAULT} - */ @Test - public void testNextScreenSize_resizedToMax_returnDefault() { - // the resized width is the same as MAX_WIDTH - when(mUserResizeBoundsMock.width()).thenReturn(MAX_WIDTH); - // the current bounds are also at MAX_WIDTH - when(mBoundsMock.width()).thenReturn(MAX_WIDTH); - - // then nextScreenSize() i.e. double tapping should - // toggle to DEFAULT state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_DEFAULT); + public void nextSizeSpec_resizedToAlmostMax_returnDefault() { + final Rect userResizeBounds = new Rect(0, 0, MAX_EDGE_SIZE, MAX_EDGE_SIZE - 1); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_DEFAULT); } - /** - * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}. - * - * <p>when the user resizes the screen to exactly the default width - * then we toggle to {@code PipSizeSpec.MAX} - */ @Test - public void testNextScreenSize_resizedToDefault_returnMax() { - // the resized width is the same as DEFAULT_WIDTH - when(mUserResizeBoundsMock.width()).thenReturn(DEFAULT_WIDTH); - // the current bounds are also at DEFAULT_WIDTH - when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH); - - // then nextScreenSize() i.e. double tapping should - // toggle to MAX state - Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock), - SIZE_SPEC_MAX); + public void nextSizeSpec_resizedToAlmostMin_returnMax() { + final Rect userResizeBounds = new Rect(0, 0, MIN_EDGE_SIZE, MIN_EDGE_SIZE + 1); + when(mMockPipBoundsState.getBounds()).thenReturn(userResizeBounds); + Assert.assertEquals(nextSizeSpec(mMockPipBoundsState, userResizeBounds), SIZE_SPEC_MAX); } } |