diff options
| -rw-r--r-- | core/api/current.txt | 1 | ||||
| -rw-r--r-- | core/api/system-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/view/ViewConfiguration.java | 18 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 75 | ||||
| -rw-r--r-- | core/res/res/values/config.xml | 3 | ||||
| -rw-r--r-- | core/res/res/values/public-staging.xml | 2 |
6 files changed, 69 insertions, 31 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 7bdaa2b8da68..bbc35dfd787e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -50911,6 +50911,7 @@ package android.view { method public int getScaledDoubleTapSlop(); method public int getScaledEdgeSlop(); method public int getScaledFadingEdgeLength(); + method public int getScaledHandwritingGestureLineMargin(); method public int getScaledHandwritingSlop(); method public float getScaledHorizontalScrollFactor(); method public int getScaledHoverSlop(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 761d9fa3841f..80e19f9377b4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -401,6 +401,7 @@ package android { public static final class R.dimen { field public static final int config_restrictedIconSize = 17104903; // 0x1050007 + field public static final int config_viewConfigurationHandwritingGestureLineMargin; } public static final class R.drawable { diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index e5a535b59eb6..f51d9bacc0a5 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -218,6 +218,11 @@ public class ViewConfiguration { private static final int WINDOW_TOUCH_SLOP = 16; /** + * Margin in dips around text line bounds where stylus handwriting gestures should be supported. + */ + private static final int HANDWRITING_GESTURE_LINE_MARGIN = 16; + + /** * Minimum velocity to initiate a fling, as measured in dips per second */ private static final int MINIMUM_FLING_VELOCITY = 50; @@ -338,6 +343,7 @@ public class ViewConfiguration { private final int mPagingTouchSlop; private final int mDoubleTapSlop; private final int mWindowTouchSlop; + private final int mHandwritingGestureLineMargin; private final float mAmbiguousGestureMultiplier; private final int mMaximumDrawingCacheSize; private final int mOverscrollDistance; @@ -381,6 +387,7 @@ public class ViewConfiguration { mPagingTouchSlop = PAGING_TOUCH_SLOP; mDoubleTapSlop = DOUBLE_TAP_SLOP; mWindowTouchSlop = WINDOW_TOUCH_SLOP; + mHandwritingGestureLineMargin = HANDWRITING_GESTURE_LINE_MARGIN; mAmbiguousGestureMultiplier = AMBIGUOUS_GESTURE_MULTIPLIER; //noinspection deprecation mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE; @@ -490,6 +497,9 @@ public class ViewConfiguration { mDoubleTapTouchSlop = mTouchSlop; + mHandwritingGestureLineMargin = res.getDimensionPixelSize( + com.android.internal.R.dimen.config_viewConfigurationHandwritingGestureLineMargin); + mMinimumFlingVelocity = res.getDimensionPixelSize( com.android.internal.R.dimen.config_viewMinFlingVelocity); mMaximumFlingVelocity = res.getDimensionPixelSize( @@ -796,6 +806,14 @@ public class ViewConfiguration { } /** + * @return margin in pixels around text line bounds where stylus handwriting gestures should be + * supported. + */ + public int getScaledHandwritingGestureLineMargin() { + return mHandwritingGestureLineMargin; + } + + /** * Interval for dispatching a recurring accessibility event in milliseconds. * This interval guarantees that a recurring event will be send at most once * during the {@link #getSendRecurringAccessibilityEventsInterval()} time frame. diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index ce5365acf1f4..a2e9faa81eeb 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -9391,12 +9391,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** @hide */ public int performHandwritingInsertGesture(@NonNull InsertGesture gesture) { PointF point = convertFromScreenToContentCoordinates(gesture.getInsertionPoint()); - int line = mLayout.getLineForVertical((int) point.y); - if (point.y < mLayout.getLineTop(line) - || point.y > mLayout.getLineBottom(line, /* includeLineSpacing= */ false)) { - return handleGestureFailure(gesture); - } - if (point.x < mLayout.getLineLeft(line) || point.x > mLayout.getLineRight(line)) { + int line = getLineForHandwritingGesture(point); + if (line == -1) { return handleGestureFailure(gesture); } int offset = mLayout.getOffsetForHorizontal(line, point.x); @@ -9412,27 +9408,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener PointF startPoint = convertFromScreenToContentCoordinates(gesture.getStartPoint()); PointF endPoint = convertFromScreenToContentCoordinates(gesture.getEndPoint()); - // The operation should be applied to the first line of text touched by the line joining - // the points. - int yMin = (int) Math.min(startPoint.y, endPoint.y); - int yMax = (int) Math.max(startPoint.y, endPoint.y); - int line = mLayout.getLineForVertical(yMin); - if (yMax < mLayout.getLineTop(line)) { - // Both points are above the top of the first line. - return handleGestureFailure(gesture); - } - if (yMin > mLayout.getLineBottom(line, /* includeLineSpacing= */ false)) { - if (line == mLayout.getLineCount() - 1 || yMax < mLayout.getLineTop(line + 1)) { - // The points are below the last line, or they are between two lines. + // The operation should be applied to the first line of text containing one of the points. + int startPointLine = getLineForHandwritingGesture(startPoint); + int endPointLine = getLineForHandwritingGesture(endPoint); + int line; + if (startPointLine == -1) { + if (endPointLine == -1) { return handleGestureFailure(gesture); - } else { - // Apply the operation to the next line. - line++; } - } - if (Math.max(startPoint.x, endPoint.x) < mLayout.getLineLeft(line) - || Math.min(startPoint.x, endPoint.x) > mLayout.getLineRight(line)) { - return handleGestureFailure(gesture); + line = endPointLine; + } else { + line = (endPointLine == -1) ? startPointLine : Math.min(startPointLine, endPointLine); } // The operation should be applied to all characters touched by the line joining the points. @@ -9479,12 +9465,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public int performHandwritingJoinOrSplitGesture(@NonNull JoinOrSplitGesture gesture) { PointF point = convertFromScreenToContentCoordinates(gesture.getJoinOrSplitPoint()); - int line = mLayout.getLineForVertical((int) point.y); - if (point.y < mLayout.getLineTop(line) - || point.y > mLayout.getLineBottom(line, /* includeLineSpacing= */ false)) { - return handleGestureFailure(gesture); - } - if (point.x < mLayout.getLineLeft(line) || point.x > mLayout.getLineRight(line)) { + int line = getLineForHandwritingGesture(point); + if (line == -1) { return handleGestureFailure(gesture); } @@ -9529,6 +9511,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED; } + /** + * Returns the closest line such that the point is either inside the line bounds or within + * {@link ViewConfiguration#getScaledHandwritingGestureLineMargin} of the line bounds. Returns + * -1 if the point is not within the margin of any line bounds. + */ + private int getLineForHandwritingGesture(PointF point) { + int line = mLayout.getLineForVertical((int) point.y); + int lineMargin = ViewConfiguration.get(mContext).getScaledHandwritingGestureLineMargin(); + if (line < mLayout.getLineCount() - 1 + && point.y > mLayout.getLineBottom(line) - lineMargin + && point.y + > (mLayout.getLineBottom(line, false) + mLayout.getLineBottom(line)) / 2f) { + // If a point is in the space between line i and line (i + 1), Layout#getLineForVertical + // returns i. If the point is within lineMargin of line (i + 1), and closer to line + // (i + 1) than line i, then the gesture operation should be applied to line (i + 1). + line++; + } else if (point.y < mLayout.getLineTop(line) - lineMargin + || point.y + > mLayout.getLineBottom(line, /* includeLineSpacing= */ false) + + lineMargin) { + // The point is not within lineMargin of a line. + return -1; + } + if (point.x < mLayout.getLineLeft(line) - lineMargin + || point.x > mLayout.getLineRight(line) + lineMargin) { + // The point is not within lineMargin of a line. + return -1; + } + return line; + } + @Nullable private Range<Integer> getRangeForRect(@NonNull RectF area, int granularity) { SegmentFinder segmentFinder; diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 90d84ddbccdb..ddc74add54a2 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2610,6 +2610,9 @@ movement threshold under which hover is considered "stationary". --> <dimen name="config_viewConfigurationHoverSlop">4dp</dimen> + <!-- Margin around text line bounds where stylus handwriting gestures should be supported. --> + <dimen name="config_viewConfigurationHandwritingGestureLineMargin">16dp</dimen> + <!-- Multiplier for gesture thresholds when a MotionEvent classification is ambiguous. --> <item name="config_ambiguousGestureMultiplier" format="float" type="dimen">2.0</item> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 89741effb945..d03d20697788 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -131,6 +131,8 @@ </staging-public-group> <staging-public-group type="dimen" first-id="0x01ca0000"> + <!-- @hide @SystemApi --> + <public name="config_viewConfigurationHandwritingGestureLineMargin" /> </staging-public-group> <staging-public-group type="color" first-id="0x01c90000"> |