Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e7a97f6 authored by Mady Mellor's avatar Mady Mellor Committed by android-build-merger
Browse files

Merge "Adjustments to PIP position while flinging" into oc-dr1-dev

am: 176f2533

Change-Id: Ic5d38c862c155ac025884e53d688826b57829529
parents 029498f8 176f2533
Loading
Loading
Loading
Loading
+93 −17
Original line number Original line Diff line number Diff line
@@ -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);
        }
    }
        mScroller.fling(stackBounds.left, stackBounds.top,

                (int) velocityX, (int) velocityY,
    /**
                movementBounds.left, movementBounds.right,
     * @return The point along the {@param movementBounds} that the PIP would intersect with based
                movementBounds.top, movementBounds.bottom);
     *         on the provided {@param velX}, {@param velY} along with the position of the PIP when
        finalStackBounds.offsetTo(mScroller.getFinalX(), mScroller.getFinalY());
     *         the gesture started, {@param dragStartPosition}.
        mScroller.abortAnimation();
     */
        return findClosestSnapBounds(movementBounds, finalStackBounds);
    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;
        }
        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);
    }
    }


    /**
    /**
+3 −0
Original line number Original line Diff line number Diff line
@@ -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>


+1 −0
Original line number Original line Diff line number Diff line
@@ -1581,6 +1581,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" />
+5 −4
Original line number Original line Diff line number Diff line
@@ -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,
+7 −3
Original line number Original line Diff line number Diff line
@@ -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);