Loading packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +10 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; Loading @@ -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); } Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +49 −22 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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(), Loading Loading @@ -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( Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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 { Loading @@ -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); Loading @@ -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. */ Loading Loading @@ -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); } /** Loading packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java 0 → 100644 +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()); } } Loading
packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +10 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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; Loading @@ -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); } Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +49 −22 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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(), Loading Loading @@ -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( Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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 { Loading @@ -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); Loading @@ -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. */ Loading Loading @@ -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); } /** Loading
packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java 0 → 100644 +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()); } }