19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007-2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * License for the specific language governing permissions and limitations under
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable;
21f9f01008624e2d28c15a90d942fa36f98c8c967dsatokimport android.text.Spanned;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.KeyListener;
23f9f01008624e2d28c15a90d942fa36f98c8c967dsatokimport android.text.style.SuggestionSpan;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.BaseInputConnection;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
27cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunneimport android.view.inputmethod.CorrectionInfo;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.ExtractedText;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.ExtractedTextRequest;
30a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawaimport android.view.inputmethod.InputConnection;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class EditableInputConnection extends BaseInputConnection {
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG = false;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "EditableInputConnection";
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final TextView mTextView;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // Keeps track of nested begin/end batch edit to ensure this connection always has a
40c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // balanced impact on its associated TextView.
41c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // A negative value means that this connection has been finished by the InputMethodManager.
42c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    private int mBatchEditNesting;
43c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public EditableInputConnection(TextView textview) {
4551bf077883df4f5cc816fbfec6d19eedffc26d70Dianne Hackborn        super(textview, true);
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView = textview;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
49cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Editable getEditable() {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TextView tv = mTextView;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tv != null) {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return tv.getEditableText();
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
57c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
58cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean beginBatchEdit() {
60c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        synchronized(this) {
61c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            if (mBatchEditNesting >= 0) {
62c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mTextView.beginBatchEdit();
63c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mBatchEditNesting++;
64c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                return true;
65c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
66c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        }
67c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        return false;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
69c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
70cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean endBatchEdit() {
72c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        synchronized(this) {
73c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            if (mBatchEditNesting > 0) {
749d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne                // When the connection is reset by the InputMethodManager and reportFinish
75c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // is called, some endBatchEdit calls may still be asynchronously received from the
76c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // IME. Do not take these into account, thus ensuring that this IC's final
77c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // contribution to mTextView's nested batch edit count is zero.
78c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mTextView.endBatchEdit();
79c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mBatchEditNesting--;
80c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                return true;
81c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
82c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        }
83c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        return false;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
85c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
86cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
879d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne    protected void reportFinish() {
889d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne        super.reportFinish();
899d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne
909d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne        synchronized(this) {
919d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne            while (mBatchEditNesting > 0) {
929d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne                endBatchEdit();
939d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne            }
949d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne            // Will prevent any further calls to begin or endBatchEdit
959d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne            mBatchEditNesting = -1;
969d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne        }
979d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne    }
989d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne
999d69ecbf61a4a142c3f4cbb9d5659faa6f85e832Gilles Debunne    @Override
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean clearMetaKeyStates(int states) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Editable content = getEditable();
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (content == null) return false;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KeyListener kl = mTextView.getKeyListener();
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (kl != null) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                kl.clearMetaKeyState(mTextView, content, states);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (AbstractMethodError e) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This is an old listener that doesn't implement the
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // new method.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
114c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
115c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    @Override
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean commitCompletion(CompletionInfo text) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "commitCompletion " + text);
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.beginBatchEdit();
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onCommitCompletion(text);
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.endBatchEdit();
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
124cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    /**
125cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne     * Calls the {@link TextView#onCommitCorrection} method of the associated TextView.
126cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne     */
127cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
128cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    public boolean commitCorrection(CorrectionInfo correctionInfo) {
129cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        if (DEBUG) Log.v(TAG, "commitCorrection" + correctionInfo);
130cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.beginBatchEdit();
131cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.onCommitCorrection(correctionInfo);
132cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.endBatchEdit();
133cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        return true;
134cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    }
135cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne
136cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performEditorAction(int actionCode) {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onEditorAction(actionCode);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
143cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performContextMenuAction(int id) {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.beginBatchEdit();
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onTextContextMenuItem(id);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.endBatchEdit();
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
152cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTextView != null) {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ExtractedText et = new ExtractedText();
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTextView.extractText(request, et)) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mTextView.setExtracting(request);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return et;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
165cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne
166cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performPrivateCommand(String action, Bundle data) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onPrivateIMECommand(action, data);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean commitText(CharSequence text, int newCursorPosition) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTextView == null) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.commitText(text, newCursorPosition);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
177f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        if (text instanceof Spanned) {
178f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            Spanned spanned = ((Spanned) text);
179f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            SuggestionSpan[] spans = spanned.getSpans(0, text.length(), SuggestionSpan.class);
180f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            mIMM.registerSuggestionSpansForNotification(spans);
181f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
183b7fc63f7aac3689696f7f84953009b5928ac3db3Gilles Debunne        mTextView.resetErrorChangedFlag();
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean success = super.commitText(text, newCursorPosition);
185b7fc63f7aac3689696f7f84953009b5928ac3db3Gilles Debunne        mTextView.hideErrorIfUnchanged();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return success;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1890023d0e0c4f5339b299d1eacbd4e7181c2fd271fYohei Yukawa
1900023d0e0c4f5339b299d1eacbd4e7181c2fd271fYohei Yukawa    @Override
191d8636ea7ca78df83d6b04088eab7853f15f3e999Yohei Yukawa    public boolean requestCursorUpdates(int cursorUpdateMode) {
192a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa        if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
193a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa
19472d35fa829549a138504dde35a42535a296f79cbYohei Yukawa        // It is possible that any other bit is used as a valid flag in a future release.
19572d35fa829549a138504dde35a42535a296f79cbYohei Yukawa        // We should reject the entire request in such a case.
196d8636ea7ca78df83d6b04088eab7853f15f3e999Yohei Yukawa        final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE |
197d8636ea7ca78df83d6b04088eab7853f15f3e999Yohei Yukawa                InputConnection.CURSOR_UPDATE_MONITOR;
19872d35fa829549a138504dde35a42535a296f79cbYohei Yukawa        final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK;
19972d35fa829549a138504dde35a42535a296f79cbYohei Yukawa        if (unknownFlags != 0) {
20072d35fa829549a138504dde35a42535a296f79cbYohei Yukawa            if (DEBUG) {
20172d35fa829549a138504dde35a42535a296f79cbYohei Yukawa                Log.d(TAG, "Rejecting requestUpdateCursorAnchorInfo due to unknown flags." +
20272d35fa829549a138504dde35a42535a296f79cbYohei Yukawa                        " cursorUpdateMode=" + cursorUpdateMode +
20372d35fa829549a138504dde35a42535a296f79cbYohei Yukawa                        " unknownFlags=" + unknownFlags);
20472d35fa829549a138504dde35a42535a296f79cbYohei Yukawa            }
20572d35fa829549a138504dde35a42535a296f79cbYohei Yukawa            return false;
20672d35fa829549a138504dde35a42535a296f79cbYohei Yukawa        }
20772d35fa829549a138504dde35a42535a296f79cbYohei Yukawa
208ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa        if (mIMM == null) {
209ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            // In this case, TYPE_CURSOR_ANCHOR_INFO is not handled.
210a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa            // TODO: Return some notification code rather than false to indicate method that
211ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            // CursorAnchorInfo is temporarily unavailable.
212a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa            return false;
213ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa        }
214a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa        mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode);
215d8636ea7ca78df83d6b04088eab7853f15f3e999Yohei Yukawa        if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) {
216ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            if (mTextView == null) {
217ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored.
218ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // TODO: Return some notification code for the input method that indicates
219ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is ignored.
220ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            } else if (mTextView.isInLayout()) {
221ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // In this case, the view hierarchy is currently undergoing a layout pass.
222ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout
223ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // pass is finished.
224ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            } else {
225ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // This will schedule a layout pass of the view tree, and the layout event
226ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                // eventually triggers IMM#updateCursorAnchorInfo.
227ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa                mTextView.requestLayout();
228ff328ae7438a9c5c2fe49c286833a30e25015e63Yohei Yukawa            }
2290023d0e0c4f5339b299d1eacbd4e7181c2fd271fYohei Yukawa        }
230a277db28e990d1f6f74ace0c32fe92401660a840Yohei Yukawa        return true;
2310023d0e0c4f5339b299d1eacbd4e7181c2fd271fYohei Yukawa    }
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
233