Skip to content

Commit 1614147

Browse files
author
Gilles Debunne
committed
SelectAllOnFocus shows a higlighted text. DO NOT MERGE.
Bug 3201383 Highlighted is different from selected, only the background is modified and selection mode is not started. Tapping inside a highlighted text places the cursor. This is especially useful for WebView and search bar has been modified to select all on focus. Selection handles time out is no longer needed. This CL is pretty involved and especially messes up with the terrible ExtractedTextView, which causes a lot of problem with text selection across device rotations. The current implementation works pretty well. It has one problem: the handles are not displayed when switching to landscape mode with a selected text. This is still an improvement over the current GB version, where the handles are not preserved at all across device rotation and where I can find more bugs. Handles are now hidden when a context menu is displayed. I can polish this more if we decide to include this in the MR1. Change-Id: Id10bf2808ff25752efd59a1987e91d609ba478cd
1 parent ca36d86 commit 1614147

File tree

2 files changed

+37
-58
lines changed

2 files changed

+37
-58
lines changed

core/java/android/widget/TextView.java

Lines changed: 36 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ class InputMethodState {
297297
Drawable mSelectHandleRight;
298298
Drawable mSelectHandleCenter;
299299

300+
// Set when this TextView gained focus with some text selected. Will start selection mode.
301+
private boolean mCreatedWithASelection = false;
302+
300303
/*
301304
* Kick-start the font cache for the zygote process (to pay the cost of
302305
* initializing freetype for our default font only once).
@@ -3758,8 +3761,10 @@ public boolean onPreDraw() {
37583761
// - ExtractEditText does not call onFocus when it is displayed. Fixing this issue would
37593762
// allow to test for hasSelection in onFocusChanged, which would trigger a
37603763
// startTextSelectionMode here. TODO
3761-
if (this instanceof ExtractEditText && selectionController != null && hasSelection()) {
3764+
if (mCreatedWithASelection ||
3765+
(this instanceof ExtractEditText && selectionController != null && hasSelection())) {
37623766
startTextSelectionMode();
3767+
mCreatedWithASelection = false;
37633768
}
37643769

37653770
mPreDrawState = PREDRAW_DONE;
@@ -4175,6 +4180,7 @@ protected void updateCursorControllerPositions() {
41754180
mInsertionPointCursorController.isShowing()) {
41764181
mInsertionPointCursorController.updatePosition();
41774182
}
4183+
41784184
if (mSelectionModifierCursorController != null &&
41794185
mSelectionModifierCursorController.isShowing()) {
41804186
mSelectionModifierCursorController.updatePosition();
@@ -6580,6 +6586,12 @@ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFoc
65806586
int selStart = getSelectionStart();
65816587
int selEnd = getSelectionEnd();
65826588

6589+
// SelectAllOnFocus fields are highlighted and not selected. Do not start text selection
6590+
// mode for these, unless there was a specific selection already started.
6591+
final boolean isFocusHighlighted = mSelectAllOnFocus && selStart == 0 &&
6592+
selEnd == mText.length();
6593+
mCreatedWithASelection = mFrozenWithFocus && hasSelection() && !isFocusHighlighted;
6594+
65836595
if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
65846596
// If a tap was used to give focus to that view, move cursor at tap position.
65856597
// Has to be done before onTakeFocus, which can be overloaded.
@@ -6592,10 +6604,6 @@ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFoc
65926604
mMovement.onTakeFocus(this, (Spannable) mText, direction);
65936605
}
65946606

6595-
if (mSelectAllOnFocus) {
6596-
Selection.setSelection((Spannable) mText, 0, mText.length());
6597-
}
6598-
65996607
// The DecorView does not have focus when the 'Done' ExtractEditText button is
66006608
// pressed. Since it is the ViewRoot's mView, it requests focus before
66016609
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
@@ -6614,6 +6622,11 @@ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFoc
66146622
*/
66156623
Selection.setSelection((Spannable) mText, selStart, selEnd);
66166624
}
6625+
6626+
if (mSelectAllOnFocus) {
6627+
Selection.setSelection((Spannable) mText, 0, mText.length());
6628+
}
6629+
66176630
mTouchFocusSelected = true;
66186631
}
66196632

@@ -6643,7 +6656,7 @@ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFoc
66436656
// ExtractEditText goes out of focus.
66446657
mIsInTextSelectionMode = false;
66456658
} else {
6646-
terminateTextSelectionMode();
6659+
stopTextSelectionMode();
66476660
}
66486661

