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

This commit is contained in:
Ben Lin
2020-03-17 18:20:11 +00:00
committed by Android (Google) Code Review
4 changed files with 230 additions and 31 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}
/**

View File

@@ -0,0 +1,170 @@
/*
* 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());
}
}