summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorAndrei Stingaceanu <stg@google.com>2016-08-01 17:15:07 +0100
committerAndrei Stingaceanu <stg@google.com>2016-08-12 10:21:08 +0000
commit3df24c31bbc41eabb661d642f1859b6fd5eb9660 (patch)
tree3afa9d947d44fcd802c6a5b5f49ae8ce6731403f /core/java/android
parente6c14fba027c9bced702653f09c6658ffeda1c30 (diff)
TextView - fix ClickableSpans always triggering on touch up
* introduce GestureDetector to TextView * completely remove link click functionality from LinkMovementMethod (the interface does not state it provides click functionality) * intercept onSingleTapConfirmed and trigger onClick on the link if it exists (simplified duplicated functionality) * renamed a bunch of LinkMovementMethod variables because eyes hurt Bug: 23692690 Change-Id: Idaf3f3391328207f42521235fb5deb1a11c66aaa
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/text/method/LinkMovementMethod.java63
-rw-r--r--core/java/android/widget/TextView.java35
2 files changed, 52 insertions, 46 deletions
diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java
index 3855ff3ae44b..24c119f29d71 100644
--- a/core/java/android/text/method/LinkMovementMethod.java
+++ b/core/java/android/text/method/LinkMovementMethod.java
@@ -29,6 +29,9 @@ import android.widget.TextView;
/**
* A movement method that traverses links in the text buffer and scrolls if necessary.
* Supports clicking on links with DPad Center or Enter.
+ *
+ * <p>Note: Starting from Android 8.0 (API level 25) this class no longer handles the touch
+ * clicks.
*/
public class LinkMovementMethod extends ScrollingMovementMethod {
private static final int CLICK = 1;
@@ -98,14 +101,14 @@ public class LinkMovementMethod extends ScrollingMovementMethod {
int padding = widget.getTotalPaddingTop() +
widget.getTotalPaddingBottom();
- int areatop = widget.getScrollY();
- int areabot = areatop + widget.getHeight() - padding;
+ int areaTop = widget.getScrollY();
+ int areaBot = areaTop + widget.getHeight() - padding;
- int linetop = layout.getLineForVertical(areatop);
- int linebot = layout.getLineForVertical(areabot);
+ int lineTop = layout.getLineForVertical(areaTop);
+ int lineBot = layout.getLineForVertical(areaBot);
- int first = layout.getLineStart(linetop);
- int last = layout.getLineEnd(linebot);
+ int first = layout.getLineStart(lineTop);
+ int last = layout.getLineEnd(lineBot);
ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class);
@@ -141,46 +144,46 @@ public class LinkMovementMethod extends ScrollingMovementMethod {
break;
case UP:
- int beststart, bestend;
+ int bestStart, bestEnd;
- beststart = -1;
- bestend = -1;
+ bestStart = -1;
+ bestEnd = -1;
for (int i = 0; i < candidates.length; i++) {
int end = buffer.getSpanEnd(candidates[i]);
if (end < selEnd || selStart == selEnd) {
- if (end > bestend) {
- beststart = buffer.getSpanStart(candidates[i]);
- bestend = end;
+ if (end > bestEnd) {
+ bestStart = buffer.getSpanStart(candidates[i]);
+ bestEnd = end;
}
}
}
- if (beststart >= 0) {
- Selection.setSelection(buffer, bestend, beststart);
+ if (bestStart >= 0) {
+ Selection.setSelection(buffer, bestEnd, bestStart);
return true;
}
break;
case DOWN:
- beststart = Integer.MAX_VALUE;
- bestend = Integer.MAX_VALUE;
+ bestStart = Integer.MAX_VALUE;
+ bestEnd = Integer.MAX_VALUE;
for (int i = 0; i < candidates.length; i++) {
int start = buffer.getSpanStart(candidates[i]);
if (start > selStart || selStart == selEnd) {
- if (start < beststart) {
- beststart = start;
- bestend = buffer.getSpanEnd(candidates[i]);
+ if (start < bestStart) {
+ bestStart = start;
+ bestEnd = buffer.getSpanEnd(candidates[i]);
}
}
}
- if (bestend < Integer.MAX_VALUE) {
- Selection.setSelection(buffer, beststart, bestend);
+ if (bestEnd < Integer.MAX_VALUE) {
+ Selection.setSelection(buffer, bestStart, bestEnd);
return true;
}
@@ -195,8 +198,7 @@ public class LinkMovementMethod extends ScrollingMovementMethod {
MotionEvent event) {
int action = event.getAction();
- if (action == MotionEvent.ACTION_UP ||
- action == MotionEvent.ACTION_DOWN) {
+ if (action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
@@ -210,17 +212,12 @@ public class LinkMovementMethod extends ScrollingMovementMethod {
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
- ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
-
- if (link.length != 0) {
- if (action == MotionEvent.ACTION_UP) {
- link[0].onClick(widget);
- } else if (action == MotionEvent.ACTION_DOWN) {
- Selection.setSelection(buffer,
- buffer.getSpanStart(link[0]),
- buffer.getSpanEnd(link[0]));
- }
+ ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
+ if (links.length != 0) {
+ Selection.setSelection(buffer,
+ buffer.getSpanStart(links[0]),
+ buffer.getSpanEnd(links[0]));
return true;
} else {
Selection.removeSelection(buffer);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a6d004fd0ec9..6dafe34fdc13 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -114,6 +114,7 @@ import android.view.ActionMode;
import android.view.Choreographer;
import android.view.ContextMenu;
import android.view.DragEvent;
+import android.view.GestureDetector;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyCharacterMap;
@@ -650,6 +651,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
private Editor mEditor;
+ private final GestureDetector mClickableSpanOnClickGestureDetector;
+
private static final int DEVICE_PROVISIONED_UNKNOWN = 0;
private static final int DEVICE_PROVISIONED_NO = 1;
private static final int DEVICE_PROVISIONED_YES = 2;
@@ -1488,6 +1491,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
+
+ mClickableSpanOnClickGestureDetector = new GestureDetector(context,
+ new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ if (mLinksClickable && (mMovement != null) &&
+ (mMovement instanceof LinkMovementMethod
+ || (mAutoLinkMask != 0 && isTextSelectable()))) {
+ ClickableSpan[] links = ((Spannable) mText).getSpans(
+ getSelectionStart(), getSelectionEnd(), ClickableSpan.class);
+ if (links.length > 0) {
+ links[0].onClick(TextView.this);
+ return true;
+ }
+ }
+ return false;
+ }
+ });
}
private int[] parseDimensionArray(TypedArray dimens) {
@@ -8515,21 +8536,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mMovement != null) {
handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
}
+ handled |= mClickableSpanOnClickGestureDetector.onTouchEvent(event);
final boolean textIsSelectable = isTextSelectable();
- if (touchIsFinished && mLinksClickable && mAutoLinkMask != 0 && textIsSelectable) {
- // The LinkMovementMethod which should handle taps on links has not been installed
- // on non editable text that support text selection.
- // We reproduce its behavior here to open links for these.
- ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
- getSelectionEnd(), ClickableSpan.class);
-
- if (links.length > 0) {
- links[0].onClick(this);
- handled = true;
- }
- }
-
if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();