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

Commit 89c3650f authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Reland: Track current resized bounds for resized PIP." into rvc-dev am:...

Merge "Reland: Track current resized bounds for resized PIP." into rvc-dev am: fed10a30 am: afb8af16 am: 41667d82

Change-Id: Ic57a3d86b9dc2e827dea05b2d3d89cf4c5567976
parents d768c0e3 41667d82
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -229,8 +229,8 @@ public class PipBoundsHandler {
     */
    Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) {
        final Rect destinationBounds;
        final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
        if (bounds == null) {
            final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
            destinationBounds = new Rect(defaultBounds);
            if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) {
                mOverrideMinimalSize = minimalSize;
+10 −8
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ public class PipResizeGestureHandler {
    private final PointF mDownPoint = new PointF();
    private final Point mMaxSize = new Point();
    private final Point mMinSize = new Point();
    private final Rect mLastResizeBounds = new Rect();
    private final Rect mTmpBounds = new Rect();
    private final int mDelta;

@@ -187,17 +188,13 @@ public class PipResizeGestureHandler {
    private void onMotionEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN) {
            mLastResizeBounds.setEmpty();
            mAllowGesture = isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
            if (mAllowGesture) {
                mDownPoint.set(ev.getX(), ev.getY());
            }

        } else if (mAllowGesture) {
            final Rect currentPipBounds = mMotionHelper.getBounds();
            Rect newSize = TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), mDownPoint.x,
                    mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, mMinSize.y, mMaxSize,
                    true, true);
            mPipBoundsHandler.transformBoundsToAspectRatio(newSize);
            switch (action) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    // We do not support multi touch for resizing via drag
@@ -206,11 +203,16 @@ public class PipResizeGestureHandler {
                case MotionEvent.ACTION_MOVE:
                    // Capture inputs
                    mInputMonitor.pilferPointers();
                    //TODO: Actually do resize here.
                    final Rect currentPipBounds = mMotionHelper.getBounds();
                    mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
                            mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
                            mMinSize.y, mMaxSize, true, true));
                    mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
                    mPipTaskOrganizer.scheduleResizePip(mLastResizeBounds, null);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    //TODO: Finish resize operation here.
                    mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds);
                    mMotionHelper.synchronizePinnedStackBounds();
                    mCtrlType = CTRL_NONE;
                    mAllowGesture = false;
