diff options
| author | Andrei Stingaceanu <stg@google.com> | 2016-08-01 17:15:07 +0100 |
|---|---|---|
| committer | Andrei Stingaceanu <stg@google.com> | 2016-08-12 10:21:08 +0000 |
| commit | 3df24c31bbc41eabb661d642f1859b6fd5eb9660 (patch) | |
| tree | 3afa9d947d44fcd802c6a5b5f49ae8ce6731403f /core/java/android | |
| parent | e6c14fba027c9bced702653f09c6658ffeda1c30 (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.java | 63 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 35 |
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(); |
