summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mady Mellor <madym@google.com> 2017-06-28 23:53:23 +0000
committer android-build-merger <android-build-merger@google.com> 2017-06-28 23:53:23 +0000
commit3e7a97f6fab22aa05bc64a7a797ca2dad0390c2e (patch)
treef33bda960888ff77df2f044a768796106f4a378e
parent029498f856683af920817f8d806744f1ea124165 (diff)
parent176f2533a1768755e965b242333dac93ae17d26b (diff)
Merge "Adjustments to PIP position while flinging" into oc-dr1-dev
am: 176f2533a1 Change-Id: Ic5d38c862c155ac025884e53d688826b57829529
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java110
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java10
5 files changed, 109 insertions, 24 deletions
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 95d714f1c3c7..749d00c136ec 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -49,9 +49,6 @@ public class PipSnapAlgorithm {
// Allows snapping on the long edge in each orientation and magnets towards corners
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
private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
@@ -64,8 +61,8 @@ public class PipSnapAlgorithm {
private final float mDefaultSizePercent;
private final float mMinAspectRatioForMinSize;
private final float mMaxAspectRatioForMinSize;
+ private final int mFlingDeceleration;
- private Scroller mScroller;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
private final int mMinimizedVisibleSize;
@@ -81,6 +78,8 @@ public class PipSnapAlgorithm {
mMaxAspectRatioForMinSize = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
+ mFlingDeceleration = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.pip_fling_deceleration);
onConfigurationChanged();
}
@@ -107,20 +106,97 @@ public class PipSnapAlgorithm {
* those for the given {@param stackBounds}.
*/
public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds, float velocityX,
- float velocityY) {
- final Rect finalStackBounds = new Rect(stackBounds);
- if (mScroller == null) {
- final ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
- mScroller = new Scroller(mContext);
- mScroller.setFriction(viewConfig.getScrollFriction() * SCROLL_FRICTION_MULTIPLIER);
+ float velocityY, Point dragStartPosition) {
+ final Rect intersectStackBounds = new Rect(stackBounds);
+ final Point intersect = getEdgeIntersect(stackBounds, movementBounds, velocityX, velocityY,
+ dragStartPosition);
+ intersectStackBounds.offsetTo(intersect.x, intersect.y);
+ 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,
- (int) velocityX, (int) velocityY,
- movementBounds.left, movementBounds.right,
- movementBounds.top, movementBounds.bottom);
- finalStackBounds.offsetTo(mScroller.getFinalX(), mScroller.getFinalY());
- mScroller.abortAnimation();
- return findClosestSnapBounds(movementBounds, finalStackBounds);
+ if (maxDistance > 0) {
+ // Only fling along the current edge if the start and end point are on the same side
+ final int startPoint = isLandscape ? dragStartPosition.y : dragStartPosition.x;
+ final int endPoint = isLandscape ? horizPoint.y : horizPoint.x;
+ final int center = movementBounds.centerX();
+ if ((startPoint < center && endPoint < center)
+ || (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);
}
/**
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5e2334d20da1..fa33d567983e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -67,6 +67,9 @@
<!-- The amount to leave on-screen when the PIP is minimized. -->
<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 -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f39c24985b17..885f0a3a9ecc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1581,6 +1581,7 @@
<java-symbol type="dimen" name="docked_stack_divider_insets" />
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<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_pictureInPictureSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
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 b8771d7e0fb6..cebb22f07aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -241,14 +241,14 @@ public class PipMotionHelper implements Handler.Callback {
/**
* 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();
// We currently only allow flinging the minimized stack up and down, so just lock the
// movement bounds to the current stack bounds horizontally
movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
movementBounds.bottom);
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
- 0 /* velocityX */, velocityY);
+ 0 /* velocityX */, velocityY, dragStartPosition);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
@@ -281,10 +281,11 @@ public class PipMotionHelper implements Handler.Callback {
* Flings the PiP to the closest snap target.
*/
Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
- AnimatorUpdateListener updateListener, AnimatorListener listener) {
+ AnimatorUpdateListener updateListener, AnimatorListener listener,
+ Point startPosition) {
cancelAnimations();
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
- velocityX, velocityY);
+ velocityX, velocityY, startPosition);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
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 3682ae655f7c..9588b03b53bd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -185,7 +185,7 @@ public class PipTouchHandler {
mDismissViewController = new PipDismissViewController(context);
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
mTouchState = new PipTouchState(mViewConfig);
- mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
+ mFlingAnimationUtils = new FlingAnimationUtils(context, 2.5f);
mGestures = new PipTouchGesture[] {
mDefaultMovementGesture
};
@@ -534,6 +534,7 @@ public class PipTouchHandler {
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
// Whether the PiP was on the left side of the screen at the start of the gesture
private boolean mStartedOnLeft;
+ private Point mStartPosition;
@Override
public void onDown(PipTouchState touchState) {
@@ -541,7 +542,9 @@ public class PipTouchHandler {
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;
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
@@ -687,7 +690,8 @@ public class PipTouchHandler {
if (isFling) {
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
- mUpdateScrimListener, postAnimationCallback);
+ mUpdateScrimListener, postAnimationCallback,
+ mStartPosition);
} else {
mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
postAnimationCallback);