@@ -223,7 +225,7 @@ public class PipResizeGestureHandler {
        mMaxSize.set(maxX, maxY);
    }

    void updateMiniSize(int minX, int minY) {
    void updateMinSize(int minX, int minY) {
        mMinSize.set(minX, minY);
    }

+49 −22
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.systemui.R;
import com.android.systemui.pip.PipBoundsHandler;
@@ -74,7 +75,7 @@ public class PipTouchHandler {
    private final Context mContext;
    private final IActivityManager mActivityManager;
    private final PipBoundsHandler mPipBoundsHandler;
    private final PipResizeGestureHandler mPipResizeGestureHandler;
    private PipResizeGestureHandler mPipResizeGestureHandler;
    private IPinnedStackController mPinnedStackController;

    private final PipMenuActivityController mMenuController;
@@ -85,14 +86,17 @@ public class PipTouchHandler {

    // The current movement bounds
    private Rect mMovementBounds = new Rect();
    // The current resized bounds, changed by user resize.
    // This is used during expand/un-expand to save/restore the user's resized size.
    @VisibleForTesting Rect mResizedBounds = new Rect();

    // The reference inset bounds, used to determine the dismiss fraction
    private Rect mInsetBounds = new Rect();
    // The reference bounds used to calculate the normal/expanded target bounds
    private Rect mNormalBounds = new Rect();
    private Rect mNormalMovementBounds = new Rect();
    @VisibleForTesting Rect mNormalMovementBounds = new Rect();
    private Rect mExpandedBounds = new Rect();
    private Rect mExpandedMovementBounds = new Rect();
    @VisibleForTesting Rect mExpandedMovementBounds = new Rect();
    private int mExpandedShortestEdgeSize;

    // Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -127,7 +131,7 @@ public class PipTouchHandler {
    private final PipTouchState mTouchState;
    private final FlingAnimationUtils mFlingAnimationUtils;
    private final FloatingContentCoordinator mFloatingContentCoordinator;
    private final PipMotionHelper mMotionHelper;
    private PipMotionHelper mMotionHelper;
    private PipTouchGesture mGesture;

    // Temp vars
@@ -240,14 +244,15 @@ public class PipTouchHandler {

            mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
        }
        mResizedBounds.setEmpty();
        mPipResizeGestureHandler.onActivityUnpinned();
    }

    public void onPinnedStackAnimationEnded() {
        // Always synchronize the motion helper bounds once PiP animations finish
        mMotionHelper.synchronizePinnedStackBounds();
        mPipResizeGestureHandler.updateMiniSize(mMotionHelper.getBounds().width(),
                mMotionHelper.getBounds().height());
        updateMovementBounds();
        mResizedBounds.set(mMotionHelper.getBounds());

        if (mShowPipMenuOnAnimationEnd) {
            mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
@@ -292,11 +297,13 @@ public class PipTouchHandler {
        Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
                mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
        mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
        mPipResizeGestureHandler.updateMaxSize(expandedSize.getWidth(), expandedSize.getHeight());
        Rect expandedMovementBounds = new Rect();
        mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
                bottomOffset);

        mPipResizeGestureHandler.updateMinSize(mNormalBounds.width(), mNormalBounds.height());
        mPipResizeGestureHandler.updateMaxSize(mExpandedBounds.width(), mExpandedBounds.height());

        // The extra offset does not really affect the movement bounds, but are applied based on the
        // current state (ime showing, or shelf offset) when we need to actually shift
        int extraOffset = Math.max(
@@ -332,7 +339,7 @@ public class PipTouchHandler {
        mExpandedMovementBounds = expandedMovementBounds;
        mDisplayRotation = displayRotation;
        mInsetBounds.set(insetBounds);
        updateMovementBounds(mMenuState);
        updateMovementBounds();
        mMovementBoundsExtraOffsets = extraOffset;

        // If we have a deferred resize, apply it now
@@ -392,7 +399,7 @@ public class PipTouchHandler {
            case MotionEvent.ACTION_UP: {
                // Update the movement bounds again if the state has changed since the user started
                // dragging (ie. when the IME shows)
                updateMovementBounds(mMenuState);
                updateMovementBounds();

                if (mGesture.onUp(mTouchState)) {
                    break;
@@ -490,9 +497,11 @@ public class PipTouchHandler {
        if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
            // Save the current snap fraction and if we do not drag or move the PiP, then
            // we store back to this snap fraction.  Otherwise, we'll reset the snap
            // fraction and snap to the closest edge
            Rect expandedBounds = new Rect(mExpandedBounds);
            // fraction and snap to the closest edge.
            // Also save the current resized bounds so when the menu disappears, we can restore it.
            if (resize) {
                mResizedBounds.set(mMotionHelper.getBounds());
                Rect expandedBounds = new Rect(mExpandedBounds);
                mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
                        mMovementBounds, mExpandedMovementBounds);
            }
@@ -520,9 +529,12 @@ public class PipTouchHandler {
                }

                if (mDeferResizeToNormalBoundsUntilRotation == -1) {
                    Rect normalBounds = new Rect(mNormalBounds);
                    mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
                            mNormalMovementBounds, mMovementBounds, false /* immediate */);
                    Rect restoreBounds = new Rect(mResizedBounds);
                    Rect restoredMovementBounds = new Rect();
                    mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
                            restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
                    mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
                            restoredMovementBounds, mMovementBounds, false /* immediate */);
                    mSavedSnapFraction = -1f;
                }
            } else {
@@ -533,7 +545,7 @@ public class PipTouchHandler {
            }
        }
        mMenuState = menuState;
        updateMovementBounds(menuState);
        updateMovementBounds();
        // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
        // as well, or it can't handle a11y focus and pip menu can't perform any action.
        onRegistrationChanged(menuState == MENU_STATE_NONE);
@@ -549,6 +561,21 @@ public class PipTouchHandler {
        return mMotionHelper;
    }

    @VisibleForTesting
    PipResizeGestureHandler getPipResizeGestureHandler() {
        return mPipResizeGestureHandler;
    }

    @VisibleForTesting
    void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
        mPipResizeGestureHandler = pipResizeGestureHandler;
    }

    @VisibleForTesting
    void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
        mMotionHelper = pipMotionHelper;
    }

    /**
     * @return the unexpanded bounds.
     */
@@ -709,14 +736,14 @@ public class PipTouchHandler {
     * Updates the current movement bounds based on whether the menu is currently visible and
     * resized.
     */
    private void updateMovementBounds(int menuState) {
        boolean isMenuExpanded = menuState == MENU_STATE_FULL;
        mMovementBounds = isMenuExpanded && willResizeMenu()
                ? mExpandedMovementBounds
                : mNormalMovementBounds;
        mPipBoundsHandler.setMinEdgeSize(
                isMenuExpanded ? mExpandedShortestEdgeSize : 0);
    private void updateMovementBounds() {
        mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds,
                mMovementBounds, mIsImeShowing ? mImeHeight : 0);
        mMotionHelper.setCurrentMovementBounds(mMovementBounds);

        boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
        mPipBoundsHandler.setMinEdgeSize(
                isMenuExpanded  && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
    }

    /**
+170 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.pip.phone;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Size;
import android.view.DisplayInfo;

import androidx.test.filters.SmallTest;

import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

/**
 * Unit tests against {@link PipTouchHandler}, including but not limited to:
 * - Update movement bounds based on new bounds
 * - Update movement bounds based on IME/shelf
 * - Update movement bounds to PipResizeHandler
 */
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class PipTouchHandlerTest extends SysuiTestCase {
    private static final int ROUNDING_ERROR_MARGIN = 10;
    private static final float DEFAULT_ASPECT_RATIO = 1f;
    private static final Rect EMPTY_CURRENT_BOUNDS = null;

    private PipTouchHandler mPipTouchHandler;
    private DisplayInfo mDefaultDisplayInfo;

    @Mock
    private IActivityManager mActivityManager;

    @Mock
    private IActivityTaskManager mIActivityTaskManager;

    @Mock
    private PipMenuActivityController mPipMenuActivityController;

    @Mock
    private InputConsumerController mInputConsumerController;

    @Mock
    private PipBoundsHandler mPipBoundsHandler;

    @Mock
    private PipTaskOrganizer mPipTaskOrganizer;

    @Mock
    private FloatingContentCoordinator mFloatingContentCoordinator;

    @Mock
    private DeviceConfigProxy mDeviceConfigProxy;


    private PipSnapAlgorithm mPipSnapAlgorithm;
    private PipMotionHelper mMotionHelper;
    private PipResizeGestureHandler mPipResizeGestureHandler;

    Rect mInsetBounds;
    Rect mMinBounds;
    Rect mCurBounds;
    boolean mFromImeAdjustment;
    boolean mFromShelfAdjustment;
    int mDisplayRotation;


    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
        mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager,
                mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
                mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
                mPipSnapAlgorithm);
        mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
        mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
        mPipTouchHandler.setPipMotionHelper(mMotionHelper);
        mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler);

        // Assume a display of 1000 x 1000
        // inset of 10
        mInsetBounds = new Rect(10, 10, 990, 990);
        // minBounds of 100x100 bottom right corner
        mMinBounds = new Rect(890, 890, 990, 990);
        mCurBounds = new Rect();
        mFromImeAdjustment = false;
        mFromShelfAdjustment = false;
        mDisplayRotation = 0;
    }

    @Test
    public void updateMovementBounds_minBounds() {
        Rect expectedMinMovementBounds = new Rect();
        mPipSnapAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds, 0);

        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        assertEquals(expectedMinMovementBounds, mPipTouchHandler.mNormalMovementBounds);
        verify(mPipResizeGestureHandler, times(1))
                .updateMinSize(mMinBounds.width(), mMinBounds.height());
    }

    @Test
    public void updateMovementBounds_maxBounds() {
        Point displaySize = new Point();
        mContext.getDisplay().getRealSize(displaySize);
        Size maxSize = mPipSnapAlgorithm.getSizeForAspectRatio(1,
                mContext.getResources().getDimensionPixelSize(
                        R.dimen.pip_expanded_shortest_edge_size), displaySize.x, displaySize.y);
        Rect maxBounds = new Rect(0, 0, maxSize.getWidth(), maxSize.getHeight());
        Rect expectedMaxMovementBounds = new Rect();
        mPipSnapAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds, 0);

        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        assertEquals(expectedMaxMovementBounds, mPipTouchHandler.mExpandedMovementBounds);
        verify(mPipResizeGestureHandler, times(1))
                .updateMaxSize(maxBounds.width(), maxBounds.height());
    }

    @Test
    public void updateMovementBounds_withImeAdjustment_movesPip() {
        mFromImeAdjustment = true;
        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt());
    }
}