168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)package org.chromium.content.browser.input;
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.os.SystemClock;
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.Editable;
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.InputType;
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.Selection;
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.text.TextUtils;
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.util.Log;
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.KeyEvent;
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.View;
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.BaseInputConnection;
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.EditorInfo;
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.ExtractedText;
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.ExtractedTextRequest;
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting;
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * InputConnection is created by ContentView.onCreateInputConnection.
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * It then adapts android's IME to chrome's RenderWidgetHostView using the
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * native ImeAdapterAndroid via the class ImeAdapter.
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)public class AdapterInputConnection extends BaseInputConnection {
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    private static final String TAG = "AdapterInputConnection";
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final boolean DEBUG = false;
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Selection value should be -1 if not known. See EditorInfo.java for details.
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static final int INVALID_SELECTION = -1;
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static final int INVALID_COMPOSITION = -1;
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private final View mInternalView;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private final ImeAdapter mImeAdapter;
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private final Editable mEditable;
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private boolean mSingleLine;
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private int mNumNestedBatchEdits = 0;
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private int mLastUpdateSelectionStart = INVALID_SELECTION;
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private int mLastUpdateSelectionEnd = INVALID_SELECTION;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private int mLastUpdateCompositionStart = INVALID_COMPOSITION;
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @VisibleForTesting
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable,
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            EditorInfo outAttrs) {
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        super(view, true);
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mInternalView = view;
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mImeAdapter = imeAdapter;
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mImeAdapter.setInputConnection(this);
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        mEditable = editable;
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // The editable passed in might have been in use by a prior keyboard and could have had
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // prior composition spans set.  To avoid keyboard conflicts, remove all composing spans
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // when taking ownership of an existing Editable.
5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        removeComposingSpans(mEditable);
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mSingleLine = true;
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        int inputType = imeAdapter.getTextInputType();
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        int inputFlags = imeAdapter.getTextInputFlags();
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if ((inputFlags & imeAdapter.sTextInputFlagAutocompleteOff) != 0) {
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        }
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if (inputType == ImeAdapter.sTextInputTypeText) {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Normal text field
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            if ((inputFlags & imeAdapter.sTextInputFlagAutocorrectOff) == 0) {
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            }
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeTextArea ||
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                inputType == ImeAdapter.sTextInputTypeContentEditable) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // TextArea or contenteditable.
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            if ((inputFlags & imeAdapter.sTextInputFlagAutocorrectOff) == 0) {
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            }
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            mSingleLine = false;
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypePassword) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Password
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeSearch) {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Search
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH;
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeUrl) {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Url
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    | InputType.TYPE_TEXT_VARIATION_URI;
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeEmail) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Email
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.inputType = InputType.TYPE_CLASS_TEXT
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeTel) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Telephone
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Number and telephone do not have both a Tab key and an
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // action in default OSK, so set the action to NEXT
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        } else if (inputType == ImeAdapter.sTextInputTypeNumber) {
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Number
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    | InputType.TYPE_NUMBER_VARIATION_NORMAL
1160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    | InputType.TYPE_NUMBER_FLAG_DECIMAL;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        outAttrs.initialSelStart = Selection.getSelectionStart(mEditable);
12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable);
12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        mLastUpdateSelectionStart = Selection.getSelectionStart(mEditable);
12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        mLastUpdateSelectionEnd = Selection.getSelectionEnd(mEditable);
12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        Selection.setSelection(mEditable, outAttrs.initialSelStart, outAttrs.initialSelEnd);
12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        updateSelectionIfRequired();
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * Updates the AdapterInputConnection's internal representation of the text being edited and
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * its selection and composition properties. The resulting Editable is accessible through the
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * getEditable() method. If the text has not changed, this also calls updateSelection on the
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * InputMethodManager.
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     *
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param text The String contents of the field being edited.
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param selectionStart The character offset of the selection start, or the caret position if
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     *                       there is no selection.
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param selectionEnd The character offset of the selection end, or the caret position if there
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     *                     is no selection.
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param compositionStart The character offset of the composition start, or -1 if there is no
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     *                         composition.
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param compositionEnd The character offset of the composition end, or -1 if there is no
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     *                       selection.
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch     * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript).
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @VisibleForTesting
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart,
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            int compositionEnd, boolean isNonImeChange) {
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) {
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + selectionEnd + "] ["
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    + compositionStart + " " + compositionEnd + "] [" + isNonImeChange + "]");
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // If this update is from the IME, no further state modification is necessary because the
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // state should have been updated already by the IM framework directly.
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        if (!isNonImeChange) return;
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces.
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        text = text.replace('\u00A0', ' ');
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        selectionStart = Math.min(selectionStart, text.length());
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        selectionEnd = Math.min(selectionEnd, text.length());
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        compositionStart = Math.min(compositionStart, text.length());
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        compositionEnd = Math.min(compositionEnd, text.length());
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        String prevText = mEditable.toString();
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        boolean textUnchanged = prevText.equals(text);
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (!textUnchanged) {
16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            mEditable.replace(0, mEditable.length(), text);
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        Selection.setSelection(mEditable, selectionStart, selectionEnd);
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (compositionStart == compositionEnd) {
17423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            removeComposingSpans(mEditable);
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } else {
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            super.setComposingRegion(compositionStart, compositionEnd);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    /**
18223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * @return Editable object which contains the state of current focused editable element.
18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
18423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Override
18523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public Editable getEditable() {
18623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        return mEditable;
18723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
18823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
18923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * Sends selection update to the InputMethodManager unless we are currently in a batch edit or
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * if the exact same selection and composition update was sent already.
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     */
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private void updateSelectionIfRequired() {
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (mNumNestedBatchEdits != 0) return;
19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int selectionStart = Selection.getSelectionStart(mEditable);
19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int selectionEnd = Selection.getSelectionEnd(mEditable);
19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int compositionStart = getComposingSpanStart(mEditable);
19823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int compositionEnd = getComposingSpanEnd(mEditable);
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Avoid sending update if we sent an exact update already previously.
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mLastUpdateSelectionStart == selectionStart &&
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                mLastUpdateSelectionEnd == selectionEnd &&
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                mLastUpdateCompositionStart == compositionStart &&
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                mLastUpdateCompositionEnd == compositionEnd) {
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return;
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) {
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            Log.w(TAG, "updateSelectionIfRequired [" + selectionStart + " " + selectionEnd + "] ["
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    + compositionStart + " " + compositionEnd + "]");
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // updateSelection should be called every time the selection or composition changes
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // if it happens not within a batch edit, or at the end of each top level batch edit.
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        getInputMethodManagerWrapper().updateSelection(mInternalView,
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                selectionStart, selectionEnd, compositionStart, compositionEnd);
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mLastUpdateSelectionStart = selectionStart;
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mLastUpdateSelectionEnd = selectionEnd;
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mLastUpdateCompositionStart = compositionStart;
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mLastUpdateCompositionEnd = compositionEnd;
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean setComposingText(CharSequence text, int newCursorPosition) {
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]");
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (maybePerformEmptyCompositionWorkaround(text)) return true;
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        super.setComposingText(text, newCursorPosition);
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
2296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition, false);
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#commitText(java.lang.CharSequence, int)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean commitText(CharSequence text, int newCursorPosition) {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (maybePerformEmptyCompositionWorkaround(text)) return true;
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        super.commitText(text, newCursorPosition);
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition,
2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                text.length() > 0);
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#performEditorAction(int)
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean performEditorAction(int actionCode) {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "performEditorAction [" + actionCode + "]");
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (actionCode == EditorInfo.IME_ACTION_NEXT) {
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            restartInput();
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Send TAB key event
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            long timeStampMs = SystemClock.uptimeMillis();
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            mImeAdapter.sendSyntheticKeyEvent(
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    ImeAdapter.sEventTypeRawKeyDown, timeStampMs, KeyEvent.KEYCODE_TAB, 0, 0);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } else {
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER,
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    | KeyEvent.FLAG_EDITOR_ACTION);
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return true;
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#performContextMenuAction(int)
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean performContextMenuAction(int id) {
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "performContextMenuAction [" + id + "]");
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        switch (id) {
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            case android.R.id.selectAll:
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return mImeAdapter.selectAll();
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            case android.R.id.cut:
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return mImeAdapter.cut();
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            case android.R.id.copy:
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return mImeAdapter.copy();
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            case android.R.id.paste:
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return mImeAdapter.paste();
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            default:
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                return false;
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest,
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     *                                           int)
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "getExtractedText");
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ExtractedText et = new ExtractedText();
29323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        et.text = mEditable.toString();
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        et.partialEndOffset = mEditable.length();
29523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        et.selectionStart = Selection.getSelectionStart(mEditable);
29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        et.selectionEnd = Selection.getSelectionEnd(mEditable);
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return et;
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#beginBatchEdit()
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean beginBatchEdit() {
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "beginBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mNumNestedBatchEdits++;
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return true;
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#endBatchEdit()
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean endBatchEdit() {
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mNumNestedBatchEdits == 0) return false;
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        --mNumNestedBatchEdits;
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (mNumNestedBatchEdits == 0) updateSelectionIfRequired();
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return mNumNestedBatchEdits != 0;
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#deleteSurroundingText(int, int)
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) {
329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]");
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        int originalBeforeLength = beforeLength;
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        int originalAfterLength = afterLength;
33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int availableBefore = Selection.getSelectionStart(mEditable);
33423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEditable);
335d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        beforeLength = Math.min(beforeLength, availableBefore);
336d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        afterLength = Math.min(afterLength, availableAfter);
337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        super.deleteSurroundingText(beforeLength, afterLength);
3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // For single-char deletion calls |ImeAdapter.sendKeyEventWithKeyCode| with the real key
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // code. For multi-character deletion, executes deletion by calling
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        // |ImeAdapter.deleteSurroundingText| and sends synthetic key events with a dummy key code.
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (originalBeforeLength == 1 && originalAfterLength == 0)
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            keyCode = KeyEvent.KEYCODE_DEL;
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        else if (originalBeforeLength == 0 && originalAfterLength == 1)
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            keyCode = KeyEvent.KEYCODE_FORWARD_DEL;
348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        boolean result = true;
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            result = mImeAdapter.sendSyntheticKeyEvent(
3526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    ImeAdapter.sEventTypeRawKeyDown, SystemClock.uptimeMillis(), keyCode, 0, 0);
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            result &= mImeAdapter.deleteSurroundingText(beforeLength, afterLength);
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            result &= mImeAdapter.sendSyntheticKeyEvent(
3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    ImeAdapter.sEventTypeKeyUp, SystemClock.uptimeMillis(), keyCode, 0, 0);
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        } else {
357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            mImeAdapter.sendKeyEventWithKeyCode(
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                    keyCode, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        }
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return result;
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean sendKeyEvent(KeyEvent event) {
3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (DEBUG) {
3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getKeyCode() + "]");
3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // If this is a key-up, and backspace/del or if the key has a character representation,
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // need to update the underlying Editable (i.e. the local representation of the text
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // being edited).
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (event.getAction() == KeyEvent.ACTION_UP) {
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                deleteSurroundingText(1, 0);
3774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                return true;
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                deleteSurroundingText(0, 1);
3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                return true;
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            } else {
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                int unicodeChar = event.getUnicodeChar();
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                if (unicodeChar != 0) {
38423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    int selectionStart = Selection.getSelectionStart(mEditable);
38523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    int selectionEnd = Selection.getSelectionEnd(mEditable);
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    if (selectionStart > selectionEnd) {
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        int temp = selectionStart;
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        selectionStart = selectionEnd;
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        selectionEnd = temp;
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    }
39123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    mEditable.replace(selectionStart, selectionEnd,
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            Character.toString((char) unicodeChar));
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                }
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            }
395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed.
397424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
398424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                beginBatchEdit();
399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                finishComposingText();
400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                mImeAdapter.translateAndSendNativeEvents(event);
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                endBatchEdit();
402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                return true;
4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            } else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                return true;
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                return true;
407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mImeAdapter.translateAndSendNativeEvents(event);
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return true;
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#finishComposingText()
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean finishComposingText() {
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "finishComposingText");
41923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return true;
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
422a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        super.finishComposingText();
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        mImeAdapter.finishComposingText();
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return true;
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#setSelection(int, int)
432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean setSelection(int start, int end) {
43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "setSelection [" + start + " " + end + "]");
43623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int textLength = mEditable.length();
43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (start < 0 || end < 0 || start > textLength || end > textLength) return true;
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        super.setSelection(start, end);
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return mImeAdapter.setEditableSelectionOffsets(start, end);
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * state is no longer what the IME has and that it needs to be updated.
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    void restartInput() {
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "restartInput");
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        getInputMethodManagerWrapper().restartInput(mInternalView);
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mNumNestedBatchEdits = 0;
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @see BaseInputConnection#setComposingRegion(int, int)
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @Override
457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean setComposingRegion(int start, int end) {
458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
45923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int textLength = mEditable.length();
460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int a = Math.min(start, end);
461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int b = Math.max(start, end);
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (a < 0) a = 0;
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (b < 0) b = 0;
46458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (a > textLength) a = textLength;
46558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (b > textLength) b = textLength;
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (a == b) {
46823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            removeComposingSpans(mEditable);
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } else {
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            super.setComposingRegion(a, b);
471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateSelectionIfRequired();
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        CharSequence regionText = null;
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (b > a) {
4766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            regionText = mEditable.subSequence(a, b);
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return mImeAdapter.setComposingRegion(regionText, a, b);
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    boolean isActive() {
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return getInputMethodManagerWrapper().isActive(mInternalView);
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private InputMethodManagerWrapper getInputMethodManagerWrapper() {
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return mImeAdapter.getInputMethodManagerWrapper();
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
48868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    /**
490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     * This method works around the issue crbug.com/373934 where Blink does not cancel
491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     * the composition when we send a commit with the empty text.
492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     *
493cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     * TODO(aurimas) Remove this once crbug.com/373934 is fixed.
494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     *
495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     * @param text Text that software keyboard requested to commit.
496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     * @return Whether the workaround was performed.
497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     */
498cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    private boolean maybePerformEmptyCompositionWorkaround(CharSequence text) {
499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int selectionStart = Selection.getSelectionStart(mEditable);
500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int selectionEnd = Selection.getSelectionEnd(mEditable);
501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int compositionStart = getComposingSpanStart(mEditable);
502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int compositionEnd = getComposingSpanEnd(mEditable);
503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (TextUtils.isEmpty(text) && (selectionStart == selectionEnd)
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                && compositionStart != INVALID_COMPOSITION
505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                && compositionEnd != INVALID_COMPOSITION) {
506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            beginBatchEdit();
507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            finishComposingText();
508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            int selection = Selection.getSelectionStart(mEditable);
509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            deleteSurroundingText(selection - compositionStart, selection - compositionEnd);
510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            endBatchEdit();
511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            return true;
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return false;
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
51668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    @VisibleForTesting
51768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    static class ImeState {
51868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public final String text;
51968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public final int selectionStart;
52068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public final int selectionEnd;
52168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public final int compositionStart;
52268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public final int compositionEnd;
52368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
52468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        public ImeState(String text, int selectionStart, int selectionEnd,
52568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                int compositionStart, int compositionEnd) {
52668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            this.text = text;
52768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            this.selectionStart = selectionStart;
52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            this.selectionEnd = selectionEnd;
52968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            this.compositionStart = compositionStart;
53068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            this.compositionEnd = compositionEnd;
53168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    @VisibleForTesting
53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ImeState getImeStateForTesting() {
53623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        String text = mEditable.toString();
53723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int selectionStart = Selection.getSelectionStart(mEditable);
53823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int selectionEnd = Selection.getSelectionEnd(mEditable);
53923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int compositionStart = getComposingSpanStart(mEditable);
54023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int compositionEnd = getComposingSpanEnd(mEditable);
54168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        return new ImeState(text, selectionStart, selectionEnd, compositionStart, compositionEnd);
54268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
544