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