summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Gilles Debunne <debunne@google.com> 2010-10-08 11:56:13 -0700
committer Gilles Debunne <debunne@google.com> 2010-10-08 14:02:37 -0700
commit528c64887e01dd6a9d802d657838499b9fac0cb2 (patch)
tree498fde7b13854dda20b4f32e61f15ce0beeb5d68
parenta2a1ca42bc07af77a8a10b714517d006cb66c36a (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.java65
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();