diff options
| author | 2010-10-08 11:56:13 -0700 | |
|---|---|---|
| committer | 2010-10-08 14:02:37 -0700 | |
| commit | 528c64887e01dd6a9d802d657838499b9fac0cb2 (patch) | |
| tree | 498fde7b13854dda20b4f32e61f15ce0beeb5d68 | |
| parent | a2a1ca42bc07af77a8a10b714517d006cb66c36a (diff) | |
TextView cursor and selection improvements.
Insertion cursor handle no longer appears on empty text views (Bug 3075988).
Tapping on an unfocused TextView moves the insertion point at tapped position.
Bug fixes for trackball initiated text selection.
Change-Id: Ief246fd9a9f1eb745dcf9f0605e2ce53b5563f01
| -rw-r--r-- | core/java/android/widget/TextView.java | 65 |
1 files changed, 37 insertions, 28 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d1974dca36fe..44b14e76355c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6549,12 +6549,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int selEnd = getSelectionEnd(); if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) { + // If a tap was used to give focus to that view, move cursor at tap position. // Has to be done before onTakeFocus, which can be overloaded. - if (mLastTouchOffset >= 0) { - // Can happen when a TextView is displayed after its content has been deleted. - mLastTouchOffset = Math.min(mLastTouchOffset, mText.length()); - Selection.setSelection((Spannable) mText, mLastTouchOffset); - } + moveCursorToLastTapPosition(); if (mMovement != null) { mMovement.onTakeFocus(this, (Spannable) mText, direction); @@ -6613,8 +6610,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { terminateTextSelectionMode(); } - - mLastTouchOffset = -1; } startStopMarquee(focused); @@ -6626,6 +6621,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onFocusChanged(focused, direction, previouslyFocusedRect); } + private void moveCursorToLastTapPosition() { + if (mSelectionModifierCursorController != null) { + int mTapToFocusPosition = ((SelectionModifierCursorController) + mSelectionModifierCursorController).getMinTouchOffset(); + if (mTapToFocusPosition >= 0) { + // Safety check, should not be possible. + if (mTapToFocusPosition > mText.length()) { + Log.e(LOG_TAG, "Invalid tap focus position (" + mTapToFocusPosition + " vs " + + mText.length() + ")"); + mTapToFocusPosition = mText.length(); + } + Selection.setSelection((Spannable) mText, mTapToFocusPosition); + } + } + } + @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); @@ -6717,7 +6728,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Tapping outside stops selection mode, if any stopTextSelectionMode(); - if (mInsertionPointCursorController != null) { + if (mInsertionPointCursorController != null && mText.length() > 0) { mInsertionPointCursorController.show(); } } @@ -7255,7 +7266,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int minOffset, maxOffset; - if (mDPadCenterIsDown || mEnterKeyIsDown) { + if (mContextMenuTriggeredByKey) { minOffset = getSelectionStart(); maxOffset = getSelectionEnd(); } else { @@ -7286,6 +7297,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private String getWordForDictionary() { + if (!mContextMenuTriggeredByKey) { + moveCursorToLastTapPosition(); + } long wordLimits = getWordLimitsAt(getSelectionStart()); if (wordLimits >= 0) { int start = extractRangeStartFromLong(wordLimits); @@ -7336,6 +7350,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener protected void onCreateContextMenu(ContextMenu menu) { super.onCreateContextMenu(menu); boolean added = false; + mContextMenuTriggeredByKey = mDPadCenterIsDown || mEnterKeyIsDown; + // Problem with context menu on long press: the menu appears while the key in down and when + // the key is released, the view does not receive the key_up event. This ensures that the + // state is reset whenever the context menu action is displayed. + // mContextMenuTriggeredByKey saved that state so that it is available in + // onTextContextMenuItem. We cannot simply clear these flags in onTextContextMenuItem since + // it may not be called (if the user/ discards the context menu with the back key). + mDPadCenterIsDown = mEnterKeyIsDown = false; if (mIsInTextSelectionMode) { MenuHandler handler = new MenuHandler(); @@ -7361,21 +7383,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener added = true; } } else { - /* - if (!isFocused()) { - if (isFocusable() && mInput != null) { - if (canCopy()) { - MenuHandler handler = new MenuHandler(); - menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy). - setOnMenuItemClickListener(handler). - setAlphabeticShortcut('c'); - menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle); - } - } - - //return; - } - */ MenuHandler handler = new MenuHandler(); if (canSelectText()) { @@ -7529,7 +7536,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_ADD_TO_DICTIONARY: String word = getWordForDictionary(); - if (word != null) { Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT"); i.putExtra("word", word); @@ -8013,6 +8019,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener SelectionModifierCursorController() { mStartHandle = new HandleView(this, HandleView.LEFT); mEndHandle = new HandleView(this, HandleView.RIGHT); + mMinTouchOffset = mMaxTouchOffset = -1; } public void show() { @@ -8095,14 +8102,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public boolean onTouchEvent(MotionEvent event) { - if (isFocused() && isTextEditable()) { + // 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()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: final int x = (int) event.getX(); final int y = (int) event.getY(); // Remember finger down position, to be able to start selection from there - mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y); + mMinTouchOffset = mMaxTouchOffset = getOffset(x, y); break; @@ -8259,11 +8268,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private CursorController mInsertionPointCursorController; private CursorController mSelectionModifierCursorController; private boolean mIsInTextSelectionMode = false; - private int mLastTouchOffset = -1; // These are needed to desambiguate a long click. If the long click comes from ones of these, we // select from the current cursor position. Otherwise, select from long pressed position. private boolean mDPadCenterIsDown = false; private boolean mEnterKeyIsDown = false; + private boolean mContextMenuTriggeredByKey = false; // Created once and shared by different CursorController helper methods. // Only one cursor controller is active at any time which prevent race conditions. private static Rect sCursorControllerTempRect = new Rect(); |