Unbalanced batch edit begin and end leave TextView unresponsive
This is a fix for http://code.google.com/p/android/issues/detail?id=17508 Adding some logs and a forced GC, I'm now reliably able to reproduce it. Here is the scenario. 1. The IME handles an event. It retrieves the current InputConnection (IC) using ic = getCurrentInputConnection() and calls ic.beginBatchEdit(); 2. The call is propagated to the UI thread and TextView's mBatchEditNesting is correctly increased through beginBatchEdit() 3. A listener calls setText(), which imm.restartInput(this); 4. As a result, the InputMethodManager creates a new ControlledInputConnectionWrapper with a new InputConnection from the TextView 5. A GC happens at that point. The previous InputConnection is no longeri referenced by the InputMethodManager's mServedInputConnection. The weak reference in the previous ControlledInputConnectionWrapper is nulled. 6. The IME thread finishes its process and calls ic.endBatchEdit(); on its version of the original InputConnection. 7. The message is passed through the InputConnect, but when the weak reference in the original IInputConnectionWrapper is dereferenced, we get a null InputConnection in executeMessage(). 8. As a result, the TextView's endBatchEdit() method is not called, leaving this TextView with a non zero mBatchEditNesting. 9. From now on, all edit actions on this TextView will be considered part of a nested edition and no invalidation is performed, which is the visible manifestation of this bug. The core problem is that the begin/end batch edit contract is broken when: 1. These are initiated by the IME thread (as opposed to the UI thread) 2. The input connection is reset between these calls 3. A GC happens in the mean time and the WeakReference is lost (otherwise calling endBatchEdit on a no longer active InputConnection is fine Solution to keep TextView's mBatchEditNesting balanced: - The IMM should notify the IC when it is no longer used. We're using the existing FINISH_INPUT_CONNECTION to do that. - The InputConnection should keep track of its nesting contribution to the TextView. When finished the IC makes sure its contribution is reset to 0. Moreover, further asynchonous calls to begin/endBatchEdit that may arrive from the IME should be ignored. This is achieved using a negative value as a flag. Notes: - finishComposingText may be too broad of a method to perform such a cleaning step but is seems to only be called in cases where the IC will not be used anymore. If that's too broad, we have to introduce a new method in the IC interface. - This is has been implemented in EditableInputConnection and not in a more general BaseInputConnection because this is where we have a notion of TextEdit, and the nesting problem is here specific to TextView. However, the same unbalanced begin/end problem will happen in these classes. They should override finishComposingText as has been done here if that matters. - We cannot re-use the TextView's mBatchEditNesting since it may take into account batch edit from various sources and resetting it on InputConnection close could then lead to an inconsistent negative count value. Patch Set 2: added synchronized blocks around mBatchEditNesting Change-Id: I1ec5518fdc16fb0551fbce9d13f5d92eb4bc78c0
Loading
Please register or sign in to comment