New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 592162 link

Starred by 3 users

Issue metadata

Status: ExternalDependency
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Android
Pri: 3
Type: Bug



Sign in to add a comment

Changing contenteditable content with JS during a key event causes composition state issues on Android

Reported by ryanac...@gmail.com, Mar 5 2016

Issue description

Example URL:
http://neilj.github.io/Squire/

Steps to reproduce the problem:
1. Open RTE
2. Start a list section
3. Type some text
4. Hit enter twice to exit list
5. Type some text
6. Press Space
7. Press backspace

What is the expected behavior?
Previous word is now underlined, word remains the same.

What went wrong?
Underline is offset by 1 character to the right, first letter of word is duplicated if you press another letter.

Does it occur on multiple sites: Yes

Is it a problem with a plugin? No 

Did this work before? N/A 

Does this work in other browsers? Yes 

Chrome version: 48.0.2564.95  Channel: stable
OS Version: 6.0
Flash Version: n/a

I'm a software engineer Quora, this is an issue we've encountered trying to get our rich text editor (RTE) to work properly on Android. You can also see this issue on other editors like Draft.js or Quill.js, but occurs by deleting the bullet point to exit a list instead of pressing enter, and state gets offset in the opposite direction.

This seems like it's somewhat the fault of the keyboard--the issue doesn't occur in Google Keyboard versions below 3.0. looked into this a bit, and it seems like the keyboard is trying to keep track of the expected cursor position (see com/android/inputmethod/latin/RichInputConnection.java), but it's wrong because it doesn't know that the second press of enter only exited the bulleted list and didn't add a character (and now mExpectedSelStart is offset). I think Chrome should be calling InputMethodManager#updateSelection(...) more often when the text changes in a way the keyboard might not expect.

I also noticed that in the Google Docs native Android app, the same thing happens if you do the sequence of events very quickly (and if you do it slightly slower you can see that there's some workaround happening since the composition underline changes).
 
device-2016-03-04-154226.mp4
1.2 MB Download

Comment 1 by kochi@chromium.org, Mar 7 2016

Components: -Blink Blink>Editing
Owner: yosin@chromium.org
Status: Assigned (was: Unconfirmed)

Comment 2 by yosin@chromium.org, Mar 7 2016

Owner: aelias@chromium.org
Is this buffer synchronization between keyboard app and Blink?
Cc: aelias@chromium.org
Owner: changwan@chromium.org
Labels: Needs-Feedback
Google Doc native app doesn't use webview. So probably this is not a chrome / webview issue.

I, too, suspect that this is a Google keyboard issue, especially so if this has to do with the timing. There is a known race condition in a list of Google Keyboard apps which recently got fixed: b/27193048 (Google internal).

But if this is indeed a webview issue, probably the recent IME redesign might have fixed it.
On Chromium, you could try this by going to 'about:flags' and enable 'Run IME on its own thread' flag.

ryanacheu@gmail.com,
Could you check if you could reproduce the same issue with another well-known keyboard app?

I mentioned Google Docs since chromium (in Java/C++ code) could probably use whatever workaround they use (I know it doesn't use a webview).

It also appears in SwiftKey, and Swype, but not Go Keyboard or Samsung's Keyboard.

The 'Run IME on its own thread' flag puts it into the same state as Google Docs where it's good as long as you don't do the action too quickly, much better though!
Thanks for the quick turnaround. And thanks for testing with development version of chrome.

This is a generic conflict handling problem. The previous version of chrome / webview is just bad at conflict resolution. The renderer will think it's A, B, C while browser will think the order is A, C, B, and weird things happen.

Do you still think chromium should call updateSelection more often in this case?
Since there is no other way to provide the conflict information to the input method app,
we just finish the currently composed text. Keyboard apps should be able to handle the conflict signal, but may not be able to do so in some cases.

By the way, one more question. Do you see the exact same issue with the flag on / off with the mentioned keyboards (when there is a problem) when you type fast enough? Or was there any difference in the results when you tested?

My suggestion of calling updateSelection more often was because I noticed the keyboard doesn't know where the cursor is. I put some logging in the keyboard and noticed that the issue was occurring when the keyboard tried to re-enter the suggestions for the previous word and called setComposingRegion with the wrong cursor position.

Every keypress was incrementing where the keyboard thought the cursor is, and chrome never sent an update to the keyboard telling it that the cursor position was actually at N-2 because one of the returns actually deleted a bullet, not added a newline. I tried a quick change in chromium to try to make it send the updateSelection more often so that it knew the correct cursor position, and that worked, but it caused text to randomly duplicate sometimes (race condition?). I figured you guys would know how to fix it better :)

Looking at the keyboard logcat for the webview with the flag on, the same thing happens now, but then updateSelection is called shortly afterwards with the correct selection/composition position. If I press the backspaces quickly, it seems like this update doesn't reach in time and it gets into a bad state.

For you last question, the behavior with the flag on, but issuing the commands quickly, is the same as the behavior with the flags off but issuing the commands at a normal or slow pace.


Ok, I had a chance to look at this today, and it seems that there is a complicated bug in Google Keyboard. Here is the sequence that leads to such a condition:

1. When typing enter key twice to exit the list mode, we keep updating the selection changes. However, the second enter key was used only for exiting the list mode, resulting in 'one new line' in the text. We update selection again in this situation, but Android's InputMethodManager internally ignores selection update when it's exactly the same as the previous update. So Google Keyboard does not seem to understand that the second enter key has been handled.

2. When typing AA and a space, Google Keyboard still thinks that editor
should supposedly have two new lines and AA and then a space. Now pressing backspace will trigger setComposingRegion() but it tries to set the region from the second A and the space because it internally keeps an incorrect state.

Latest version of Chrome does not seem to have this problem (with or without IME thread option turned on) with Google Keyboard. It seems to me that Google Keyboard tries to correct the state after its first trial only for the latest version.

I think Google Keyboard (and all the other keyboards) may need to handle silent selection update better.

Status: ExternalDependency (was: Assigned)
Filed b/27781317 for internal tracking of the issue for Google Keyboard.
Yes that's the same conclusion I came to when I investigated this bug (wrong keyboard state when you have diff # of characters than a plaintext doc).

I can still reliably reproduce the bug in the latest Chrome Dev build on the play store using the steps in the video.

If it's helpful, we fixed this in our webview based native app by calculating the correct position in JS and calling InputConnectionWrapper#setSelection whenever we think the internal keyboard state will get out of sync by passing a message to native.
Re #10, I'm afraid that it will end up in a race condition when you type quickly. Also, please note that setSelection() will not help the situation when we migrate to IME thread approach.

BTW, is this one of the reasons why Quora overrides WebView#onCreateInputConnection()? Are there some other workarounds?

It can lead to a race condition, but it's preferred since users naturally pause after hitting enter (I also haven't been able to trigger it by exiting lists, only by holding delete while deleting lists with multiple indent levels).

This is currently the only workaround, we previously had others for older Android versions. We switched to using Crosswalk (a Chromium fork) for the editor recently to reach better consistency across versions.
Labels: Pri-3

Sign in to add a comment