Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ae3718b authored by Gilles Debunne's avatar Gilles Debunne Committed by Android Git Automerger
Browse files

am dbd25cdb: Made text selection work in ExtractEditText. DO NOT MERGE

Merge commit 'dbd25cdb' into gingerbread-plus-aosp

* commit 'dbd25cdb':
  Made text selection work in ExtractEditText. DO NOT MERGE
parents 59a5d2d5 dbd25cdb
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -78450,7 +78450,7 @@
 type="float"
 transient="false"
 volatile="false"
 value="0.0010f"
 value="0.001f"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -225477,7 +225477,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="t" type="T">
<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
+10 −1
Original line number Diff line number Diff line
@@ -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);
    }
    
+107 −99
Original line number Diff line number Diff line
@@ -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,19 +3675,22 @@ 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()) {
            if (selectionController != null && selectionController.isSelectionStartDragged()) {
                curs = getSelectionStart();
            }
            }

            /*
             * TODO: This should really only keep the end in view if
@@ -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;
    }
@@ -6482,13 +6492,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            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) {
@@ -6499,7 +6505,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
@@ -6509,7 +6520,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;
@@ -6528,13 +6538,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();
@@ -6543,14 +6546,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            onEndBatchEdit();

            hideInsertionPointCursorController();
            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);
@@ -6609,60 +6617,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }
    }

    class CommitSelectionReceiver extends ResultReceiver {
        private final int mPrevStart, mPrevEnd;
        private final int mNewStart, mNewEnd;
        
        public CommitSelectionReceiver(int mPrevStart, int mPrevEnd, int mNewStart, int mNewEnd) {
            super(getHandler());
            this.mPrevStart = mPrevStart;
            this.mPrevEnd = mPrevEnd;
            this.mNewStart = mNewStart;
            this.mNewEnd = mNewEnd;
        }
        
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            int start = mNewStart;
            int end = mNewEnd;
    private void onTapUpEvent(int prevStart, int prevEnd) {
        final int start = getSelectionStart();
        final int end = getSelectionEnd();

            // Move the cursor to the new position, unless this tap was actually
            // use to show the IMM. Leave cursor unchanged in that case.
            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);
        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;
        
        public CommitSelectionReceiver(int prevStart, int prevEnd) {
            super(getHandler());
            mPrevStart = prevStart;
            mPrevEnd = prevEnd;
        }
        
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            // 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) {
                final int len = mText.length();
            if (start > len) {
                start = len;
                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();
                }
            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.
@@ -6684,9 +6689,6 @@ 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);
            }
@@ -6696,6 +6698,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);
            }
@@ -6705,17 +6711,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    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);
                }
            }

@@ -7157,14 +7163,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);
@@ -7172,7 +7175,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        } else {
            return null;
        }
        
    }
    
    @Override
@@ -7444,6 +7446,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }

    private void startTextSelectionMode() {
        if (!mIsInTextSelectionMode) {
            if (mSelectionModifierCursorController == null) {
                Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled.");
                return;
@@ -7457,6 +7460,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            mSelectionModifierCursorController.show();
            mIsInTextSelectionMode = true;
        }
    }
    
    /**
     * Same as {@link #stopTextSelectionMode()}, except that there is no cursor controller
@@ -7560,8 +7564,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;
@@ -7592,6 +7597,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);
        }

@@ -7870,7 +7876,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);

@@ -7886,7 +7893,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) {
@@ -7902,7 +7909,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;
@@ -8076,8 +8084,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();