diff options
-rw-r--r-- | core/java/android/view/inputmethod/InputMethodManager.java | 44 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/EditableInputConnection.java | 54 |
2 files changed, 72 insertions, 26 deletions
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b41e6f5..0985e14 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -651,19 +651,7 @@ public final class InputMethodManager { } } - if (mServedInputConnection != null) { - // We need to tell the previously served view that it is no - // longer the input target, so it can reset its state. Schedule - // this call on its window's Handler so it will be on the correct - // thread and outside of our lock. - Handler vh = mServedView.getHandler(); - if (vh != null) { - // This will result in a call to reportFinishInputConnection() - // below. - vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION, - mServedInputConnection)); - } - } + notifyInputConnectionFinished(); mServedView = null; mCompletions = null; @@ -671,7 +659,25 @@ public final class InputMethodManager { clearConnectionLocked(); } } - + + /** + * Notifies the served view that the current InputConnection will no longer be used. + */ + private void notifyInputConnectionFinished() { + if (mServedView != null && mServedInputConnection != null) { + // We need to tell the previously served view that it is no + // longer the input target, so it can reset its state. Schedule + // this call on its window's Handler so it will be on the correct + // thread and outside of our lock. + Handler vh = mServedView.getHandler(); + if (vh != null) { + // This will result in a call to reportFinishInputConnection() below. + vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION, + mServedInputConnection)); + } + } + } + /** * Called from the FINISH_INPUT_CONNECTION message above. * @hide @@ -681,7 +687,7 @@ public final class InputMethodManager { ic.finishComposingText(); } } - + public void displayCompletions(View view, CompletionInfo[] completions) { checkFocus(); synchronized (mH) { @@ -831,7 +837,7 @@ public final class InputMethodManager { * shown with {@link #SHOW_FORCED}. */ public static final int HIDE_NOT_ALWAYS = 0x0002; - + /** * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} * without a result: request to hide the soft input window from the @@ -993,7 +999,7 @@ public final class InputMethodManager { tba.fieldId = view.getId(); InputConnection ic = view.onCreateInputConnection(tba); if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); - + synchronized (mH) { // Now that we are locked again, validate that our state hasn't // changed. @@ -1012,6 +1018,8 @@ public final class InputMethodManager { // Hook 'em up and let 'er rip. mCurrentTextBoxAttribute = tba; mServedConnecting = false; + // Notify the served view that its previous input connection is finished + notifyInputConnectionFinished(); mServedInputConnection = ic; IInputContext servedContext; if (ic != null) { @@ -1115,7 +1123,7 @@ public final class InputMethodManager { } } - void scheduleCheckFocusLocked(View view) { + static void scheduleCheckFocusLocked(View view) { Handler vh = view.getHandler(); if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) { // This will result in a call to checkFocus() below. diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index 32e733b..9579bce 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -35,6 +35,11 @@ public class EditableInputConnection extends BaseInputConnection { private final TextView mTextView; + // Keeps track of nested begin/end batch edit to ensure this connection always has a + // balanced impact on its associated TextView. + // A negative value means that this connection has been finished by the InputMethodManager. + private int mBatchEditNesting; + public EditableInputConnection(TextView textview) { super(textview, true); mTextView = textview; @@ -48,19 +53,35 @@ public class EditableInputConnection extends BaseInputConnection { } return null; } - + @Override public boolean beginBatchEdit() { - mTextView.beginBatchEdit(); - return true; + synchronized(this) { + if (mBatchEditNesting >= 0) { + mTextView.beginBatchEdit(); + mBatchEditNesting++; + return true; + } + } + return false; } - + @Override public boolean endBatchEdit() { - mTextView.endBatchEdit(); - return true; + synchronized(this) { + if (mBatchEditNesting > 0) { + // When the connection is reset by the InputMethodManager and finishComposingText + // is called, some endBatchEdit calls may still be asynchronously received from the + // IME. Do not take these into account, thus ensuring that this IC's final + // contribution to mTextView's nested batch edit count is zero. + mTextView.endBatchEdit(); + mBatchEditNesting--; + return true; + } + } + return false; } - + @Override public boolean clearMetaKeyStates(int states) { final Editable content = getEditable(); @@ -76,7 +97,24 @@ public class EditableInputConnection extends BaseInputConnection { } return true; } - + + @Override + public boolean finishComposingText() { + final boolean superResult = super.finishComposingText(); + synchronized(this) { + if (mBatchEditNesting < 0) { + // The connection was already finished + return false; + } + while (mBatchEditNesting > 0) { + endBatchEdit(); + } + // Will prevent any further calls to begin or endBatchEdit + mBatchEditNesting = -1; + } + return superResult; + } + @Override public boolean commitCompletion(CompletionInfo text) { if (DEBUG) Log.v(TAG, "commitCompletion " + text); |