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

Commit 623e3588 authored by Mateusz Cicheński's avatar Mateusz Cicheński
Browse files

Scaling PiP proportionally on screen rotation and fold/unfold

The end bounds are stored in PipBoundsState and the transition system
does not have knowledge of the proportional resize, so the value in
pipChange.getEndAbsBounds() is not the correct one.

Updating the rotation handler to correctly update the scale and max
size in OnDisplayChangingListener, so that all future calculations
are using the updated values for scale/max size.

Since the value has been cached locally in PipBoundsState, having
stale invocations would lead to artifacts such as PiP resizing in
unexpected way upon screen rotation or during fixed rotation enter
PiP animation.

Test: manually
Test: atest EnterPipToOtherOrientation
Test: 3 button nav rotation http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/gxlk5IJSb0gVojnPfJvMxY
Test: gesture nav rotation http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/ga3gIHEOVatMVTr6WXQnNX
Test: 3 button nav fixed rotation enter pip http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/8A94b9HbYXvtlEuU8KQO5
Test: gesture nav fixed rotation enter pip http://recall/-/ekEuGtt9d9HWqkUtAzpHx8/gcJsqm3Hu3RaYagOapDXsS
Bug: 322091225
Bug: 319083003
Bug: 308093519
Bug: 323789757
Flag: none

Change-Id: Idc1429577da5c1817fe2f4ad12cefc32e0e86dd6
parent 862b59b9
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ public class PipBoundsState {
        // 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);
            updateBoundsScale();
        });
    }

@@ -152,6 +152,11 @@ public class PipBoundsState {
        mSizeSpecSource.onConfigurationChanged();
    }

    /** Update the bounds scale percentage value. */
    public void updateBoundsScale() {
        mBoundsScale = Math.min((float) mBounds.width() / mMaxSize.x, 1.0f);
    }

    private void reloadResources() {
        mStashOffset = mContext.getResources().getDimensionPixelSize(R.dimen.pip_stash_offset);
    }
+0 −6
Original line number Diff line number Diff line
@@ -286,12 +286,6 @@ public class PipTransition extends PipTransitionController {
        // For transition that we don't animate, but contains the PIP leash, we need to update the
        // PIP surface, otherwise it will be reset after the transition.
        if (currentPipTaskChange != null) {
            // Set the "end" bounds of pip. The default setup uses the start bounds. Since this is
            // changing the *finish*Transaction, we need to use the end bounds. This will also
            // make sure that the fade-in animation (below) uses the end bounds as well.
            if (!currentPipTaskChange.getEndAbsBounds().isEmpty()) {
                mPipBoundsState.setBounds(currentPipTaskChange.getEndAbsBounds());
            }
            updatePipForUnhandledTransition(currentPipTaskChange, startTransaction,
                    finishTransaction);
        }
+19 −13
Original line number Diff line number Diff line
@@ -244,6 +244,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
            // The same rotation may have been set by auto PiP-able or fixed rotation. So notify
            // the change with fromRotation=false to apply the rotated destination bounds from
            // PipTaskOrganizer#onMovementBoundsChanged.
            // We need to update the bounds scale in case this was from fixed rotation, as the
            // current proportion was computed using the previous orientation max size and is wrong.
            mPipBoundsState.updateBoundsScale();
            updateMovementBounds(null, false /* fromRotation */,
                    false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
            return;
@@ -797,21 +800,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(
@@ -827,6 +824,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb
            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.
@@ -1146,6 +1147,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb

        // Update the display layout
        mPipDisplayLayoutState.rotateTo(toRotation);
        mTouchHandler.updateMinMaxSize(mPipBoundsState.getAspectRatio());

        postChangeStackBounds.set(0, 0,
                (int) (mPipBoundsState.getMaxSize().x * mPipBoundsState.getBoundsScale()),
                (int) (mPipBoundsState.getMaxSize().y * mPipBoundsState.getBoundsScale()));

        // Calculate the stack bounds in the new orientation based on same fraction along the
        // rotated movement bounds.
+12 −0
Original line number Diff line number Diff line
@@ -86,6 +86,8 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli
                .withNavOrTaskBarVisible()
                .withStatusBarVisible()
                .waitForAndVerify()

            pipApp.tapPipToShowMenu(wmHelper)
        }
    }

@@ -194,6 +196,16 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli
        }
    }

    @Postsubmit
    @Test
    fun menuOverlayMatchesTaskSurface() {
        flicker.assertLayersEnd {
            val pipAppRegion = visibleRegion(pipApp)
            val pipMenuRegion = visibleRegion(ComponentNameMatcher.PIP_MENU_OVERLAY)
            pipAppRegion.coversExactly(pipMenuRegion.region)
        }
    }

    /** {@inheritDoc} */
    @FlakyTest(bugId = 267424412)
    @Test
+8 −0
Original line number Diff line number Diff line
@@ -340,6 +340,14 @@ open class PipAppHelper(instrumentation: Instrumentation) :
        wmHelper.StateSyncBuilder().withPipGone().withHomeActivityVisible().waitForAndVerify()
    }

    open fun tapPipToShowMenu(wmHelper: WindowManagerStateHelper) {
        val windowRect = getWindowRect(wmHelper)
        uiDevice.click(windowRect.centerX(), windowRect.centerY())
        // search and interact with the dismiss button
        val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
        uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
    }

    /** Close the pip window by pressing the expand button */
    fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
        val windowRect = getWindowRect(wmHelper)