AdapterInputConnection.java revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
19085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// Copyright 2013 The Chromium Authors. All rights reserved.
29085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// Use of this source code is governed by a BSD-style license that can be
39085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// found in the LICENSE file.
45ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
55ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.orgpackage org.chromium.content.browser.input;
65ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
75ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.orgimport android.os.SystemClock;
89085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.text.Editable;
99085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.text.InputType;
109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.text.Selection;
119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.text.TextUtils;
129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.util.Log;
139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.KeyEvent;
149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.View;
159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.inputmethod.BaseInputConnection;
169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.inputmethod.EditorInfo;
179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.inputmethod.ExtractedText;
189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport android.view.inputmethod.ExtractedTextRequest;
199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgimport com.google.common.annotations.VisibleForTesting;
219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org/**
239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * InputConnection is created by ContentView.onCreateInputConnection.
249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * It then adapts android's IME to chrome's RenderWidgetHostView using the
259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * native ImeAdapterAndroid via the class ImeAdapter.
269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */
279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgpublic class AdapterInputConnection extends BaseInputConnection {
289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private static final String TAG = "AdapterInputConnection";
299085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private static final boolean DEBUG = false;
309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    /**
319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * Selection value should be -1 if not known. See EditorInfo.java for details.
329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
3356454717593e7552d6846198b8e0f661fa36a3cayangguo@chromium.org    public static final int INVALID_SELECTION = -1;
349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    public static final int INVALID_COMPOSITION = -1;
359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private final View mInternalView;
379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private final ImeAdapter mImeAdapter;
389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private final Editable mEditable;
399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
40c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org    private boolean mSingleLine;
41c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org    private int mNumNestedBatchEdits = 0;
4271affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org
4371affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org    private int mLastUpdateSelectionStart = INVALID_SELECTION;
449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    private int mLastUpdateSelectionEnd = INVALID_SELECTION;
45e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org    private int mLastUpdateCompositionStart = INVALID_COMPOSITION;
46e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org    private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
47e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
481b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org    @VisibleForTesting
4940b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org    AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable,
5040b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org            EditorInfo outAttrs) {
51e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org        super(view, true);
52e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org        mInternalView = view;
531b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org        mImeAdapter = imeAdapter;
5440b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org        mImeAdapter.setInputConnection(this);
5540b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org        mEditable = editable;
56b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org        // The editable passed in might have been in use by a prior keyboard and could have had
57b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org        // prior composition spans set.  To avoid keyboard conflicts, remove all composing spans
581b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org        // when taking ownership of an existing Editable.
5940b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org        removeComposingSpans(mEditable);
6040b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org        mSingleLine = true;
61b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
62b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org                | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
631b3afd1cab9087ca3c4e585d3da77d374d65c082mstarzinger@chromium.org        outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
6440b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org                | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
6540b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org
66e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org        if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeText) {
67e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org            // Normal text field
689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeTextArea ||
719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeContentEditable) {
729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            // TextArea or contenteditable.
739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE;
779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            mSingleLine = false;
789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypePassword) {
799085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            // Password
809085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
819085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
829085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
839085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeSearch) {
849085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            // Search
859085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH;
869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeUrl) {
879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            // Url
889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    | InputType.TYPE_TEXT_VARIATION_URI;
909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
91a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeEmail) {
92a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            // Email
93a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
94a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                    | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
95a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
96b08986cb66c3f6687247cb6da186c1e73057e399whesse@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeTel) {
97a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            // Telephone
98a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org            // Number and telephone do not have both a Tab key and an
99a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org            // action in default OSK, so set the action to NEXT
100a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org            outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
101a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
102a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeNumber) {
103a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            // Number
104c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org            outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
1053a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org                    | InputType.TYPE_NUMBER_VARIATION_NORMAL
106c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org                    | InputType.TYPE_NUMBER_FLAG_DECIMAL;
107c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
108c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        }
109a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        outAttrs.initialSelStart = Selection.getSelectionStart(mEditable);
1103a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org        outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable);
111c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        mLastUpdateSelectionStart = Selection.getSelectionStart(mEditable);
112c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        mLastUpdateSelectionEnd = Selection.getSelectionEnd(mEditable);
113c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org
114a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        Selection.setSelection(mEditable, outAttrs.initialSelStart, outAttrs.initialSelEnd);
115a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        updateSelectionIfRequired();
116a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    }
117a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
118a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    /**
119c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org     * Updates the AdapterInputConnection's internal representation of the text being edited and
120c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org     * its selection and composition properties. The resulting Editable is accessible through the
121a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * getEditable() method. If the text has not changed, this also calls updateSelection on the
122a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * InputMethodManager.
123a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     *
124a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * @param text The String contents of the field being edited.
125c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org     * @param selectionStart The character offset of the selection start, or the caret position if
126b08986cb66c3f6687247cb6da186c1e73057e399whesse@chromium.org     *                       there is no selection.
127a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * @param selectionEnd The character offset of the selection end, or the caret position if there
128a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     *                     is no selection.
129a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * @param compositionStart The character offset of the composition start, or -1 if there is no
130a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     *                         composition.
13184bcc559ac20fb04f806e97d28a314b20b58fd60svenpanne@chromium.org     * @param compositionEnd The character offset of the composition end, or -1 if there is no
132eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org     *                       selection.
133755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org     * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript).
134755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org     */
135a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    @VisibleForTesting
1364a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org    public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart,
13756454717593e7552d6846198b8e0f661fa36a3cayangguo@chromium.org            int compositionEnd, boolean isNonImeChange) {
13856454717593e7552d6846198b8e0f661fa36a3cayangguo@chromium.org        if (DEBUG) {
1394a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org            Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + selectionEnd + "] ["
1409085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    + compositionStart + " " + compositionEnd + "] [" + isNonImeChange + "]");
1419085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        }
1429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        // If this update is from the IME, no further state modification is necessary because the
1434a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org        // state should have been updated already by the IM framework directly.
144eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org        if (!isNonImeChange) return;
1459085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1469085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces.
1475aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        text = text.replace('\u00A0', ' ');
1485aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
1495aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        selectionStart = Math.min(selectionStart, text.length());
1505aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        selectionEnd = Math.min(selectionEnd, text.length());
1515aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        compositionStart = Math.min(compositionStart, text.length());
1525aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        compositionEnd = Math.min(compositionEnd, text.length());
1535aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
1545aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        String prevText = mEditable.toString();
1555aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        boolean textUnchanged = prevText.equals(text);
1565aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
1575aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        if (!textUnchanged) {
1585c838251403b0be9a882540f1922577abba4c872ager@chromium.org            mEditable.replace(0, mEditable.length(), text);
1595c838251403b0be9a882540f1922577abba4c872ager@chromium.org        }
1609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1610ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org        Selection.setSelection(mEditable, selectionStart, selectionEnd);
162c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org
163a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        if (compositionStart == compositionEnd) {
1643a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org            removeComposingSpans(mEditable);
1659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else {
1669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            super.setComposingRegion(compositionStart, compositionEnd);
1671456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        }
1681456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        updateSelectionIfRequired();
1691456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    }
1701456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org
1711456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    /**
1721456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org     * @return Editable object which contains the state of current focused editable element.
1731456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org     */
1741456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    @Override
1751456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    public Editable getEditable() {
1761456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        return mEditable;
1771456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    }
1781456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org
1791456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    /**
1801456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org     * Sends selection update to the InputMethodManager unless we are currently in a batch edit or
1811456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org     * if the exact same selection and composition update was sent already.
1821456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org     */
1831456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org    private void updateSelectionIfRequired() {
1841456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        if (mNumNestedBatchEdits != 0) return;
1851456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        int selectionStart = Selection.getSelectionStart(mEditable);
1861456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        int selectionEnd = Selection.getSelectionEnd(mEditable);
1871456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        int compositionStart = getComposingSpanStart(mEditable);
1881456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        int compositionEnd = getComposingSpanEnd(mEditable);
1891456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        // Avoid sending update if we sent an exact update already previously.
1901456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        if (mLastUpdateSelectionStart == selectionStart &&
1911456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org                mLastUpdateSelectionEnd == selectionEnd &&
1921456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org                mLastUpdateCompositionStart == compositionStart &&
1931456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org                mLastUpdateCompositionEnd == compositionEnd) {
1941456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org            return;
1951456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        }
1961456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        if (DEBUG) {
1971456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org            Log.w(TAG, "updateSelectionIfRequired [" + selectionStart + " " + selectionEnd + "] ["
1981456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org                    + compositionStart + " " + compositionEnd + "]");
1991456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        }
2001456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        // updateSelection should be called every time the selection or composition changes
2011456e708d277e725ca42a03463af16fe471c9210jkummerow@chromium.org        // if it happens not within a batch edit, or at the end of each top level batch edit.
2025aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org        getInputMethodManagerWrapper().updateSelection(mInternalView,
2035aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org                selectionStart, selectionEnd, compositionStart, compositionEnd);
2049085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        mLastUpdateSelectionStart = selectionStart;
20594b0d6fcb08a2f01ba52c6edb712068f482366f1danno@chromium.org        mLastUpdateSelectionEnd = selectionEnd;
206a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        mLastUpdateCompositionStart = compositionStart;
207a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        mLastUpdateCompositionEnd = compositionEnd;
208a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org    }
209a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org
210a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    /**
211a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int)
212a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     */
213a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    @Override
214a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    public boolean setComposingText(CharSequence text, int newCursorPosition) {
215a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]");
216c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        if (maybePerformEmptyCompositionWorkaround(text)) return true;
217a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org        super.setComposingText(text, newCursorPosition);
218c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        updateSelectionIfRequired();
219c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition, false);
220c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org    }
221c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org
222a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    /**
223a6bbcc801f63c451f814d6da77a1a48fba3d36c6yangguo@chromium.org     * @see BaseInputConnection#commitText(java.lang.CharSequence, int)
224a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     */
225a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    @Override
226a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    public boolean commitText(CharSequence text, int newCursorPosition) {
227a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
228a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        if (maybePerformEmptyCompositionWorkaround(text)) return true;
229a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        super.commitText(text, newCursorPosition);
230a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        updateSelectionIfRequired();
231a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition,
232a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org                text.length() > 0);
233a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    }
234a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
235a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    /**
236a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     * @see BaseInputConnection#performEditorAction(int)
237a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org     */
238a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    @Override
239a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    public boolean performEditorAction(int actionCode) {
240a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        if (DEBUG) Log.w(TAG, "performEditorAction [" + actionCode + "]");
241a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        if (actionCode == EditorInfo.IME_ACTION_NEXT) {
242a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            restartInput();
243a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org            // Send TAB key event
244c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            long timeStampMs = SystemClock.uptimeMillis();
245c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            mImeAdapter.sendSyntheticKeyEvent(
24694b0d6fcb08a2f01ba52c6edb712068f482366f1danno@chromium.org                    ImeAdapter.sEventTypeRawKeyDown, timeStampMs, KeyEvent.KEYCODE_TAB, 0);
247c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com        } else {
248c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER,
249c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
25094b0d6fcb08a2f01ba52c6edb712068f482366f1danno@chromium.org                    | KeyEvent.FLAG_EDITOR_ACTION);
251c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org        }
2524a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org        return true;
2539085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
2549085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    /**
2569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * @see BaseInputConnection#performContextMenuAction(int)
25786f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org     */
25886f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org    @Override
25986f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org    public boolean performContextMenuAction(int id) {
26086f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org        if (DEBUG) Log.w(TAG, "performContextMenuAction [" + id + "]");
26186f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org        switch (id) {
26286f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org            case android.R.id.selectAll:
26386f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org                return mImeAdapter.selectAll();
26486f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org            case android.R.id.cut:
26586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org                return mImeAdapter.cut();
26686f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org            case android.R.id.copy:
26786f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org                return mImeAdapter.copy();
2689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            case android.R.id.paste:
2699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return mImeAdapter.paste();
2709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            default:
271b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org                return false;
272b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        }
273b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org    }
274b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org
275b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org    /**
276b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org     * @see BaseInputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest,
277b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org     *                                           int)
278b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org     */
279b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org    @Override
280b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
281b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        if (DEBUG) Log.w(TAG, "getExtractedText");
282b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        ExtractedText et = new ExtractedText();
283b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        et.text = mEditable.toString();
284b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        et.partialEndOffset = mEditable.length();
285b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        et.selectionStart = Selection.getSelectionStart(mEditable);
286b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org        et.selectionEnd = Selection.getSelectionEnd(mEditable);
2879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
288a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org        return et;
289a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    }
290a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
291a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org    /**
2929085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * @see BaseInputConnection#beginBatchEdit()
2939085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
2949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    @Override
2959085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    public boolean beginBatchEdit() {
2969085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (DEBUG) Log.w(TAG, "beginBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
2979085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        mNumNestedBatchEdits++;
2989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return true;
2999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
3009085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3019085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    /**
3029085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * @see BaseInputConnection#endBatchEdit()
3039085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
3049085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    @Override
3059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    public boolean endBatchEdit() {
3069085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (mNumNestedBatchEdits == 0) return false;
3079085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        --mNumNestedBatchEdits;
3089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
3099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (mNumNestedBatchEdits == 0) updateSelectionIfRequired();
3109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return mNumNestedBatchEdits != 0;
3119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
3129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3139d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com    /**
3149d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com     * @see BaseInputConnection#deleteSurroundingText(int, int)
3159d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com     */
3169d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com    @Override
3179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
3189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (DEBUG) {
3199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]");
3209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        }
3219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int availableBefore = Selection.getSelectionStart(mEditable);
3229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEditable);
3239d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com        beforeLength = Math.min(beforeLength, availableBefore);
3249d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com        afterLength = Math.min(afterLength, availableAfter);
3259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        super.deleteSurroundingText(beforeLength, afterLength);
3269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        updateSelectionIfRequired();
3279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
3289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
3299085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    /**
3319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
3325ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org     */
3335ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org    @Override
3345ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org    public boolean sendKeyEvent(KeyEvent event) {
3355ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org        if (DEBUG) {
3369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getKeyCode() + "]");
3379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        }
3389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        // If this is a key-up, and backspace/del or if the key has a character representation,
3399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        // need to update the underlying Editable (i.e. the local representation of the text
3409085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        // being edited).
3419085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (event.getAction() == KeyEvent.ACTION_UP) {
3429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
3439085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                deleteSurroundingText(1, 0);
3449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return true;
3459085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
3469085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                deleteSurroundingText(0, 1);
3479085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return true;
3489085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            } else {
3499085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                int unicodeChar = event.getUnicodeChar();
3509085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                if (unicodeChar != 0) {
3519085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    int selectionStart = Selection.getSelectionStart(mEditable);
3529085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    int selectionEnd = Selection.getSelectionEnd(mEditable);
3539085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    if (selectionStart > selectionEnd) {
3549085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                        int temp = selectionStart;
3559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                        selectionStart = selectionEnd;
3569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                        selectionEnd = temp;
3579085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    }
3589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                    mEditable.replace(selectionStart, selectionEnd,
3599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                            Character.toString((char) unicodeChar));
3609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                }
3615ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org            }
3629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
3639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed.
3649085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
3659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                beginBatchEdit();
3669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                finishComposingText();
367755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org                mImeAdapter.translateAndSendNativeEvents(event);
3689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                endBatchEdit();
3699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return true;
370755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org            } else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
3719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return true;
3729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
3739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                return true;
3749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            }
3759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        }
3769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        mImeAdapter.translateAndSendNativeEvents(event);
3779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return true;
3789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
3799085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3803e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    /**
3813e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org     * @see BaseInputConnection#finishComposingText()
3823e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org     */
3833e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    @Override
3843e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    public boolean finishComposingText() {
3853e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org        if (DEBUG) Log.w(TAG, "finishComposingText");
3869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
3879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            return true;
3889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        }
3899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        super.finishComposingText();
3919085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        updateSelectionIfRequired();
392eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org        mImeAdapter.finishComposingText();
3939085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return true;
395755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org    }
396755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
397755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org    /**
398755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org     * @see BaseInputConnection#setSelection(int, int)
3999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
4009085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    @Override
401755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org    public boolean setSelection(int start, int end) {
402755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        if (DEBUG) Log.w(TAG, "setSelection [" + start + " " + end + "]");
403755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        int textLength = mEditable.length();
4049085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (start < 0 || end < 0 || start > textLength || end > textLength) return true;
4059155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org        super.setSelection(start, end);
4069155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org        updateSelectionIfRequired();
4079155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org        return mImeAdapter.setEditableSelectionOffsets(start, end);
4089155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org    }
4099155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org
4100ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org    /**
4110ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org     * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text
4120ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org     * state is no longer what the IME has and that it needs to be updated.
4130ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org     */
414eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org    void restartInput() {
415eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org        if (DEBUG) Log.w(TAG, "restartInput");
416eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org        getInputMethodManagerWrapper().restartInput(mInternalView);
417eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org        mNumNestedBatchEdits = 0;
418eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org    }
419eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org
420eb96f4fd17b379ad2247264f82af1100f448779bricow@chromium.org    /**
4219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * @see BaseInputConnection#setComposingRegion(int, int)
4229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
42330ce411529579186181838984710b0b0980857aaricow@chromium.org    @Override
4240ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org    public boolean setComposingRegion(int start, int end) {
4250ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org        if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
4269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int textLength = mEditable.length();
427e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org        int a = Math.min(start, end);
4289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int b = Math.max(start, end);
429755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        if (a < 0) a = 0;
4309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (b < 0) b = 0;
4319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (a > textLength) a = textLength;
432755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        if (b > textLength) b = textLength;
4339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        if (a == b) {
435755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org            removeComposingSpans(mEditable);
436755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        } else {
437755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org            super.setComposingRegion(a, b);
438755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        }
4399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        updateSelectionIfRequired();
440755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org        return mImeAdapter.setComposingRegion(a, b);
4419085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    }
4429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4439085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    boolean isActive() {
4449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return getInputMethodManagerWrapper().isActive(mInternalView);
445750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    }
4469085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
447750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    private InputMethodManagerWrapper getInputMethodManagerWrapper() {
448750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org        return mImeAdapter.getInputMethodManagerWrapper();
4493e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    }
4509085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4513e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    /**
4529085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * This method works around the issue crbug.com/373934 where Blink does not cancel
453c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org     * the composition when we send a commit with the empty text.
4549085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     *
4559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     * TODO(aurimas) Remove this once crbug.com/373934 is fixed.
4569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     *
457c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org     * @param text Text that software keyboard requested to commit.
458ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org     * @return Whether the workaround was performed.
4599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org     */
460c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org    private boolean maybePerformEmptyCompositionWorkaround(CharSequence text) {
461c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org        int selectionStart = Selection.getSelectionStart(mEditable);
4629d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com        int selectionEnd = Selection.getSelectionEnd(mEditable);
4639d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com        int compositionStart = getComposingSpanStart(mEditable);
4647a6fc815d62905d0c52705b96225b1bd23e00a43jkummerow@chromium.org        int compositionEnd = getComposingSpanEnd(mEditable);
4659d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com        if (TextUtils.isEmpty(text) && (selectionStart == selectionEnd)
4669d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com                && compositionStart != INVALID_COMPOSITION
4679d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com                && compositionEnd != INVALID_COMPOSITION) {
468750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org            beginBatchEdit();
4699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org            finishComposingText();
470c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            int selection = Selection.getSelectionStart(mEditable);
471750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org            deleteSurroundingText(selection - compositionStart, selection - compositionEnd);
472c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            endBatchEdit();
473750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org            return true;
474750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org        }
4759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        return false;
47683e168294456ca2f02db421a635f7d5f5d023966kmillikin@chromium.org    }
477750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org
478750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    @VisibleForTesting
479750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    static class ImeState {
480750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org        public final String text;
481ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org        public final int selectionStart;
482c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org        public final int selectionEnd;
4833e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org        public final int compositionStart;
4843e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org        public final int compositionEnd;
485ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org
486ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org        public ImeState(String text, int selectionStart, int selectionEnd,
487c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org                int compositionStart, int compositionEnd) {
488ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org            this.text = text;
489c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            this.selectionStart = selectionStart;
490c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            this.selectionEnd = selectionEnd;
491c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            this.compositionStart = compositionStart;
492c36ce6e8979bbbd43539f0a0effc87ea20dd65cckmillikin@chromium.org            this.compositionEnd = compositionEnd;
493750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org        }
494ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org    }
495003650ee766f5e92756d470a37973fd371757485yangguo@chromium.org
496ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org    @VisibleForTesting
4979085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org    ImeState getImeStateForTesting() {
4989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        String text = mEditable.toString();
4999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int selectionStart = Selection.getSelectionStart(mEditable);
500ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.org        int selectionEnd = Selection.getSelectionEnd(mEditable);
5019085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org        int compositionStart = getComposingSpanStart(mEditable);
5023e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org        int compositionEnd = getComposingSpanEnd(mEditable);
5033e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org        return new ImeState(text, selectionStart, selectionEnd, compositionStart, compositionEnd);
5043e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org    }
5059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
5063e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org