From 36ffc5c960cdb3de7269898d2142a361acdec74a Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Thu, 21 Oct 2010 18:44:32 -0700 Subject: DO NOT MERGE Fix bug 3121030 - Text handles erroneously appear over extract mode IME window Make the SelectionModifierCursorController track its show/hide state more accurately in the presence of an extract mode IME. Lazily initialize CursorControllers so that we don't end up creating them for various TextViews where they are not needed. Change-Id: Ib76a95d9e7669016cf11b8b0add8843b438068ea --- core/java/android/widget/TextView.java | 127 +++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 29 deletions(-) diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b30b6b1d3841..41c973614b82 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3758,7 +3758,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // - 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()) { + if (this instanceof ExtractEditText && selectionController != null && hasSelection()) { startTextSelectionMode(); } @@ -4819,6 +4819,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void beginBatchEdit() { + mInBatchEditControllers = true; final InputMethodState ims = mInputMethodState; if (ims != null) { int nesting = ++ims.mBatchEditNesting; @@ -4841,6 +4842,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void endBatchEdit() { + mInBatchEditControllers = false; final InputMethodState ims = mInputMethodState; if (ims != null) { int nesting = --ims.mBatchEditNesting; @@ -6747,10 +6749,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Restore previous selection Selection.setSelection((Spannable)mText, prevStart, prevEnd); - if (mSelectionModifierCursorController != null && - !mSelectionModifierCursorController.isShowing()) { + if (hasSelectionController() && !getSelectionController().isShowing()) { // If the anchors aren't showing, revive them. - mSelectionModifierCursorController.show(); + getSelectionController().show(); } else { // Tapping inside the selection displays the cut/copy/paste context menu // as long as the anchors are already showing. @@ -6761,12 +6762,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Tapping outside stops selection mode, if any stopTextSelectionMode(); - if (mInsertionPointCursorController != null && mText.length() > 0) { - mInsertionPointCursorController.show(); + if (hasInsertionController() && mText.length() > 0) { + getInsertionController().show(); } } - } else if (hasSelection() && mSelectionModifierCursorController != null) { - mSelectionModifierCursorController.show(); + } else if (hasSelection() && hasSelectionController()) { + getSelectionController().show(); } } @@ -6800,11 +6801,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { - if (mInsertionPointCursorController != null) { - mInsertionPointCursorController.onTouchEvent(event); + if (hasInsertionController()) { + getInsertionController().onTouchEvent(event); } - if (mSelectionModifierCursorController != null) { - mSelectionModifierCursorController.onTouchEvent(event); + if (hasSelectionController()) { + getSelectionController().onTouchEvent(event); } // Reset this state; it will be re-set if super.onTouchEvent @@ -6826,11 +6827,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) { - if (mInsertionPointCursorController != null) { - mInsertionPointCursorController.onTouchEvent(event); + if (hasInsertionController()) { + getInsertionController().onTouchEvent(event); } - if (mSelectionModifierCursorController != null) { - mSelectionModifierCursorController.onTouchEvent(event); + if (hasSelectionController()) { + getSelectionController().onTouchEvent(event); } boolean handled = false; @@ -6892,19 +6893,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // TODO Add an extra android:cursorController flag to disable the controller? - if (windowSupportsHandles && mCursorVisible && mLayout != null) { - if (mInsertionPointCursorController == null) { - mInsertionPointCursorController = new InsertionPointCursorController(); - } - } else { + mInsertionControllerEnabled = windowSupportsHandles && mCursorVisible && mLayout != null; + mSelectionControllerEnabled = windowSupportsHandles && textCanBeSelected() && + mLayout != null; + + if (!mInsertionControllerEnabled) { mInsertionPointCursorController = null; } - if (windowSupportsHandles && textCanBeSelected() && mLayout != null) { - if (mSelectionModifierCursorController == null) { - mSelectionModifierCursorController = new SelectionModifierCursorController(); - } - } else { + if (!mSelectionControllerEnabled) { // Stop selection mode if the controller becomes unavailable. stopTextSelectionMode(); mSelectionModifierCursorController = null; @@ -7535,10 +7532,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_SELECT_ALL: Selection.setSelection((Spannable) mText, 0, mText.length()); startTextSelectionMode(); + getSelectionController().show(); return true; case ID_START_SELECTING_TEXT: startTextSelectionMode(); + getSelectionController().show(); return true; case ID_CUT: @@ -7648,7 +7647,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void startTextSelectionMode() { if (!mIsInTextSelectionMode) { - if (mSelectionModifierCursorController == null) { + if (!hasSelectionController()) { Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled."); return; } @@ -7658,7 +7657,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } selectCurrentWord(); - mSelectionModifierCursorController.show(); mIsInTextSelectionMode = true; } } @@ -7837,6 +7835,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return true; } + if (isInBatchEditMode()) { + return false; + } + final int extendedPaddingTop = getExtendedPaddingTop(); final int extendedPaddingBottom = getExtendedPaddingBottom(); final int compoundPaddingLeft = getCompoundPaddingLeft(); @@ -7876,7 +7878,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPositionY = y - TextView.this.mScrollY; if (isPositionVisible()) { int[] coords = null; - if (mContainer.isShowing()){ + if (mContainer.isShowing()) { coords = mTempCoords; TextView.this.getLocationInWindow(coords); mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY, @@ -8065,6 +8067,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void show() { + if (isInBatchEditMode()) { + return; + } + mIsShowing = true; updatePosition(); mStartHandle.show(); @@ -8128,6 +8134,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void updatePosition() { + if (!isShowing()) { + return; + } + final int selectionStart = getSelectionStart(); final int selectionEnd = getSelectionEnd(); @@ -8288,6 +8298,62 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getOffsetForHorizontal(line, x); } + /** + * @return True if this view supports insertion handles. + */ + boolean hasInsertionController() { + return mInsertionControllerEnabled; + } + + /** + * @return True if this view supports selection handles. + */ + boolean hasSelectionController() { + return mSelectionControllerEnabled; + } + + CursorController getInsertionController() { + if (!mInsertionControllerEnabled) { + return null; + } + + if (mInsertionPointCursorController == null) { + mInsertionPointCursorController = new InsertionPointCursorController(); + + final ViewTreeObserver observer = getViewTreeObserver(); + if (observer != null) { + observer.addOnTouchModeChangeListener(mInsertionPointCursorController); + } + } + + return mInsertionPointCursorController; + } + + CursorController getSelectionController() { + if (!mSelectionControllerEnabled) { + return null; + } + + if (mSelectionModifierCursorController == null) { + mSelectionModifierCursorController = new SelectionModifierCursorController(); + + final ViewTreeObserver observer = getViewTreeObserver(); + if (observer != null) { + observer.addOnTouchModeChangeListener(mSelectionModifierCursorController); + } + } + + return mSelectionModifierCursorController; + } + + boolean isInBatchEditMode() { + final InputMethodState ims = mInputMethodState; + if (ims != null) { + return ims.mBatchEditNesting > 0; + } + return mInBatchEditControllers; + } + @ViewDebug.ExportedProperty private CharSequence mText; private CharSequence mTransformed; @@ -8319,6 +8385,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Cursor Controllers. Null when disabled. private CursorController mInsertionPointCursorController; private CursorController mSelectionModifierCursorController; + private boolean mInsertionControllerEnabled; + private boolean mSelectionControllerEnabled; + private boolean mInBatchEditControllers; private boolean mIsInTextSelectionMode = false; // 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. -- cgit v1.2.3-59-g8ed1b