Merge "Unbalanced batch edit begin and end leave TextView unresponsive"
This commit is contained in:
committed by
Android (Google) Code Review
commit
3f696b264e
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user