Merge "Add drag down to dismiss pip as a dismiss option"
This commit is contained in:
@@ -56,7 +56,8 @@ public class PipMotionHelper {
|
||||
|
||||
private static final int DEFAULT_MOVE_STACK_DURATION = 225;
|
||||
private static final int SNAP_STACK_DURATION = 225;
|
||||
private static final int DISMISS_STACK_DURATION = 375;
|
||||
private static final int DRAG_TO_TARGET_DISMISS_STACK_DURATION = 375;
|
||||
private static final int DRAG_TO_DISMISS_STACK_DURATION = 175;
|
||||
private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
|
||||
private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
|
||||
private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 300;
|
||||
@@ -65,6 +66,8 @@ public class PipMotionHelper {
|
||||
|
||||
// The fraction of the stack width that the user has to drag offscreen to minimize the PiP
|
||||
private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.2f;
|
||||
// The fraction of the stack height that the user has to drag offscreen to minimize the PiP
|
||||
private static final float DISMISS_OFFSCREEN_FRACTION = 0.35f;
|
||||
|
||||
private Context mContext;
|
||||
private IActivityManager mActivityManager;
|
||||
@@ -193,6 +196,19 @@ public class PipMotionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the PiP at the current bounds should be dismissed.
|
||||
*/
|
||||
boolean shouldDismissPip() {
|
||||
Point displaySize = new Point();
|
||||
mContext.getDisplay().getRealSize(displaySize);
|
||||
if (mBounds.bottom > displaySize.y) {
|
||||
float offscreenFraction = (float) (mBounds.bottom - displaySize.y) / mBounds.height();
|
||||
return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flings the minimized PiP to the closest minimized snap target.
|
||||
*/
|
||||
@@ -297,16 +313,38 @@ public class PipMotionHelper {
|
||||
resizeAndAnimatePipUnchecked(toBounds, IME_SHIFT_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the dismissal of the PiP off the edge of the screen.
|
||||
*/
|
||||
Rect animateDragToEdgeDismiss(Rect pipBounds) {
|
||||
cancelAnimations();
|
||||
Point displaySize = new Point();
|
||||
mContext.getDisplay().getRealSize(displaySize);
|
||||
Rect toBounds = new Rect(pipBounds);
|
||||
toBounds.offset(0, displaySize.y - pipBounds.top);
|
||||
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DRAG_TO_DISMISS_STACK_DURATION,
|
||||
FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
|
||||
mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dismissPip();
|
||||
}
|
||||
});
|
||||
mBoundsAnimator.start();
|
||||
return toBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the dismissal of the PiP over the dismiss target bounds.
|
||||
*/
|
||||
Rect animateDismissFromDrag(Rect dismissBounds) {
|
||||
Rect animateDragToTargetDismiss(Rect dismissBounds) {
|
||||
cancelAnimations();
|
||||
Rect toBounds = new Rect(dismissBounds.centerX(),
|
||||
dismissBounds.centerY(),
|
||||
dismissBounds.centerX() + 1,
|
||||
dismissBounds.centerY() + 1);
|
||||
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DISMISS_STACK_DURATION,
|
||||
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
|
||||
DRAG_TO_TARGET_DISMISS_STACK_DURATION,
|
||||
FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
|
||||
mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
|
||||
@@ -52,7 +52,8 @@ public class PipTouchHandler {
|
||||
private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200;
|
||||
|
||||
// Allow dragging the PIP to a location to close it
|
||||
private static final boolean ENABLE_DRAG_TO_DISMISS = false;
|
||||
private static final boolean ENABLE_DISMISS_DRAG_TO_TARGET = false;
|
||||
private static final boolean ENABLE_DISMISS_DRAG_TO_EDGE = false;
|
||||
|
||||
private final Context mContext;
|
||||
private final IActivityManager mActivityManager;
|
||||
@@ -78,7 +79,7 @@ public class PipTouchHandler {
|
||||
private Runnable mShowDismissAffordance = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (ENABLE_DRAG_TO_DISMISS) {
|
||||
if (ENABLE_DISMISS_DRAG_TO_TARGET) {
|
||||
mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
|
||||
}
|
||||
}
|
||||
@@ -378,7 +379,7 @@ public class PipTouchHandler {
|
||||
mMenuController.pokeMenu();
|
||||
}
|
||||
|
||||
if (ENABLE_DRAG_TO_DISMISS) {
|
||||
if (ENABLE_DISMISS_DRAG_TO_TARGET) {
|
||||
mDismissViewController.createDismissTarget();
|
||||
mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
|
||||
}
|
||||
@@ -394,7 +395,7 @@ public class PipTouchHandler {
|
||||
mSavedSnapFraction = -1f;
|
||||
}
|
||||
|
||||
if (touchState.startedDragging() && ENABLE_DRAG_TO_DISMISS) {
|
||||
if (touchState.startedDragging() && ENABLE_DISMISS_DRAG_TO_TARGET) {
|
||||
mHandler.removeCallbacks(mShowDismissAffordance);
|
||||
mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
|
||||
}
|
||||
@@ -408,11 +409,16 @@ public class PipTouchHandler {
|
||||
if (!touchState.allowDraggingOffscreen()) {
|
||||
left = Math.max(mMovementBounds.left, Math.min(mMovementBounds.right, left));
|
||||
}
|
||||
top = Math.max(mMovementBounds.top, Math.min(mMovementBounds.bottom, top));
|
||||
if (ENABLE_DISMISS_DRAG_TO_EDGE) {
|
||||
// Allow pip to move past bottom bounds
|
||||
top = Math.max(mMovementBounds.top, top);
|
||||
} else {
|
||||
top = Math.max(mMovementBounds.top, Math.min(mMovementBounds.bottom, top));
|
||||
}
|
||||
mTmpBounds.offsetTo((int) left, (int) top);
|
||||
mMotionHelper.movePip(mTmpBounds);
|
||||
|
||||
if (ENABLE_DRAG_TO_DISMISS) {
|
||||
if (ENABLE_DISMISS_DRAG_TO_TARGET) {
|
||||
mDismissViewController.updateDismissTarget(mTmpBounds);
|
||||
}
|
||||
return true;
|
||||
@@ -427,7 +433,7 @@ public class PipTouchHandler {
|
||||
}
|
||||
|
||||
try {
|
||||
if (ENABLE_DRAG_TO_DISMISS) {
|
||||
if (ENABLE_DISMISS_DRAG_TO_TARGET) {
|
||||
mHandler.removeCallbacks(mShowDismissAffordance);
|
||||
PointF vel = mTouchState.getVelocity();
|
||||
final float velocity = PointF.length(vel.x, vel.y);
|
||||
@@ -435,7 +441,7 @@ public class PipTouchHandler {
|
||||
&& velocity < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
|
||||
if (mDismissViewController.shouldDismiss(mMotionHelper.getBounds())) {
|
||||
Rect dismissBounds = mDismissViewController.getDismissBounds();
|
||||
mMotionHelper.animateDismissFromDrag(dismissBounds);
|
||||
mMotionHelper.animateDragToTargetDismiss(dismissBounds);
|
||||
MetricsLogger.action(mContext,
|
||||
MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
|
||||
METRIC_VALUE_DISMISSED_BY_DRAG);
|
||||
@@ -448,9 +454,17 @@ public class PipTouchHandler {
|
||||
}
|
||||
|
||||
if (touchState.isDragging()) {
|
||||
PointF vel = mTouchState.getVelocity();
|
||||
if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
|
||||
|| isHorizontalFlingTowardsCurrentEdge(vel))) {
|
||||
final boolean onLeft = mMotionHelper.getBounds().left < mMovementBounds.centerX();
|
||||
boolean isFlingToBot = isFlingTowardsEdge(touchState, 4 /* bottom */);
|
||||
if (ENABLE_DISMISS_DRAG_TO_EDGE
|
||||
&& (mMotionHelper.shouldDismissPip() || isFlingToBot)) {
|
||||
mMotionHelper.animateDragToEdgeDismiss(mMotionHelper.getBounds());
|
||||
MetricsLogger.action(mContext,
|
||||
MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
|
||||
METRIC_VALUE_DISMISSED_BY_DRAG);
|
||||
return true;
|
||||
} else if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
|
||||
|| isFlingTowardsEdge(touchState, onLeft ? 2 : 3))) {
|
||||
// Pip should be minimized
|
||||
setMinimizedStateInternal(true);
|
||||
if (mMenuController.isMenuVisible()) {
|
||||
@@ -475,6 +489,7 @@ public class PipTouchHandler {
|
||||
mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds);
|
||||
}
|
||||
|
||||
final PointF vel = mTouchState.getVelocity();
|
||||
final float velocity = PointF.length(vel.x, vel.y);
|
||||
if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
|
||||
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds);
|
||||
@@ -495,29 +510,39 @@ public class PipTouchHandler {
|
||||
};
|
||||
|
||||
/**
|
||||
* @return whether the gesture ending in the {@param vel} is fast enough to be a fling towards
|
||||
* the same edge the PIP is on. Used to identify a minimize gesture.
|
||||
* @return whether the gesture ending in {@param vel} is fast enough to be a fling and towards
|
||||
* the provided {@param edge} where:
|
||||
*
|
||||
* 1 = top
|
||||
* 2 = left
|
||||
* 3 = right
|
||||
* 4 = bottom
|
||||
*/
|
||||
private boolean isHorizontalFlingTowardsCurrentEdge(PointF vel) {
|
||||
final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
|
||||
final boolean isFling = PointF.length(vel.x, vel.y) > mFlingAnimationUtils
|
||||
.getMinVelocityPxPerSecond();
|
||||
final boolean towardsCurrentEdge = isOverEdge(true /* left */) && vel.x < 0
|
||||
|| isOverEdge(false /* right */) && vel.x > 0;
|
||||
return towardsCurrentEdge && isHorizontal && isFling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the given bounds are on the left or right edge (depending on
|
||||
* {@param checkLeft})
|
||||
*/
|
||||
private boolean isOverEdge(boolean checkLeft) {
|
||||
private boolean isFlingTowardsEdge(PipTouchState touchState, int edge) {
|
||||
final PointF vel = touchState.getVelocity();
|
||||
final PointF downPos = touchState.getDownTouchPosition();
|
||||
final Rect bounds = mMotionHelper.getBounds();
|
||||
if (checkLeft) {
|
||||
return bounds.left <= mMovementBounds.left;
|
||||
} else {
|
||||
return bounds.right >= mMovementBounds.right + bounds.width();
|
||||
final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
|
||||
final boolean isFling =
|
||||
PointF.length(vel.x, vel.y) > mFlingAnimationUtils.getMinVelocityPxPerSecond();
|
||||
if (!isFling) {
|
||||
return false;
|
||||
}
|
||||
switch (edge) {
|
||||
case 1: // top
|
||||
return !isHorizontal && vel.y < 0
|
||||
&& downPos.y <= mMovementBounds.top + bounds.height();
|
||||
case 2: // left
|
||||
return isHorizontal && vel.x < 0
|
||||
&& downPos.x <= mMovementBounds.left + bounds.width();
|
||||
case 3: // right
|
||||
return isHorizontal && vel.x > 0
|
||||
&& downPos.x >= mMovementBounds.right;
|
||||
case 4: // bottom
|
||||
return !isHorizontal && vel.y > 0
|
||||
&& downPos.y >= mMovementBounds.bottom;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -542,7 +567,7 @@ public class PipTouchHandler {
|
||||
pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
|
||||
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
|
||||
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
|
||||
pw.println(innerPrefix + "mEnableDragToDismiss=" + ENABLE_DRAG_TO_DISMISS);
|
||||
pw.println(innerPrefix + "mEnableDragToDismiss=" + ENABLE_DISMISS_DRAG_TO_TARGET);
|
||||
mSnapAlgorithm.dump(pw, innerPrefix);
|
||||
mTouchState.dump(pw, innerPrefix);
|
||||
mMotionHelper.dump(pw, innerPrefix);
|
||||
|
||||
@@ -169,6 +169,13 @@ public class PipTouchState {
|
||||
return mLastDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the down touch position.
|
||||
*/
|
||||
public PointF getDownTouchPosition() {
|
||||
return mDownTouch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the movement delta between the last handled touch event and the down touch
|
||||
* position.
|
||||
|
||||
Reference in New Issue
Block a user