diff options
| author | 2020-02-13 14:48:40 -0500 | |
|---|---|---|
| committer | 2020-02-18 11:27:17 -0500 | |
| commit | c81ff3d4e90f0b72708a5e4685286a2a00692be8 (patch) | |
| tree | 369361068be30998aad99eebd610c327959e5270 | |
| parent | 7155bf102fac826bd5f07082b571e1722555ef23 (diff) | |
Modifies PIP to use the FloatingContentCoordinator.
Test: atest SystemUITests
Bug: 138115889
Change-Id: I639852a498676230e2318e4ba78c5a4333f6df02
4 files changed, 144 insertions, 58 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java index 383d459b7ed1..adee7f23e709 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java @@ -20,6 +20,7 @@ import android.content.res.Configuration; import java.io.PrintWriter; + public interface BasePipManager { void showPictureInPictureMenu(); default void expandPip() {} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index b5c8d66947ca..cb94e28e3467 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -46,6 +46,7 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.wm.DisplayChangeController; import com.android.systemui.wm.DisplayController; @@ -229,7 +230,8 @@ public class PipManager implements BasePipManager { @Inject public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, - DisplayController displayController) { + DisplayController displayController, + FloatingContentCoordinator floatingContentCoordinator) { mContext = context; mActivityManager = ActivityManager.getService(); mActivityTaskManager = ActivityTaskManager.getService(); @@ -247,7 +249,8 @@ public class PipManager implements BasePipManager { mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController, mInputConsumerController); mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager, - mMenuController, mInputConsumerController, mPipBoundsHandler); + mMenuController, mInputConsumerController, mPipBoundsHandler, + floatingContentCoordinator); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, mTouchHandler.getMotionHelper()); displayController.addDisplayChangingController(mRotationController); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 3ae627d27def..c6e28522ccbd 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -19,6 +19,7 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.StackInfo; import android.app.IActivityManager; @@ -41,6 +42,7 @@ import com.android.internal.os.SomeArgs; import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.animation.FloatProperties; import com.android.systemui.util.animation.PhysicsAnimator; @@ -49,7 +51,8 @@ import java.io.PrintWriter; /** * A helper to animate and manipulate the PiP. */ -public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback { +public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback, + FloatingContentCoordinator.FloatingContent { private static final String TAG = "PipMotionHelper"; private static final boolean DEBUG = false; @@ -85,6 +88,12 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** PIP's current bounds on the screen. */ private final Rect mBounds = new Rect(); + /** The bounds within which PIP's top-left coordinate is allowed to move. */ + private Rect mMovementBounds = new Rect(); + + /** The region that all of PIP must stay within. */ + private Rect mFloatingAllowedArea = new Rect(); + private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider = new SfVsyncFrameCallbackProvider(); @@ -93,6 +102,12 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call */ private final Rect mAnimatedBounds = new Rect(); + /** The destination bounds to which PIP is animating. */ + private Rect mAnimatingToBounds = new Rect(); + + /** Coordinator instance for resolving conflicts with other floating content. */ + private FloatingContentCoordinator mFloatingContentCoordinator; + /** * PhysicsAnimator instance for animating {@link #mAnimatedBounds} using physics animations. */ @@ -119,9 +134,15 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call new PhysicsAnimator.SpringConfig( SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + /** SpringConfig to use for springing PIP away from conflicting floating content. */ + private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig = + new PhysicsAnimator.SpringConfig( + SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + public PipMotionHelper(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, - PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) { + PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils, + FloatingContentCoordinator floatingContentCoordinator) { mContext = context; mHandler = new Handler(ForegroundThread.get().getLooper(), this); mActivityManager = activityManager; @@ -129,9 +150,27 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call mMenuController = menuController; mSnapAlgorithm = snapAlgorithm; mFlingAnimationUtils = flingAnimationUtils; + mFloatingContentCoordinator = floatingContentCoordinator; onConfigurationChanged(); } + @NonNull + @Override + public Rect getFloatingBoundsOnScreen() { + return !mAnimatingToBounds.isEmpty() ? mAnimatingToBounds : mBounds; + } + + @NonNull + @Override + public Rect getAllowedFloatingBoundsRegion() { + return mFloatingAllowedArea; + } + + @Override + public void moveToBounds(@NonNull Rect bounds) { + animateToBounds(bounds, mConflictResolutionSpringConfig); + } + /** * Updates whenever the configuration changes. */ @@ -157,9 +196,24 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call } /** - * Tries to the move the pinned stack to the given {@param bounds}. + * Tries to move the pinned stack to the given {@param bounds}. */ void movePip(Rect toBounds) { + movePip(toBounds, false /* isDragging */); + } + + /** + * Tries to move the pinned stack to the given {@param bounds}. + * + * @param isDragging Whether this movement is the result of a drag touch gesture. If so, we + * won't notify the floating content coordinator of this move, since that will + * happen when the gesture ends. + */ + void movePip(Rect toBounds, boolean isDragging) { + if (!isDragging) { + mFloatingContentCoordinator.onContentMoved(this); + } + cancelAnimations(); resizePipUnchecked(toBounds); mBounds.set(toBounds); @@ -211,6 +265,18 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call }); } + /** Sets the movement bounds to use to constrain PIP position animations. */ + void setCurrentMovementBounds(Rect movementBounds) { + mMovementBounds.set(movementBounds); + rebuildFlingConfigs(); + + // The movement bounds represent the area within which we can move PIP's top-left position. + // The allowed area for all of PIP is those bounds plus PIP's width and height. + mFloatingAllowedArea.set(mMovementBounds); + mFloatingAllowedArea.right += mBounds.width(); + mFloatingAllowedArea.bottom += mBounds.height(); + } + /** * @return the PiP bounds. */ @@ -221,11 +287,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * @return the closest minimized PiP bounds. */ - Rect getClosestMinimizedBounds(Rect stackBounds, Rect movementBounds) { + Rect getClosestMinimizedBounds(Rect stackBounds) { Point displaySize = new Point(); mContext.getDisplay().getRealSize(displaySize); - Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, stackBounds); - mSnapAlgorithm.applyMinimizedOffset(toBounds, movementBounds, displaySize, mStableInsets); + Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mMovementBounds, stackBounds); + mSnapAlgorithm.applyMinimizedOffset(toBounds, mMovementBounds, displaySize, mStableInsets); return toBounds; } @@ -264,11 +330,10 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * Animates the PiP to the minimized state, slightly offscreen. */ - void animateToClosestMinimizedState(Rect movementBounds, @Nullable Runnable updateAction) { - final Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds); - - prepareForBoundsAnimation(movementBounds); + void animateToClosestMinimizedState(@Nullable Runnable updateAction) { + final Rect toBounds = getClosestMinimizedBounds(mBounds); + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig) .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig); @@ -285,10 +350,8 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call * Flings the PiP to the closest snap target. */ void flingToSnapTarget( - float velocityX, float velocityY, Rect movementBounds, Runnable updateAction, - @Nullable Runnable endAction) { - prepareForBoundsAnimation(movementBounds); - + float velocityX, float velocityY, Runnable updateAction, @Nullable Runnable endAction) { + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator .flingThenSpring( FloatProperties.RECT_X, velocityX, mFlingConfigX, mSpringConfig, @@ -298,21 +361,39 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call .addUpdateListener((target, values) -> updateAction.run()) .withEndActions(endAction); + final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right; + final float estimatedFlingYEndValue = + PhysicsAnimator.estimateFlingEndValue(mBounds.top, velocityY, mFlingConfigY); + + setAnimatingToBounds(new Rect( + (int) xEndValue, + (int) estimatedFlingYEndValue, + (int) xEndValue + mBounds.width(), + (int) estimatedFlingYEndValue + mBounds.height())); + startBoundsAnimation(); } /** * Animates the PiP to the closest snap target. */ - void animateToClosestSnapTarget(Rect movementBounds) { - prepareForBoundsAnimation(movementBounds); + void animateToClosestSnapTarget() { + final Rect newBounds = mSnapAlgorithm.findClosestSnapBounds(mMovementBounds, mBounds); + animateToBounds(newBounds, mSpringConfig); + } - final Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds); + /** + * Animates PIP to the provided bounds, using physics animations and the given spring + * configuration + */ + void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) { + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator - .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig) - .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig); - + .spring(FloatProperties.RECT_X, bounds.left, springConfig) + .spring(FloatProperties.RECT_Y, bounds.top, springConfig); startBoundsAnimation(); + + setAnimatingToBounds(bounds); } /** @@ -323,9 +404,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond(); final Point dismissEndPoint = getDismissEndPoint(mBounds, velocityX, velocityY, isFling); - // Set the animated bounds to start at the current bounds. We don't need to rebuild the - // fling configs here via prepareForBoundsAnimation, since animateDismiss isn't provided - // with new movement bounds. mAnimatedBounds.set(mBounds); // Animate to the dismiss end point, and then dismiss PIP. @@ -366,9 +444,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call currentMovementBounds); } mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction); + if (minimized) { - normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); + normalBounds = getClosestMinimizedBounds(normalBounds); } + if (immediate) { movePip(normalBounds); } else { @@ -400,19 +480,15 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call */ private void cancelAnimations() { mAnimatedBoundsPhysicsAnimator.cancel(); + mAnimatingToBounds.setEmpty(); } - /** - * Set new fling configs whose min/max values respect the given movement bounds, and set the - * animated bounds to PIP's current 'real' bounds. - */ - private void prepareForBoundsAnimation(Rect movementBounds) { + /** Set new fling configs whose min/max values respect the given movement bounds. */ + private void rebuildFlingConfigs() { mFlingConfigX = new PhysicsAnimator.FlingConfig( - DEFAULT_FRICTION, movementBounds.left, movementBounds.right); + DEFAULT_FRICTION, mMovementBounds.left, mMovementBounds.right); mFlingConfigY = new PhysicsAnimator.FlingConfig( - DEFAULT_FRICTION, movementBounds.top, movementBounds.bottom); - - mAnimatedBounds.set(mBounds); + DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom); } /** @@ -432,6 +508,16 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call } /** + * Notifies the floating coordinator that we're moving, and sets {@link #mAnimatingToBounds} so + * we return these bounds from + * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}. + */ + private void setAnimatingToBounds(Rect bounds) { + mAnimatingToBounds = bounds; + mFloatingContentCoordinator.onContentMoved(this); + } + + /** * Directly resizes the PiP to the given {@param bounds}. */ private void resizePipUnchecked(Rect toBounds) { @@ -459,6 +545,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call args.arg1 = toBounds; args.argi1 = duration; mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); + setAnimatingToBounds(toBounds); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 924edb6fe312..8e588e67861c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -47,6 +47,7 @@ import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.util.FloatingContentCoordinator; import java.io.PrintWriter; @@ -127,6 +128,7 @@ public class PipTouchHandler { // Touch state private final PipTouchState mTouchState; private final FlingAnimationUtils mFlingAnimationUtils; + private final FloatingContentCoordinator mFloatingContentCoordinator; private final PipMotionHelper mMotionHelper; private PipTouchGesture mGesture; @@ -152,7 +154,7 @@ public class PipTouchHandler { @Override public void onPipMinimize() { setMinimizedStateInternal(true); - mMotionHelper.animateToClosestMinimizedState(mMovementBounds, null /* updateAction */); + mMotionHelper.animateToClosestMinimizedState(null /* updateAction */); } @Override @@ -172,7 +174,8 @@ public class PipTouchHandler { public PipTouchHandler(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, InputConsumerController inputConsumerController, - PipBoundsHandler pipBoundsHandler) { + PipBoundsHandler pipBoundsHandler, + FloatingContentCoordinator floatingContentCoordinator) { // Initialize the Pip input consumer mContext = context; @@ -188,7 +191,7 @@ public class PipTouchHandler { 2.5f); mGesture = new DefaultPipTouchGesture(); mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mActivityTaskManager, - mMenuController, mSnapAlgorithm, mFlingAnimationUtils); + mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator); mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper); mTouchState = new PipTouchState(mViewConfig, mHandler, @@ -207,6 +210,7 @@ public class PipTouchHandler { inputConsumerController.setRegistrationListener(this::onRegistrationChanged); mPipBoundsHandler = pipBoundsHandler; + mFloatingContentCoordinator = floatingContentCoordinator; mConnection = new PipAccessibilityInteractionConnection(mMotionHelper, this::onAccessibilityShowMenu, mHandler); } @@ -228,15 +232,18 @@ public class PipTouchHandler { } public void onActivityPinned() { - cleanUp(); + cleanUpDismissTarget(); mShowPipMenuOnAnimationEnd = true; mPipResizeGestureHandler.onActivityPinned(); + mFloatingContentCoordinator.onContentAdded(mMotionHelper); } public void onActivityUnpinned(ComponentName topPipActivity) { if (topPipActivity == null) { // Clean up state after the last PiP activity is removed - cleanUp(); + cleanUpDismissTarget(); + + mFloatingContentCoordinator.onContentRemoved(mMotionHelper); } mPipResizeGestureHandler.onActivityUnpinned(); } @@ -501,8 +508,7 @@ public class PipTouchHandler { if (fromController) { if (isMinimized) { // Move the PiP to the new bounds immediately if minimized - mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds, - mMovementBounds)); + mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds)); } } else if (mPinnedStackController != null) { try { @@ -654,7 +660,7 @@ public class PipTouchHandler { mTmpBounds.set(mMotionHelper.getBounds()); mTmpBounds.offsetTo((int) left, (int) top); - mMotionHelper.movePip(mTmpBounds); + mMotionHelper.movePip(mTmpBounds, true /* isDragging */); if (mEnableDimissDragToEdge) { updateDismissFraction(); @@ -724,7 +730,6 @@ public class PipTouchHandler { mMenuController.hideMenu(); } else { mMotionHelper.animateToClosestMinimizedState( - mMovementBounds, PipTouchHandler.this::updateDismissFraction /* updateAction */); } return true; @@ -748,16 +753,15 @@ public class PipTouchHandler { } if (isFling) { - mMotionHelper.flingToSnapTarget( - vel.x, vel.y, mMovementBounds, + mMotionHelper.flingToSnapTarget(vel.x, vel.y, PipTouchHandler.this::updateDismissFraction /* updateAction */, endAction /* endAction */); } else { - mMotionHelper.animateToClosestSnapTarget(mMovementBounds); + mMotionHelper.animateToClosestSnapTarget(); } } else if (mIsMinimized) { // This was a tap, so no longer minimized - mMotionHelper.animateToClosestSnapTarget(mMovementBounds); + mMotionHelper.animateToClosestSnapTarget(); setMinimizedStateInternal(false); } else if (mTouchState.isDoubleTap()) { // Expand to fullscreen if this is a double tap @@ -789,6 +793,7 @@ public class PipTouchHandler { : mNormalMovementBounds; mPipBoundsHandler.setMinEdgeSize( isMenuExpanded ? mExpandedShortestEdgeSize : 0); + mMotionHelper.setCurrentMovementBounds(mMovementBounds); } /** @@ -800,16 +805,6 @@ public class PipTouchHandler { } /** - * Resets some states related to the touch handling. - */ - private void cleanUp() { - if (mIsMinimized) { - setMinimizedStateInternal(false); - } - cleanUpDismissTarget(); - } - - /** * @return whether the menu will resize as a part of showing the full menu. */ private boolean willResizeMenu() { |