diff options
| author | 2011-07-11 18:26:19 -0700 | |
|---|---|---|
| committer | 2011-07-12 12:27:01 -0700 | |
| commit | bb588da7b16734c89618e91d7f6d53db39f1266c (patch) | |
| tree | 960ba524591e4cc2f9745d3f36558450fb0b03e8 | |
| parent | 8c55a9a57e4f13ec420c3de7b3abfdcf454f6633 (diff) | |
Refactored TextView selectable state methods.
There were inconsistencies across methods on how to decide if text is selectable.
Fleshed up textCanBeSelected to support all cases (including non editable textIsSelectable).
onTouchEvent removed from CursorController, test in SelectionModifierCursorController for
editable text is not needed since it is conditionned by an hasSelectionController().
Bug 5016955: protection in offset for text selection
Change-Id: I1e39f7c4a859476e0220e72a4e490b43e60b4a9a
| -rw-r--r-- | core/java/android/widget/TextView.java | 118 |
1 files changed, 54 insertions, 64 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 766b520f2b40..aae38090e8e1 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -16,11 +16,6 @@ package android.widget; -import com.android.internal.util.FastMath; -import com.android.internal.widget.EditableInputConnection; - -import org.xmlpull.v1.XmlPullParserException; - import android.R; import android.content.ClipData; import android.content.ClipData.Item; @@ -132,6 +127,11 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.RemoteViews.RemoteView; +import com.android.internal.util.FastMath; +import com.android.internal.widget.EditableInputConnection; + +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.lang.ref.WeakReference; import java.text.BreakIterator; @@ -1119,6 +1119,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } super.setEnabled(enabled); + prepareCursorControllers(); } /** @@ -2841,8 +2842,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Do not change the movement method for text that support text selection as it // would prevent an arbitrary cursor displacement. - final boolean hasTextSelection = this instanceof EditText || mTextIsSelectable; - if (mLinksClickable && !hasTextSelection) { + if (mLinksClickable && !textCanBeSelected()) { setMovementMethod(LinkMovementMethod.getInstance()); } } @@ -4228,7 +4228,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * {@link android.R.styleable#TextView_textIsSelectable} XML attribute to make this TextView * selectable (text is not selectable by default). * - * Note that the content of an EditText is always selectable. + * Note that this method simply returns the state of this flag. Although this flag has to be set + * in order to select text in non-editable TextView, the content of an {@link EditText} can + * always be selected, independently of the value of this flag. * * @return True if the text displayed in this TextView can be selected by the user. * @@ -4465,12 +4467,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener selStart = getSelectionStart(); selEnd = getSelectionEnd(); - if ((isCursorVisible() || mTextIsSelectable) && selStart >= 0 && isEnabled()) { + if (selStart >= 0) { if (mHighlightPath == null) mHighlightPath = new Path(); if (selStart == selEnd) { - if (!mTextIsSelectable && + if (isCursorVisible() && (SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK) < BLINK) { if (mHighlightPathBogus) { mHighlightPath.reset(); @@ -4489,7 +4491,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener highlight = mHighlightPath; drawCursor = mCursorCount > 0; } - } else { + } else if (textCanBeSelected()) { if (mHighlightPathBogus) { mHighlightPath.reset(); mLayout.getSelectionPath(selStart, selEnd, mHighlightPath); @@ -7450,9 +7452,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); - if (hasInsertionController()) { - getInsertionController().onTouchEvent(event); - } if (hasSelectionController()) { getSelectionController().onTouchEvent(event); } @@ -7880,7 +7879,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // prepareCursorController() relies on this method. // If you change this condition, make sure prepareCursorController is called anywhere // the value of this condition might be changed. - return mText instanceof Spannable && mMovement != null && mMovement.canSelectArbitrarily(); + if (mMovement == null || !mMovement.canSelectArbitrarily()) return false; + return isTextEditable() || (mTextIsSelectable && mText instanceof Spannable && isEnabled()); } private boolean canCut() { @@ -7968,6 +7968,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int minOffset = extractRangeStartFromLong(lastTouchOffsets); final int maxOffset = extractRangeEndFromLong(lastTouchOffsets); + // Safety check in case standard touch event handling has been bypassed + if (minOffset < 0 || minOffset >= mText.length()) return false; + if (maxOffset < 0 || maxOffset >= mText.length()) return false; + int selectionStart, selectionEnd; // If a URLSpan (web address, email, phone...) is found at that position, select it. @@ -9723,13 +9727,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void hide(); /** - * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller - * a chance to become active and/or visible. - * @param event The touch event - */ - public boolean onTouchEvent(MotionEvent event); - - /** * Called when the view is detached from window. Perform house keeping task, such as * stopping Runnable thread that would otherwise keep a reference on the context, thus * preventing the activity from being recycled. @@ -9756,10 +9753,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - public boolean onTouchEvent(MotionEvent ev) { - return false; - } - public void onTouchModeChanged(boolean isInTouchMode) { if (!isInTouchMode) { hide(); @@ -9818,52 +9811,49 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEndHandle != null) mEndHandle.hide(); } - public boolean onTouchEvent(MotionEvent event) { + public void onTouchEvent(MotionEvent event) { // This is done even when the View does not have focus, so that long presses can start // selection and tap can move cursor from this tap position. - if (isTextEditable() || mTextIsSelectable) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - final float x = event.getX(); - final float y = event.getY(); - - // Remember finger down position, to be able to start selection from there - mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y); - - // Double tap detection - long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime; - if (duration <= ViewConfiguration.getDoubleTapTimeout() && - isPositionOnText(x, y)) { - final float deltaX = x - mPreviousTapPositionX; - final float deltaY = y - mPreviousTapPositionY; - final float distanceSquared = deltaX * deltaX + deltaY * deltaY; - if (distanceSquared < mSquaredTouchSlopDistance) { - showSuggestions(); - mDiscardNextActionUp = true; - } + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + final float x = event.getX(); + final float y = event.getY(); + + // Remember finger down position, to be able to start selection from there + mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y); + + // Double tap detection + long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime; + if (duration <= ViewConfiguration.getDoubleTapTimeout() && + isPositionOnText(x, y)) { + final float deltaX = x - mPreviousTapPositionX; + final float deltaY = y - mPreviousTapPositionY; + final float distanceSquared = deltaX * deltaX + deltaY * deltaY; + if (distanceSquared < mSquaredTouchSlopDistance) { + showSuggestions(); + mDiscardNextActionUp = true; } + } - mPreviousTapPositionX = x; - mPreviousTapPositionY = y; + mPreviousTapPositionX = x; + mPreviousTapPositionY = y; - break; + break; - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_POINTER_UP: - // Handle multi-point gestures. Keep min and max offset positions. - // Only activated for devices that correctly handle multi-touch. - if (mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) { - updateMinAndMaxOffsets(event); - } - break; + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_POINTER_UP: + // Handle multi-point gestures. Keep min and max offset positions. + // Only activated for devices that correctly handle multi-touch. + if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) { + updateMinAndMaxOffsets(event); + } + break; - case MotionEvent.ACTION_UP: - mPreviousTapUpTime = SystemClock.uptimeMillis(); - break; - } + case MotionEvent.ACTION_UP: + mPreviousTapUpTime = SystemClock.uptimeMillis(); + break; } - return false; } /** |