EditableInputConnection.java revision c478c171e92b2f255e9699d9c9306b001368ac20
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;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class EditableInputConnection extends BaseInputConnection {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG = false;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "EditableInputConnection";
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final TextView mTextView;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // Keeps track of nested begin/end batch edit to ensure this connection always has a
39c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // balanced impact on its associated TextView.
40c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    // A negative value means that this connection has been finished by the InputMethodManager.
41c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    private int mBatchEditNesting;
42c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public EditableInputConnection(TextView textview) {
4451bf077883df4f5cc816fbfec6d19eedffc26d70Dianne Hackborn        super(textview, true);
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView = textview;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Editable getEditable() {
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TextView tv = mTextView;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tv != null) {
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return tv.getEditableText();
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
56c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
57cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean beginBatchEdit() {
59c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        synchronized(this) {
60c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            if (mBatchEditNesting >= 0) {
61c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mTextView.beginBatchEdit();
62c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mBatchEditNesting++;
63c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                return true;
64c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
65c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        }
66c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        return false;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
68c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
69cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean endBatchEdit() {
71c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        synchronized(this) {
72c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            if (mBatchEditNesting > 0) {
73c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // When the connection is reset by the InputMethodManager and finishComposingText
74c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // is called, some endBatchEdit calls may still be asynchronously received from the
75c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // IME. Do not take these into account, thus ensuring that this IC's final
76c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // contribution to mTextView's nested batch edit count is zero.
77c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mTextView.endBatchEdit();
78c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                mBatchEditNesting--;
79c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                return true;
80c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
81c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        }
82c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        return false;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
84c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
85cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean clearMetaKeyStates(int states) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Editable content = getEditable();
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (content == null) return false;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KeyListener kl = mTextView.getKeyListener();
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (kl != null) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                kl.clearMetaKeyState(mTextView, content, states);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (AbstractMethodError e) {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This is an old listener that doesn't implement the
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // new method.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
100c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
101c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    @Override
102c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    public boolean finishComposingText() {
103c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        final boolean superResult = super.finishComposingText();
104c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        synchronized(this) {
105c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            if (mBatchEditNesting < 0) {
106c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                // The connection was already finished
107c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                return false;
108c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
109c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            while (mBatchEditNesting > 0) {
110c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne                endBatchEdit();
111c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            }
112c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            // Will prevent any further calls to begin or endBatchEdit
113c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne            mBatchEditNesting = -1;
114c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        }
115c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne        return superResult;
116c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne    }
117c478c171e92b2f255e9699d9c9306b001368ac20Gilles Debunne
118cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean commitCompletion(CompletionInfo text) {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "commitCompletion " + text);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.beginBatchEdit();
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onCommitCompletion(text);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.endBatchEdit();
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
127cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    /**
128cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne     * Calls the {@link TextView#onCommitCorrection} method of the associated TextView.
129cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne     */
130cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
131cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    public boolean commitCorrection(CorrectionInfo correctionInfo) {
132cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        if (DEBUG) Log.v(TAG, "commitCorrection" + correctionInfo);
133cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.beginBatchEdit();
134cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.onCommitCorrection(correctionInfo);
135cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        mTextView.endBatchEdit();
136cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne        return true;
137cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    }
138cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne
139cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performEditorAction(int actionCode) {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onEditorAction(actionCode);
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
146cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performContextMenuAction(int id) {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.beginBatchEdit();
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onTextContextMenuItem(id);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.endBatchEdit();
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
155cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTextView != null) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ExtractedText et = new ExtractedText();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mTextView.extractText(request, et)) {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mTextView.setExtracting(request);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return et;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
168cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne
169cf9cf2f40efc4ccf3f73e6fdb07725d9c00c4f91Gilles Debunne    @Override
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean performPrivateCommand(String action, Bundle data) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTextView.onPrivateIMECommand(action, data);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean commitText(CharSequence text, int newCursorPosition) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTextView == null) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.commitText(text, newCursorPosition);
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
180f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        if (text instanceof Spanned) {
181f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            Spanned spanned = ((Spanned) text);
182f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            SuggestionSpan[] spans = spanned.getSpans(0, text.length(), SuggestionSpan.class);
183f9f01008624e2d28c15a90d942fa36f98c8c967dsatok            mIMM.registerSuggestionSpansForNotification(spans);
184f9f01008624e2d28c15a90d942fa36f98c8c967dsatok        }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
186b7fc63f7aac3689696f7f84953009b5928ac3db3Gilles Debunne        mTextView.resetErrorChangedFlag();
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean success = super.commitText(text, newCursorPosition);
188b7fc63f7aac3689696f7f84953009b5928ac3db3Gilles Debunne        mTextView.hideErrorIfUnchanged();
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return success;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
193