diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java index f33517b8d210c..62d410b9ffade 100644 --- a/services/java/com/android/server/accessibility/ScreenMagnifier.java +++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java @@ -46,10 +46,9 @@ import android.view.Gravity; import android.view.IDisplayContentChangeListener; import android.view.IWindowManager; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; -import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; @@ -370,7 +369,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { public GestureDetector(Context context) { final float density = context.getResources().getDisplayMetrics().density; mScaledDetectPanningThreshold = DETECT_PANNING_THRESHOLD_DIP * density; - mScaleGestureDetector = new ScaleGestureDetector(context, this); + mScaleGestureDetector = new ScaleGestureDetector(this); } public void onMotionEvent(MotionEvent event) { @@ -409,7 +408,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { performScale(detector, true); clear(); transitionToState(STATE_SCALING); - return false; + return true; } mCurrPan = (float) MathUtils.dist( mScaleGestureDetector.getFocusX(), @@ -423,7 +422,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { performPan(detector, true); clear(); transitionToState(STATE_PANNING); - return false; + return true; } } break; case STATE_SCALING: { @@ -460,7 +459,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { @Override public void onScaleEnd(ScaleGestureDetector detector) { - /* do nothing */ + clear(); } public void clear() { @@ -1763,4 +1762,482 @@ public final class ScreenMagnifier implements EventStreamTransformation { updateDisplayInfo(); } } + + /** + * The listener for receiving notifications when gestures occur. + * If you want to listen for all the different gestures then implement + * this interface. If you only want to listen for a subset it might + * be easier to extend {@link SimpleOnScaleGestureListener}. + * + * An application will receive events in the following order: + *
Applications should pass a complete and consistent event stream to this method. + * A complete and consistent event stream involves all MotionEvents from the initial + * ACTION_DOWN to the final ACTION_UP or ACTION_CANCEL.
+ * + * @param event The event to process + * @return true if the event was processed and the detector wants to receive the + * rest of the MotionEvents in this event stream. + */ + public boolean onTouchEvent(MotionEvent event) { + boolean streamEnded = false; + boolean contextChanged = false; + int excludedPtrIdx = -1; + final int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: { + contextChanged = true; + } break; + case MotionEvent.ACTION_POINTER_UP: { + contextChanged = true; + excludedPtrIdx = event.getActionIndex(); + } break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + streamEnded = true; + } break; + } + + if (mInProgress && (contextChanged || streamEnded)) { + mListener.onScaleEnd(this); + mInProgress = false; + mPrevSpan = 0; + mPrevSpanX = 0; + mPrevSpanY = 0; + return true; + } + + final long currTime = mCurrTime; + + mFocusX = 0; + mFocusY = 0; + mCurrSpan = 0; + mCurrSpanX = 0; + mCurrSpanY = 0; + mCurrTime = 0; + mPrevTime = 0; + + if (!streamEnded) { + MinCircleFinder.Circle circle = + mMinCircleFinder.computeMinCircleAroundPointers(event); + mFocusX = circle.centerX; + mFocusY = circle.centerY; + + double sumSlope = 0; + final int pointerCount = event.getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + if (i == excludedPtrIdx) { + continue; + } + float x = event.getX(i) - mFocusX; + float y = event.getY(i) - mFocusY; + if (x == 0) { + x += 0.1f; + } + sumSlope += y / x; + } + final double avgSlope = sumSlope + / ((excludedPtrIdx < 0) ? pointerCount : pointerCount - 1); + + double angle = Math.atan(avgSlope); + mCurrSpan = 2 * circle.radius; + mCurrSpanX = (float) Math.abs((Math.cos(angle) * mCurrSpan)); + mCurrSpanY = (float) Math.abs((Math.sin(angle) * mCurrSpan)); + } + + if (contextChanged || mPrevSpan == 0 || mPrevSpanX == 0 || mPrevSpanY == 0) { + mPrevSpan = mCurrSpan; + mPrevSpanX = mCurrSpanX; + mPrevSpanY = mCurrSpanY; + } + + if (!mInProgress && mCurrSpan != 0 && !streamEnded) { + mInProgress = mListener.onScaleBegin(this); + } + + if (mInProgress) { + mPrevTime = (currTime != 0) ? currTime : event.getEventTime(); + mCurrTime = event.getEventTime(); + if (mCurrSpan == 0) { + mListener.onScaleEnd(this); + mInProgress = false; + } else { + if (mListener.onScale(this)) { + mPrevSpanX = mCurrSpanX; + mPrevSpanY = mCurrSpanY; + mPrevSpan = mCurrSpan; + } + } + } + + return true; + } + + /** + * Returns {@code true} if a scale gesture is in progress. + */ + public boolean isInProgress() { + return mInProgress; + } + + /** + * Get the X coordinate of the current gesture's focal point. + * If a gesture is in progress, the focal point is between + * each of the pointers forming the gesture. + * + * If {@link #isInProgress()} would return false, the result of this + * function is undefined. + * + * @return X coordinate of the focal point in pixels. + */ + public float getFocusX() { + return mFocusX; + } + + /** + * Get the Y coordinate of the current gesture's focal point. + * If a gesture is in progress, the focal point is between + * each of the pointers forming the gesture. + * + * If {@link #isInProgress()} would return false, the result of this + * function is undefined. + * + * @return Y coordinate of the focal point in pixels. + */ + public float getFocusY() { + return mFocusY; + } + + /** + * Return the average distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpan() { + return mCurrSpan; + } + + /** + * Return the average X distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpanX() { + return mCurrSpanX; + } + + /** + * Return the average Y distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpanY() { + return mCurrSpanY; + } + + /** + * Return the previous average distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpan() { + return mPrevSpan; + } + + /** + * Return the previous average X distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpanX() { + return mPrevSpanX; + } + + /** + * Return the previous average Y distance between each of the pointers forming the + * gesture in progress through the focal point. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpanY() { + return mPrevSpanY; + } + + /** + * Return the scaling factor from the previous scale event to the current + * event. This value is defined as + * ({@link #getCurrentSpan()} / {@link #getPreviousSpan()}). + * + * @return The current scaling factor. + */ + public float getScaleFactor() { + return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1; + } + + /** + * Return the time difference in milliseconds between the previous + * accepted scaling event and the current scaling event. + * + * @return Time difference since the last scaling event in milliseconds. + */ + public long getTimeDelta() { + return mCurrTime - mPrevTime; + } + + /** + * Return the event time of the current event being processed. + * + * @return Current event time in milliseconds. + */ + public long getEventTime() { + return mCurrTime; + } + } + + private static final class MinCircleFinder { + private final ArrayList