summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Debunne <debunne@google.com>2012-01-25 15:08:29 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-01-25 15:08:29 -0800
commit3f696b264e4a3dd28421e9e1a58fe2c6241f48e4 (patch)
tree6fef94dac48e49f1751ff930019313cf4140a146
parent842e379074e069d0273711399f45a2d7109f9e64 (diff)
parentc478c171e92b2f255e9699d9c9306b001368ac20 (diff)
downloadframeworks_base-3f696b264e4a3dd28421e9e1a58fe2c6241f48e4.zip
frameworks_base-3f696b264e4a3dd28421e9e1a58fe2c6241f48e4.tar.gz
frameworks_base-3f696b264e4a3dd28421e9e1a58fe2c6241f48e4.tar.bz2
Merge "Unbalanced batch edit begin and end leave TextView unresponsive"
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java44
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java54
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);