66496662
if (mSelectionModifierCursorController != null) {
@@ -6745,29 +6758,23 @@ private void onTapUpEvent(int prevStart, int prevEnd) {
67456758
final int end = getSelectionEnd();
67466759

67476760
if (start == end) {
6748-
if (start >= prevStart && start < prevEnd) {
6761+
boolean tapInsideSelectAllOnFocus = mSelectAllOnFocus && prevStart == 0 &&
6762+
prevEnd == mText.length();
6763+
if (start >= prevStart && start < prevEnd && !tapInsideSelectAllOnFocus) {
67496764
// Restore previous selection
67506765
Selection.setSelection((Spannable)mText, prevStart, prevEnd);
67516766

6752-
if (hasSelectionController() && !getSelectionController().isShowing()) {
6753-
// If the anchors aren't showing, revive them.
6754-
getSelectionController().show();
6755-
} else {
6756-
// Tapping inside the selection displays the cut/copy/paste context menu
6757-
// as long as the anchors are already showing.
6758-
showContextMenu();
6759-
}
6760-
return;
6767+
// Tapping inside the selection displays the cut/copy/paste context menu
6768+
showContextMenu();
67616769
} else {
67626770
// Tapping outside stops selection mode, if any
67636771
stopTextSelectionMode();
67646772

6765-
if (hasInsertionController() && mText.length() > 0) {
6773+
boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
6774+
if (hasInsertionController() && !selectAllGotFocus) {
67666775
getInsertionController().show();
67676776
}
67686777
}
6769-
} else if (hasSelection() && hasSelectionController()) {
6770-
getSelectionController().show();
67716778
}
67726779
}
67736780

@@ -6790,7 +6797,8 @@ protected void onReceiveResult(int resultCode, Bundle resultData) {
67906797
int end = Math.min(len, mPrevEnd);
67916798
Selection.setSelection((Spannable)mText, start, end);
67926799

6793-
if (hasSelection()) {
6800+
boolean selectAllGotFocus = mSelectAllOnFocus && mTouchFocusSelected;
6801+
if (hasSelection() && !selectAllGotFocus) {
67946802
startTextSelectionMode();
67956803
}
67966804
}
@@ -7147,7 +7155,7 @@ public boolean onKeyShortcut(int keyCode, KeyEvent event) {
71477155
}
71487156

71497157
private boolean canSelectText() {
7150-
return textCanBeSelected() && mText.length() != 0;
7158+
return hasSelectionController() && mText.length() != 0;
71517159
}
71527160

71537161
private boolean textCanBeSelected() {
@@ -7317,7 +7325,7 @@ private void selectCurrentWord() {
73177325
}
73187326

73197327
int selectionStart, selectionEnd;
7320-
7328+
73217329
long wordLimits = getWordLimitsAt(minOffset);
73227330
if (wordLimits >= 0) {
73237331
selectionStart = extractRangeStartFromLong(wordLimits);
@@ -7476,6 +7484,7 @@ protected void onCreateContextMenu(ContextMenu menu) {
74767484
}
74777485

74787486
if (added) {
7487+
hideControllers();
74797488
menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
74807489
}
74817490
}
@@ -7652,29 +7661,18 @@ private void startTextSelectionMode() {
76527661
return;
76537662
}
76547663

7655-
if (!requestFocus()) {
7664+
if (!canSelectText() || !requestFocus()) {
76567665
return;
76577666
}
76587667

76597668
selectCurrentWord();
7669+
getSelectionController().show();
7670+
final InputMethodManager imm = (InputMethodManager)
7671+
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
7672+
imm.showSoftInput(this, 0, null);
76607673
mIsInTextSelectionMode = true;
76617674
}
76627675
}
7663-
7664-
/**
7665-
* Same as {@link #stopTextSelectionMode()}, except that there is no cursor controller
7666-
* fade out animation. Needed since the drawable and their alpha values are shared by all
7667-
* TextViews. Switching from one TextView to another would fade the cursor controllers in the
7668-
* new one otherwise.
7669-
*/
7670-
private void terminateTextSelectionMode() {
7671-
stopTextSelectionMode();
7672-
if (mSelectionModifierCursorController != null) {
7673-
SelectionModifierCursorController selectionModifierCursorController =
7674-
(SelectionModifierCursorController) mSelectionModifierCursorController;
7675-
selectionModifierCursorController.cancelFadeOutAnimation();
7676-
}
7677-
}
76787676

76797677
private void stopTextSelectionMode() {
76807678
if (mIsInTextSelectionMode) {
@@ -8052,14 +8050,6 @@ private class SelectionModifierCursorController implements CursorController {
80528050
// Whether selection anchors are active
80538051
private boolean mIsShowing;
80548052

8055-
private static final int DELAY_BEFORE_FADE_OUT = 4100;
8056-
8057-
private final Runnable mHider = new Runnable() {
8058-
public void run() {
8059-
hide();
8060-
}
8061-
};
8062-
80638053
SelectionModifierCursorController() {
80648054
mStartHandle = new HandleView(this, HandleView.LEFT);
80658055
mEndHandle = new HandleView(this, HandleView.RIGHT);
@@ -8076,29 +8066,18 @@ public void show() {
80768066
mStartHandle.show();
80778067
mEndHandle.show();
80788068
hideInsertionPointCursorController();
8079-
hideDelayed(DELAY_BEFORE_FADE_OUT);
80808069
}
80818070

80828071
public void hide() {
80838072
mStartHandle.hide();
80848073
mEndHandle.hide();
80858074
mIsShowing = false;
8086-
removeCallbacks(mHider);
8087-
}
8088-
8089-
private void hideDelayed(int delay) {
8090-
removeCallbacks(mHider);
8091-
postDelayed(mHider, delay);
80928075
}
80938076

80948077
public boolean isShowing() {
80958078
return mIsShowing;
80968079
}
80978080

8098-
public void cancelFadeOutAnimation() {
8099-
hide();
8100-
}
8101-
81028081
public void updatePosition(HandleView handle, int x, int y) {
81038082
int selectionStart = getSelectionStart();
81048083
int selectionEnd = getSelectionEnd();
@@ -8150,7 +8129,6 @@ public void updatePosition() {
81508129

81518130
mStartHandle.positionAtCursor(selectionStart, true);
81528131
mEndHandle.positionAtCursor(selectionEnd, true);
8153-
hideDelayed(DELAY_BEFORE_FADE_OUT);
81548132
}
81558133

81568134
public boolean onTouchEvent(MotionEvent event) {

core/res/res/layout/search_bar.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
android:drawablePadding="2dip"
7676
android:singleLine="true"
7777
android:ellipsize="end"
78+
android:selectAllOnFocus="true"
7879
android:inputType="text|textAutoComplete"
7980
android:dropDownWidth="match_parent"
8081
android:dropDownHeight="match_parent"

0 commit comments

Comments
 (0)