Merge "Adjustments to PIP position while flinging" into oc-dr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
176f2533a1
@@ -49,9 +49,6 @@ public class PipSnapAlgorithm {
|
|||||||
// Allows snapping on the long edge in each orientation and magnets towards corners
|
// Allows snapping on the long edge in each orientation and magnets towards corners
|
||||||
private static final int SNAP_MODE_LONG_EDGE_MAGNET_CORNERS = 4;
|
private static final int SNAP_MODE_LONG_EDGE_MAGNET_CORNERS = 4;
|
||||||
|
|
||||||
// The friction multiplier to control how slippery the PIP is when flung
|
|
||||||
private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
|
|
||||||
|
|
||||||
// Threshold to magnet to a corner
|
// Threshold to magnet to a corner
|
||||||
private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
|
private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
|
||||||
|
|
||||||
@@ -64,8 +61,8 @@ public class PipSnapAlgorithm {
|
|||||||
private final float mDefaultSizePercent;
|
private final float mDefaultSizePercent;
|
||||||
private final float mMinAspectRatioForMinSize;
|
private final float mMinAspectRatioForMinSize;
|
||||||
private final float mMaxAspectRatioForMinSize;
|
private final float mMaxAspectRatioForMinSize;
|
||||||
|
private final int mFlingDeceleration;
|
||||||
|
|
||||||
private Scroller mScroller;
|
|
||||||
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
|
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
|
||||||
|
|
||||||
private final int mMinimizedVisibleSize;
|
private final int mMinimizedVisibleSize;
|
||||||
@@ -81,6 +78,8 @@ public class PipSnapAlgorithm {
|
|||||||
mMaxAspectRatioForMinSize = res.getFloat(
|
mMaxAspectRatioForMinSize = res.getFloat(
|
||||||
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
|
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
|
||||||
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
|
||||||
|
mFlingDeceleration = mContext.getResources().getDimensionPixelSize(
|
||||||
|
com.android.internal.R.dimen.pip_fling_deceleration);
|
||||||
onConfigurationChanged();
|
onConfigurationChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,20 +106,97 @@ public class PipSnapAlgorithm {
|
|||||||
* those for the given {@param stackBounds}.
|
* those for the given {@param stackBounds}.
|
||||||
*/
|
*/
|
||||||
public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds, float velocityX,
|
public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds, float velocityX,
|
||||||
float velocityY) {
|
float velocityY, Point dragStartPosition) {
|
||||||
final Rect finalStackBounds = new Rect(stackBounds);
|
final Rect intersectStackBounds = new Rect(stackBounds);
|
||||||
if (mScroller == null) {
|
final Point intersect = getEdgeIntersect(stackBounds, movementBounds, velocityX, velocityY,
|
||||||
final ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
|
dragStartPosition);
|
||||||
mScroller = new Scroller(mContext);
|
intersectStackBounds.offsetTo(intersect.x, intersect.y);
|
||||||
mScroller.setFriction(viewConfig.getScrollFriction() * SCROLL_FRICTION_MULTIPLIER);
|
return findClosestSnapBounds(movementBounds, intersectStackBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The point along the {@param movementBounds} that the PIP would intersect with based
|
||||||
|
* on the provided {@param velX}, {@param velY} along with the position of the PIP when
|
||||||
|
* the gesture started, {@param dragStartPosition}.
|
||||||
|
*/
|
||||||
|
public Point getEdgeIntersect(Rect stackBounds, Rect movementBounds, float velX, float velY,
|
||||||
|
Point dragStartPosition) {
|
||||||
|
final boolean isLandscape = mOrientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||||
|
final int x = stackBounds.left;
|
||||||
|
final int y = stackBounds.top;
|
||||||
|
|
||||||
|
// Find the line of movement the PIP is on. Line defined by: y = slope * x + yIntercept
|
||||||
|
final float slope = velY / velX; // slope = rise / run
|
||||||
|
final float yIntercept = y - slope * x; // rearrange line equation for yIntercept
|
||||||
|
// The PIP can have two intercept points:
|
||||||
|
// 1) Where the line intersects with one of the edges of the screen (vertical line)
|
||||||
|
Point vertPoint = new Point();
|
||||||
|
// 2) Where the line intersects with the top or bottom of the screen (horizontal line)
|
||||||
|
Point horizPoint = new Point();
|
||||||
|
|
||||||
|
// Find the vertical line intersection, x will be one of the edges
|
||||||
|
vertPoint.x = velX > 0 ? movementBounds.right : movementBounds.left;
|
||||||
|
// Sub in x in our line equation to determine y position
|
||||||
|
vertPoint.y = findY(slope, yIntercept, vertPoint.x);
|
||||||
|
|
||||||
|
// Find the horizontal line intersection, y will be the top or bottom of the screen
|
||||||
|
horizPoint.y = velY > 0 ? movementBounds.bottom : movementBounds.top;
|
||||||
|
// Sub in y in our line equation to determine x position
|
||||||
|
horizPoint.x = findX(slope, yIntercept, horizPoint.y);
|
||||||
|
|
||||||
|
// Now pick one of these points -- first determine if we're flinging along the current edge.
|
||||||
|
// Only fling along current edge if it's a direction with space for the PIP to move to
|
||||||
|
int maxDistance;
|
||||||
|
if (isLandscape) {
|
||||||
|
maxDistance = velX > 0
|
||||||
|
? movementBounds.right - stackBounds.left
|
||||||
|
: stackBounds.left - movementBounds.left;
|
||||||
|
} else {
|
||||||
|
maxDistance = velY > 0
|
||||||
|
? movementBounds.bottom - stackBounds.top
|
||||||
|
: stackBounds.top - movementBounds.top;
|
||||||
}
|
}
|
||||||
mScroller.fling(stackBounds.left, stackBounds.top,
|
if (maxDistance > 0) {
|
||||||
(int) velocityX, (int) velocityY,
|
// Only fling along the current edge if the start and end point are on the same side
|
||||||
movementBounds.left, movementBounds.right,
|
final int startPoint = isLandscape ? dragStartPosition.y : dragStartPosition.x;
|
||||||
movementBounds.top, movementBounds.bottom);
|
final int endPoint = isLandscape ? horizPoint.y : horizPoint.x;
|
||||||
finalStackBounds.offsetTo(mScroller.getFinalX(), mScroller.getFinalY());
|
final int center = movementBounds.centerX();
|
||||||
mScroller.abortAnimation();
|
if ((startPoint < center && endPoint < center)
|
||||||
return findClosestSnapBounds(movementBounds, finalStackBounds);
|
|| (startPoint > center && endPoint > center)) {
|
||||||
|
// We are flinging along the current edge, figure out how far it should travel
|
||||||
|
// based on velocity and assumed deceleration.
|
||||||
|
int distance = (int) (0 - Math.pow(isLandscape ? velX : velY, 2))
|
||||||
|
/ (2 * mFlingDeceleration);
|
||||||
|
distance = Math.min(distance, maxDistance);
|
||||||
|
// Adjust the point for the distance
|
||||||
|
if (isLandscape) {
|
||||||
|
horizPoint.x = stackBounds.left + (velX > 0 ? distance : -distance);
|
||||||
|
} else {
|
||||||
|
horizPoint.y = stackBounds.top + (velY > 0 ? distance : -distance);
|
||||||
|
}
|
||||||
|
return horizPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we're not flinging along the current edge, find the closest point instead.
|
||||||
|
final double distanceVert = Math.hypot(vertPoint.x - x, vertPoint.y - y);
|
||||||
|
final double distanceHoriz = Math.hypot(horizPoint.x - x, horizPoint.y - y);
|
||||||
|
// Ensure that we're actually going somewhere
|
||||||
|
if (distanceVert == 0) {
|
||||||
|
return horizPoint;
|
||||||
|
}
|
||||||
|
if (distanceHoriz == 0) {
|
||||||
|
return vertPoint;
|
||||||
|
}
|
||||||
|
// Otherwise use the closest point
|
||||||
|
return Math.abs(distanceVert) > Math.abs(distanceHoriz) ? horizPoint : vertPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findY(float slope, float yIntercept, float x) {
|
||||||
|
return (int) ((slope * x) + yIntercept);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findX(float slope, float yIntercept, float y) {
|
||||||
|
return (int) ((y - yIntercept) / slope);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -67,6 +67,9 @@
|
|||||||
<!-- The amount to leave on-screen when the PIP is minimized. -->
|
<!-- The amount to leave on-screen when the PIP is minimized. -->
|
||||||
<dimen name="pip_minimized_visible_size">48dp</dimen>
|
<dimen name="pip_minimized_visible_size">48dp</dimen>
|
||||||
|
|
||||||
|
<!-- The the PIP decelerates at while moving from a fling. -->
|
||||||
|
<dimen name="pip_fling_deceleration">-3000dp</dimen>
|
||||||
|
|
||||||
<!-- Min width for a tablet device -->
|
<!-- Min width for a tablet device -->
|
||||||
<dimen name="min_xlarge_screen_width">800dp</dimen>
|
<dimen name="min_xlarge_screen_width">800dp</dimen>
|
||||||
|
|
||||||
|
|||||||
@@ -1583,6 +1583,7 @@
|
|||||||
<java-symbol type="dimen" name="docked_stack_divider_insets" />
|
<java-symbol type="dimen" name="docked_stack_divider_insets" />
|
||||||
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
|
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
|
||||||
<java-symbol type="dimen" name="pip_minimized_visible_size" />
|
<java-symbol type="dimen" name="pip_minimized_visible_size" />
|
||||||
|
<java-symbol type="dimen" name="pip_fling_deceleration" />
|
||||||
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
|
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
|
||||||
<java-symbol type="integer" name="config_pictureInPictureSnapMode" />
|
<java-symbol type="integer" name="config_pictureInPictureSnapMode" />
|
||||||
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
|
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
|
||||||
|
|||||||
@@ -241,14 +241,14 @@ public class PipMotionHelper implements Handler.Callback {
|
|||||||
/**
|
/**
|
||||||
* Flings the minimized PiP to the closest minimized snap target.
|
* Flings the minimized PiP to the closest minimized snap target.
|
||||||
*/
|
*/
|
||||||
Rect flingToMinimizedState(float velocityY, Rect movementBounds) {
|
Rect flingToMinimizedState(float velocityY, Rect movementBounds, Point dragStartPosition) {
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
// We currently only allow flinging the minimized stack up and down, so just lock the
|
// We currently only allow flinging the minimized stack up and down, so just lock the
|
||||||
// movement bounds to the current stack bounds horizontally
|
// movement bounds to the current stack bounds horizontally
|
||||||
movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
|
movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
|
||||||
movementBounds.bottom);
|
movementBounds.bottom);
|
||||||
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
|
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
|
||||||
0 /* velocityX */, velocityY);
|
0 /* velocityX */, velocityY, dragStartPosition);
|
||||||
if (!mBounds.equals(toBounds)) {
|
if (!mBounds.equals(toBounds)) {
|
||||||
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
|
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
|
||||||
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
|
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
|
||||||
@@ -281,10 +281,11 @@ public class PipMotionHelper implements Handler.Callback {
|
|||||||
* Flings the PiP to the closest snap target.
|
* Flings the PiP to the closest snap target.
|
||||||
*/
|
*/
|
||||||
Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
|
Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
|
||||||
AnimatorUpdateListener updateListener, AnimatorListener listener) {
|
AnimatorUpdateListener updateListener, AnimatorListener listener,
|
||||||
|
Point startPosition) {
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
|
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
|
||||||
velocityX, velocityY);
|
velocityX, velocityY, startPosition);
|
||||||
if (!mBounds.equals(toBounds)) {
|
if (!mBounds.equals(toBounds)) {
|
||||||
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
|
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
|
||||||
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
|
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ public class PipTouchHandler {
|
|||||||
mDismissViewController = new PipDismissViewController(context);
|
mDismissViewController = new PipDismissViewController(context);
|
||||||
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
|
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
|
||||||
mTouchState = new PipTouchState(mViewConfig);
|
mTouchState = new PipTouchState(mViewConfig);
|
||||||
mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
|
mFlingAnimationUtils = new FlingAnimationUtils(context, 2.5f);
|
||||||
mGestures = new PipTouchGesture[] {
|
mGestures = new PipTouchGesture[] {
|
||||||
mDefaultMovementGesture
|
mDefaultMovementGesture
|
||||||
};
|
};
|
||||||
@@ -534,6 +534,7 @@ public class PipTouchHandler {
|
|||||||
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
|
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
|
||||||
// Whether the PiP was on the left side of the screen at the start of the gesture
|
// Whether the PiP was on the left side of the screen at the start of the gesture
|
||||||
private boolean mStartedOnLeft;
|
private boolean mStartedOnLeft;
|
||||||
|
private Point mStartPosition;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDown(PipTouchState touchState) {
|
public void onDown(PipTouchState touchState) {
|
||||||
@@ -541,7 +542,9 @@ public class PipTouchHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mStartedOnLeft = mMotionHelper.getBounds().left < mMovementBounds.centerX();
|
Rect bounds = mMotionHelper.getBounds();
|
||||||
|
mStartPosition = new Point(bounds.left, bounds.top);
|
||||||
|
mStartedOnLeft = bounds.left < mMovementBounds.centerX();
|
||||||
mMovementWithinMinimize = true;
|
mMovementWithinMinimize = true;
|
||||||
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
|
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
|
||||||
|
|
||||||
@@ -687,7 +690,8 @@ public class PipTouchHandler {
|
|||||||
|
|
||||||
if (isFling) {
|
if (isFling) {
|
||||||
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
|
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
|
||||||
mUpdateScrimListener, postAnimationCallback);
|
mUpdateScrimListener, postAnimationCallback,
|
||||||
|
mStartPosition);
|
||||||
} else {
|
} else {
|
||||||
mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
|
mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
|
||||||
postAnimationCallback);
|
postAnimationCallback);
|
||||||
|
|||||||
Reference in New Issue
Block a user