summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Debunne <debunne@google.com>2010-09-07 15:21:14 -0700
committerGilles Debunne <debunne@google.com>2010-09-07 18:07:30 -0700
commitdbd25cdbc3dcad573aaeaf493bc186006bce3d8e (patch)
tree9dd10a772a2771fce5bcc54e1cd2702bcf059b6c
parentd0f74ae081bac9a9c8f7faf9288305647735d743 (diff)
downloadframeworks_base-dbd25cdbc3dcad573aaeaf493bc186006bce3d8e.zip
frameworks_base-dbd25cdbc3dcad573aaeaf493bc186006bce3d8e.tar.gz
frameworks_base-dbd25cdbc3dcad573aaeaf493bc186006bce3d8e.tar.bz2
Made text selection work in ExtractEditText. DO NOT MERGE
Change insertion point on tap is no longer handled by the CommitSelectionReceiver (as it is not called by ExtractEditText). Fixed a bug to handle drawing positions when the internal TextView scroller is used. Change-Id: I87398c7109c5527d21dee6abbdb925848244d594
-rw-r--r--api/current.xml4
-rw-r--r--core/java/android/inputmethodservice/ExtractEditText.java11
-rw-r--r--core/java/android/widget/TextView.java206
3 files changed, 119 insertions, 102 deletions
diff --git a/api/current.xml b/api/current.xml
index b4fc949..bbe9936 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -78402,7 +78402,7 @@
type="float"
transient="false"
volatile="false"
- value="0.0010f"
+ value="0.001f"
static="true"
final="true"
deprecated="not deprecated"
@@ -225403,7 +225403,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 22968b0..8a52e40 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -18,6 +18,7 @@ package android.inputmethodservice;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.ContextMenu;
import android.view.inputmethod.ExtractedText;
import android.widget.EditText;
@@ -28,6 +29,7 @@ import android.widget.EditText;
public class ExtractEditText extends EditText {
private InputMethodService mIME;
private int mSettingExtractedText;
+ private boolean mContextMenuShouldBeHandledBySuper = false;
public ExtractEditText(Context context) {
super(context, null);
@@ -97,12 +99,19 @@ public class ExtractEditText extends EditText {
return false;
}
+ @Override
+ protected void onCreateContextMenu(ContextMenu menu) {
+ super.onCreateContextMenu(menu);
+ mContextMenuShouldBeHandledBySuper = true;
+ }
+
@Override public boolean onTextContextMenuItem(int id) {
- if (mIME != null) {
+ if (mIME != null && !mContextMenuShouldBeHandledBySuper) {
if (mIME.onExtractTextContextMenuItem(id)) {
return true;
}
}
+ mContextMenuShouldBeHandledBySuper = false;
return super.onTextContextMenuItem(id);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1e8023c..d0dd6cc 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -35,6 +35,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.inputmethodservice.ExtractEditText;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -3674,18 +3675,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean changed = false;
+ SelectionModifierCursorController selectionController = null;
+ if (mSelectionModifierCursorController != null) {
+ selectionController = (SelectionModifierCursorController)
+ mSelectionModifierCursorController;
+ }
+
+
if (mMovement != null) {
/* This code also provides auto-scrolling when a cursor is moved using a
* CursorController (insertion point or selection limits).
* For selection, ensure start or end is visible depending on controller's state.
*/
int curs = getSelectionEnd();
- if (mSelectionModifierCursorController != null) {
- SelectionModifierCursorController selectionController =
- (SelectionModifierCursorController) mSelectionModifierCursorController;
- if (selectionController.isSelectionStartDragged()) {
- curs = getSelectionStart();
- }
+ if (selectionController != null && selectionController.isSelectionStartDragged()) {
+ curs = getSelectionStart();
}
/*
@@ -3705,10 +3709,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
changed = bringTextIntoView();
}
- if (mShouldStartTextSelectionMode) {
+ // This has to be checked here since:
+ // - onFocusChanged cannot start it when focus is given to a view with selected text (after
+ // a screen rotation) since layout is not yet initialized at that point.
+ // - ExtractEditText does not call onFocus when it is displayed. Fixing this issue would
+ // allow to test for hasSelection in onFocusChanged, which would trigger a
+ // startTextSelectionMode here. TODO
+ if (selectionController != null && hasSelection()) {
startTextSelectionMode();
- mShouldStartTextSelectionMode = false;
}
+
mPreDrawState = PREDRAW_DONE;
return !changed;
}
@@ -6471,19 +6481,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mShowCursor = SystemClock.uptimeMillis();
ensureEndedBatchEdit();
-
+
if (focused) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
- boolean selMoved = mSelectionMoved;
-
- if (mSelectionModifierCursorController != null) {
- final int touchOffset =
- ((SelectionModifierCursorController) mSelectionModifierCursorController).
- getMinTouchOffset();
- Selection.setSelection((Spannable) mText, touchOffset);
+ // Has to be done before onTakeFocus, which can be overloaded.
+ if (mLastTouchOffset >= 0) {
+ Selection.setSelection((Spannable) mText, mLastTouchOffset);
}
if (mMovement != null) {
@@ -6494,7 +6500,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) mText, 0, mText.length());
}
- if (selMoved && selStart >= 0 && selEnd >= 0) {
+ // The DecorView does not have focus when the 'Done' ExtractEditText button is
+ // pressed. Since it is the ViewRoot's mView, it requests focus before
+ // ExtractEditText clears focus, which gives focus to the ExtractEditText.
+ // This special case ensure that we keep current selection in that case.
+ // It would be better to know why the DecorView does not have focus at that time.
+ if (((this instanceof ExtractEditText) || mSelectionMoved) && selStart >= 0 && selEnd >= 0) {
/*
* Someone intentionally set the selection, so let them
* do whatever it is that they wanted to do instead of
@@ -6504,7 +6515,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* just setting the selection in theirs and we still
* need to go through that path.
*/
-
Selection.setSelection((Spannable) mText, selStart, selEnd);
}
mTouchFocusSelected = true;
@@ -6523,13 +6533,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mError != null) {
showError();
}
-
- // We cannot start the selection mode immediately. The layout may be null here and is
- // needed by the cursor controller. Layout creation is deferred up to drawing. The
- // selection action mode will be started in onPreDraw().
- if (selStart != selEnd) {
- mShouldStartTextSelectionMode = true;
- }
} else {
if (mError != null) {
hideError();
@@ -6538,14 +6541,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
onEndBatchEdit();
hideInsertionPointCursorController();
- terminateTextSelectionMode();
+ if (this instanceof ExtractEditText) {
+ // terminateTextSelectionMode would remove selection, which we want to keep when
+ // ExtractEditText goes out of focus.
+ mIsInTextSelectionMode = false;
+ } else {
+ terminateTextSelectionMode();
+ }
}
startStopMarquee(focused);
if (mTransformation != null) {
- mTransformation.onFocusChanged(this, mText, focused, direction,
- previouslyFocusedRect);
+ mTransformation.onFocusChanged(this, mText, focused, direction, previouslyFocusedRect);
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
@@ -6604,60 +6612,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ private void onTapUpEvent(int prevStart, int prevEnd) {
+ final int start = getSelectionStart();
+ final int end = getSelectionEnd();
+
+ if (start == end) {
+ if (start >= prevStart && start < prevEnd) {
+ // Tapping inside the selection displays the cut/copy/paste context menu.
+ showContextMenu();
+ return;
+ } else {
+ // Tapping outside stops selection mode, if any
+ stopTextSelectionMode();
+
+ if (mInsertionPointCursorController != null) {
+ mInsertionPointCursorController.show();
+ }
+ }
+ }
+ }
+
class CommitSelectionReceiver extends ResultReceiver {
private final int mPrevStart, mPrevEnd;
- private final int mNewStart, mNewEnd;
- public CommitSelectionReceiver(int mPrevStart, int mPrevEnd, int mNewStart, int mNewEnd) {
+ public CommitSelectionReceiver(int prevStart, int prevEnd) {
super(getHandler());
- this.mPrevStart = mPrevStart;
- this.mPrevEnd = mPrevEnd;
- this.mNewStart = mNewStart;
- this.mNewEnd = mNewEnd;
+ mPrevStart = prevStart;
+ mPrevEnd = prevEnd;
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- int start = mNewStart;
- int end = mNewEnd;
-
- // Move the cursor to the new position, unless this tap was actually
- // use to show the IMM. Leave cursor unchanged in that case.
+ // If this tap was actually used to show the IMM, leave cursor or selection unchanged
+ // by restoring its previous position.
if (resultCode == InputMethodManager.RESULT_SHOWN) {
- start = mPrevStart;
- end = mPrevEnd;
- } else {
- if ((mPrevStart != mPrevEnd) && (start == end)) {
- if ((start >= mPrevStart) && (start < mPrevEnd)) {
- // Tapping inside the selection does nothing
- Selection.setSelection((Spannable) mText, mPrevStart, mPrevEnd);
- showContextMenu();
- return;
- } else {
- // Tapping outside stops selection mode, if any
- stopTextSelectionMode();
- }
- }
-
- if (mInsertionPointCursorController != null) {
+ final int len = mText.length();
+ int start = Math.min(len, mPrevStart);
+ int end = Math.min(len, mPrevEnd);
+ Selection.setSelection((Spannable)mText, start, end);
+
+ if (hasSelection()) {
+ startTextSelectionMode();
+ } else if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.show();
}
}
-
- final int len = mText.length();
- if (start > len) {
- start = len;
- }
- if (end > len) {
- end = len;
- }
- Selection.setSelection((Spannable)mText, start, end);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
+ final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
@@ -6678,10 +6683,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
-
- int oldSelStart = getSelectionStart();
- int oldSelEnd = getSelectionEnd();
-
+
if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.onTouchEvent(event);
}
@@ -6690,6 +6692,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
boolean handled = false;
+
+ // Save previous selection, in case this event is used to show the IME.
+ int oldSelStart = getSelectionStart();
+ int oldSelEnd = getSelectionEnd();
if (mMovement != null) {
handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
@@ -6699,18 +6705,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (action == MotionEvent.ACTION_UP && isFocused() && !mScrolled) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-
- final int newSelStart = getSelectionStart();
- final int newSelEnd = getSelectionEnd();
-
+
CommitSelectionReceiver csr = null;
- if (newSelStart != oldSelStart || newSelEnd != oldSelEnd ||
+ if (getSelectionStart() != oldSelStart || getSelectionEnd() != oldSelEnd ||
didTouchFocusSelect()) {
- csr = new CommitSelectionReceiver(oldSelStart, oldSelEnd,
- newSelStart, newSelEnd);
+ csr = new CommitSelectionReceiver(oldSelStart, oldSelEnd);
}
-
+
handled |= imm.showSoftInput(this, 0, csr) && (csr != null);
+
+ // Cannot be done by CommitSelectionReceiver, which might not always be called,
+ // for instance when dealing with an ExtractEditText.
+ onTapUpEvent(oldSelStart, oldSelEnd);
}
}
@@ -7152,14 +7158,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private String getWordForDictionary() {
- if (mSelectionModifierCursorController == null) {
+ if (mLastTouchOffset < 0) {
return null;
}
- int offset = ((SelectionModifierCursorController) mSelectionModifierCursorController).
- getMinTouchOffset();
-
- long wordLimits = getWordLimitsAt(offset);
+ long wordLimits = getWordLimitsAt(mLastTouchOffset);
if (wordLimits >= 0) {
int start = (int) (wordLimits >>> 32);
int end = (int) (wordLimits & 0x00000000FFFFFFFFL);
@@ -7167,7 +7170,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else {
return null;
}
-
}
@Override
@@ -7439,18 +7441,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void startTextSelectionMode() {
- if (mSelectionModifierCursorController == null) {
- Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled.");
- return;
- }
+ if (!mIsInTextSelectionMode) {
+ if (mSelectionModifierCursorController == null) {
+ Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled.");
+ return;
+ }
- if (!requestFocus()) {
- return;
- }
+ if (!requestFocus()) {
+ return;
+ }
- selectCurrentWord();
- mSelectionModifierCursorController.show();
- mIsInTextSelectionMode = true;
+ selectCurrentWord();
+ mSelectionModifierCursorController.show();
+ mIsInTextSelectionMode = true;
+ }
}
/**
@@ -7555,8 +7559,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mHotSpotVerticalPosition = lineTop;
final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0);
- bounds.top = (bottom ? lineBottom : lineTop) - drawableHeight / 2;
+ bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0)
+ + mScrollX;
+ bounds.top = (bottom ? lineBottom : lineTop) - drawableHeight / 2 + mScrollY;
mTopExtension = bottom ? 0 : drawableHeight / 2;
mBottomExtension = drawableHeight;
@@ -7587,6 +7592,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
(int) (y - mBottomExtension),
(int) (x + drawableWidth / 2.0),
(int) (y + mTopExtension));
+ fingerRect.offset(mScrollX, mScrollY);
return Rect.intersects(mDrawable.getBounds(), fingerRect);
}
@@ -7865,7 +7871,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
- boolean oneLineSelection = mLayout.getLineForOffset(selectionStart) == mLayout.getLineForOffset(selectionEnd);
+ boolean oneLineSelection = mLayout.getLineForOffset(selectionStart) ==
+ mLayout.getLineForOffset(selectionEnd);
mStartHandle.positionAtCursor(selectionStart, oneLineSelection);
mEndHandle.positionAtCursor(selectionEnd, true);
@@ -7881,7 +7888,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int y = (int) event.getY();
// Remember finger down position, to be able to start selection from there
- mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
+ mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y);
if (mIsVisible) {
if (mMovement instanceof ArrowKeyMovementMethod) {
@@ -7897,7 +7904,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// In case both controllers are under finger (very small
// selection region), arbitrarily pick end controller.
mStartIsDragged = !isOnEnd;
- final Handle draggedHandle = mStartIsDragged ? mStartHandle : mEndHandle;
+ final Handle draggedHandle =
+ mStartIsDragged ? mStartHandle : mEndHandle;
final Rect bounds = draggedHandle.mDrawable.getBounds();
mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
mOffsetY = draggedHandle.mHotSpotVerticalPosition - y;
@@ -8071,8 +8079,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Cursor Controllers. Null when disabled.
private CursorController mInsertionPointCursorController;
private CursorController mSelectionModifierCursorController;
- private boolean mShouldStartTextSelectionMode = false;
private boolean mIsInTextSelectionMode = false;
+ private int mLastTouchOffset = -1;
// 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();