summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/java/android/view/ViewConfiguration.java18
-rw-r--r--core/java/android/widget/TextView.java75
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/public-staging.xml2
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">