diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java index bbce7b09e9b67..9e11451afa064 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java @@ -71,6 +71,7 @@ public class CropView extends View { private int mImageWidth; private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE; + private int mActivePointerId; // The starting value of mCurrentDraggingBoundary's crop, used to compute touch deltas. private float mMovementStartValue; private float mStartingY; // y coordinate of ACTION_DOWN @@ -138,35 +139,60 @@ public class CropView extends View { public boolean onTouchEvent(MotionEvent event) { int topPx = fractionToVerticalPixels(mCrop.top); int bottomPx = fractionToVerticalPixels(mCrop.bottom); - switch (event.getAction()) { + switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mCurrentDraggingBoundary = nearestBoundary(event, topPx, bottomPx, fractionToHorizontalPixels(mCrop.left), fractionToHorizontalPixels(mCrop.right)); if (mCurrentDraggingBoundary != CropBoundary.NONE) { + mActivePointerId = event.getPointerId(0); mStartingY = event.getY(); mStartingX = event.getX(); mMovementStartValue = getBoundaryPosition(mCurrentDraggingBoundary); - updateListener(event); + updateListener(MotionEvent.ACTION_DOWN, event.getX()); mMotionRange = getAllowedValues(mCurrentDraggingBoundary); } return true; case MotionEvent.ACTION_MOVE: if (mCurrentDraggingBoundary != CropBoundary.NONE) { - float deltaPx = isVertical(mCurrentDraggingBoundary) ? event.getY() - mStartingY - : event.getX() - mStartingX; - float delta = pixelDistanceToFraction((int) deltaPx, mCurrentDraggingBoundary); - setBoundaryPosition(mCurrentDraggingBoundary, - mMotionRange.clamp(mMovementStartValue + delta)); - updateListener(event); - invalidate(); + int pointerIndex = event.findPointerIndex(mActivePointerId); + if (pointerIndex >= 0) { + // Original pointer still active, do the move. + float deltaPx = isVertical(mCurrentDraggingBoundary) + ? event.getY(pointerIndex) - mStartingY + : event.getX(pointerIndex) - mStartingX; + float delta = pixelDistanceToFraction((int) deltaPx, + mCurrentDraggingBoundary); + setBoundaryPosition(mCurrentDraggingBoundary, + mMotionRange.clamp(mMovementStartValue + delta)); + updateListener(MotionEvent.ACTION_MOVE, event.getX(pointerIndex)); + invalidate(); + } return true; } + break; + case MotionEvent.ACTION_POINTER_DOWN: + if (mActivePointerId == event.getPointerId(event.getActionIndex()) + && mCurrentDraggingBoundary != CropBoundary.NONE) { + updateListener(MotionEvent.ACTION_DOWN, event.getX(event.getActionIndex())); + return true; + } + break; + case MotionEvent.ACTION_POINTER_UP: + if (mActivePointerId == event.getPointerId(event.getActionIndex()) + && mCurrentDraggingBoundary != CropBoundary.NONE) { + updateListener(MotionEvent.ACTION_UP, event.getX(event.getActionIndex())); + return true; + } + break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - if (mCurrentDraggingBoundary != CropBoundary.NONE) { - updateListener(event); + if (mCurrentDraggingBoundary != CropBoundary.NONE + && mActivePointerId == event.getPointerId(mActivePointerId)) { + updateListener(MotionEvent.ACTION_UP, event.getX(0)); + return true; } + break; } return super.onTouchEvent(event); } @@ -308,12 +334,29 @@ public class CropView extends View { return null; } - private void updateListener(MotionEvent event) { - if (mCropInteractionListener != null && (isVertical(mCurrentDraggingBoundary))) { + /** + * @param action either ACTION_DOWN, ACTION_UP or ACTION_MOVE. + * @param x coordinate of the relevant pointer. + */ + private void updateListener(int action, float x) { + if (mCropInteractionListener != null && isVertical(mCurrentDraggingBoundary)) { float boundaryPosition = getBoundaryPosition(mCurrentDraggingBoundary); - mCropInteractionListener.onCropMotionEvent(event, mCurrentDraggingBoundary, - boundaryPosition, fractionToVerticalPixels(boundaryPosition), - (mCrop.left + mCrop.right) / 2); + switch (action) { + case MotionEvent.ACTION_DOWN: + mCropInteractionListener.onCropDragStarted(mCurrentDraggingBoundary, + boundaryPosition, fractionToVerticalPixels(boundaryPosition), + (mCrop.left + mCrop.right) / 2, x); + break; + case MotionEvent.ACTION_MOVE: + mCropInteractionListener.onCropDragMoved(mCurrentDraggingBoundary, + boundaryPosition, fractionToVerticalPixels(boundaryPosition), + (mCrop.left + mCrop.right) / 2, x); + break; + case MotionEvent.ACTION_UP: + mCropInteractionListener.onCropDragComplete(); + break; + + } } } @@ -545,12 +588,11 @@ public class CropView extends View { * Listen for crop motion events and state. */ public interface CropInteractionListener { - /** - * Called whenever CropView has a MotionEvent that can impact the position of the crop - * boundaries. - */ - void onCropMotionEvent(MotionEvent event, CropBoundary boundary, float boundaryPosition, - int boundaryPositionPx, float horizontalCenter); + void onCropDragStarted(CropBoundary boundary, float boundaryPosition, + int boundaryPositionPx, float horizontalCenter, float x); + void onCropDragMoved(CropBoundary boundary, float boundaryPosition, + int boundaryPositionPx, float horizontalCenter, float x); + void onCropDragComplete(); } static class SavedState extends BaseSavedState { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java index 08cd91ccada54..34b40f79836b8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java @@ -28,7 +28,6 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.view.MotionEvent; import android.view.View; import android.view.ViewPropertyAnimator; @@ -148,49 +147,51 @@ public class MagnifierView extends View implements CropView.CropInteractionListe } @Override - public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary, - float cropPosition, int cropPositionPx, float horizontalCenter) { + public void onCropDragStarted(CropView.CropBoundary boundary, float boundaryPosition, + int boundaryPositionPx, float horizontalCenter, float x) { mCropBoundary = boundary; mLastCenter = horizontalCenter; - boolean touchOnRight = event.getX() > getParentWidth() / 2; + boolean touchOnRight = x > getParentWidth() / 2; float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth(); - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mLastCropPosition = cropPosition; - setTranslationY(cropPositionPx - getHeight() / 2); - setPivotX(getWidth() / 2); - setPivotY(getHeight() / 2); - setScaleX(0.2f); - setScaleY(0.2f); - setAlpha(0f); - setTranslationX((getParentWidth() - getWidth()) / 2); - setVisibility(View.VISIBLE); - mTranslationAnimator = - animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f); - mTranslationAnimator.setListener(mTranslationAnimatorListener); - mTranslationAnimator.start(); - break; - case MotionEvent.ACTION_MOVE: - // The touch is near the middle if it's within 10% of the center point. - // We don't want to animate horizontally if the touch is near the middle. - boolean nearMiddle = Math.abs(event.getX() - getParentWidth() / 2) - < getParentWidth() / 10f; - boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2; - if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) { - mTranslationAnimator = animate().translationX(translateXTarget); - mTranslationAnimator.setListener(mTranslationAnimatorListener); - mTranslationAnimator.start(); - } - mLastCropPosition = cropPosition; - setTranslationY(cropPositionPx - getHeight() / 2); - invalidate(); - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - animate().alpha(0).translationX((getParentWidth() - getWidth()) / 2).scaleX(0.2f) - .scaleY(0.2f).withEndAction(() -> setVisibility(View.INVISIBLE)).start(); - break; + mLastCropPosition = boundaryPosition; + setTranslationY(boundaryPositionPx - getHeight() / 2); + setPivotX(getWidth() / 2); + setPivotY(getHeight() / 2); + setScaleX(0.2f); + setScaleY(0.2f); + setAlpha(0f); + setTranslationX((getParentWidth() - getWidth()) / 2); + setVisibility(View.VISIBLE); + mTranslationAnimator = + animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f); + mTranslationAnimator.setListener(mTranslationAnimatorListener); + mTranslationAnimator.start(); + } + + @Override + public void onCropDragMoved(CropView.CropBoundary boundary, float boundaryPosition, + int boundaryPositionPx, float horizontalCenter, float x) { + boolean touchOnRight = x > getParentWidth() / 2; + float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth(); + // The touch is near the middle if it's within 10% of the center point. + // We don't want to animate horizontally if the touch is near the middle. + boolean nearMiddle = Math.abs(x - getParentWidth() / 2) + < getParentWidth() / 10f; + boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2; + if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) { + mTranslationAnimator = animate().translationX(translateXTarget); + mTranslationAnimator.setListener(mTranslationAnimatorListener); + mTranslationAnimator.start(); } + mLastCropPosition = boundaryPosition; + setTranslationY(boundaryPositionPx - getHeight() / 2); + invalidate(); + } + + @Override + public void onCropDragComplete() { + animate().alpha(0).translationX((getParentWidth() - getWidth()) / 2).scaleX(0.2f) + .scaleY(0.2f).withEndAction(() -> setVisibility(View.INVISIBLE)).start(); } private Path generateCheckerboard() {