Loading core/java/android/widget/TextView.java +37 −28 Original line number Diff line number Diff line Loading @@ -6554,12 +6554,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); Loading Loading @@ -6618,8 +6615,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { terminateTextSelectionMode(); } mLastTouchOffset = -1; } startStopMarquee(focused); Loading @@ -6631,6 +6626,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); Loading Loading @@ -6722,7 +6733,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(); } } Loading Loading @@ -7260,7 +7271,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int minOffset, maxOffset; if (mDPadCenterIsDown || mEnterKeyIsDown) { if (mContextMenuTriggeredByKey) { minOffset = getSelectionStart(); maxOffset = getSelectionEnd(); } else { Loading Loading @@ -7291,6 +7302,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); Loading Loading @@ -7341,6 +7355,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(); Loading @@ -7366,21 +7388,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()) { Loading Loading @@ -7534,7 +7541,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); Loading Loading @@ -8018,6 +8024,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() { Loading Loading @@ -8100,14 +8107,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; Loading Loading @@ -8264,11 +8273,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(); Loading Loading
core/java/android/widget/TextView.java +37 −28 Original line number Diff line number Diff line Loading @@ -6554,12 +6554,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); Loading Loading @@ -6618,8 +6615,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { terminateTextSelectionMode(); } mLastTouchOffset = -1; } startStopMarquee(focused); Loading @@ -6631,6 +6626,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); Loading Loading @@ -6722,7 +6733,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(); } } Loading Loading @@ -7260,7 +7271,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int minOffset, maxOffset; if (mDPadCenterIsDown || mEnterKeyIsDown) { if (mContextMenuTriggeredByKey) { minOffset = getSelectionStart(); maxOffset = getSelectionEnd(); } else { Loading Loading @@ -7291,6 +7302,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); Loading Loading @@ -7341,6 +7355,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(); Loading @@ -7366,21 +7388,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()) { Loading Loading @@ -7534,7 +7541,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); Loading Loading @@ -8018,6 +8024,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() { Loading Loading @@ -8100,14 +8107,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; Loading Loading @@ -8264,11 +8273,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(); Loading