-
Notifications
You must be signed in to change notification settings - Fork 6k
[Android Text Input] Make the editing state listenable and allow batch edits #21534
[Android Text Input] Make the editing state listenable and allow batch edits #21534
Conversation
| mRepeatCheckNeeded = false; | ||
| // Called when the current text editing state held by the text input plugin is overwritten by a | ||
| // newly received value from the framework. | ||
| public void didUpdateEditingValue() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The android text input plugin doesn't seem to completely overwrite the input state with the newly received value, the composing range is ignored. If the text is composing and the user replaces the entire string with something else, would that put the input method in a broken state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried it out? Ignoring the composing region definitely seems incorrect. If there's no visible bug, maybe it's fixing itself when subsequent edits happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried a 3rd party japanese IME that uses composing region, it's not working in flutter apps (not composing at all). I'll see if there's an easy fix.
update it seems the Japanese input bug fixed itself.
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as long as the tests pass. There is one failing now but I think it's just a problem with a test.
Thanks for jumping on all of these refactors, it's going to be a lot cleaner.
| mRepeatCheckNeeded = false; | ||
| // Called when the current text editing state held by the text input plugin is overwritten by a | ||
| // newly received value from the framework. | ||
| public void didUpdateEditingValue() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried it out? Ignoring the composing region definitely seems incorrect. If there's no visible bug, maybe it's fixing itself when subsequent edits happen.
|
|
||
| @Override | ||
| public boolean performEditorAction(int actionCode) { | ||
| markDirty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's great seeing all these markDirty's going away. This seems so much simpler.
|
I don't think the failure is a flake. Can we fix the presubmit and land this? |
ca21217 to
0f1e22f
Compare
0f1e22f to
163685d
Compare
|
@LongCatIsLooong: Can you tell if the failure is a flake? And, if not, land this patch? |
|
The failure doesn't look related. There's still something in the PR I'm trying to fix. Turning this into a draft. |
55d4578 to
0339d06
Compare
0339d06 to
f6905d7
Compare
| } | ||
| } | ||
|
|
||
| public final int getSelecionStart() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo, did you mean getSelection?
| return Selection.getSelectionStart(this); | ||
| } | ||
|
|
||
| public final int getSelecionEnd() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, getSelection
| @Override | ||
| public boolean deleteSurroundingText(int beforeLength, int afterLength) { | ||
| if (Selection.getSelectionStart(mEditable) == -1) return true; | ||
| if (mEditable.getSelecionStart() == -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*getSelectionStart
|
|
||
| private BaseInputConnection mDummyConnection; | ||
|
|
||
| // The View is only use for creating a dummy BaseInputConnection for setComposingRegion. The View |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is only used
| } | ||
| if (mBatchEditNestDepth == 1 && !mListeners.isEmpty()) { | ||
| mTextWhenBeginBatchEdit = toString(); | ||
| mSelectionStartWhenBeginBatchEdit = getSelecionStart(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getSelection
| boolean textChanged, boolean selectionChanged, boolean composingRegionChanged); | ||
| } | ||
|
|
||
| private static final String TAG = "flutter"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to use a tag specific to the class name in some cases, but (don't quote me on this) the tool may filter for flutter explicitly, so you should probably verify the message is visible when you want it to be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated all 3 classes to use their class names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change the level to Log.v it doesn't show up even if I change the TAG to "flutter" and use flutter run -v.
| view, inputTarget.id, textInputChannel, keyProcessor, mEditable, outAttrs); | ||
| outAttrs.initialSelStart = Selection.getSelectionStart(mEditable); | ||
| outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable); | ||
| outAttrs.initialSelStart = mEditable.getSelecionStart(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getSelectionStart and getSelectionEnd
| // ### Keep the AFM updated | ||
| // | ||
| // The autofill session connected to The AFM keeps a copy of the current state for each reported | ||
| // field in "AutofillVirtualStructure"(instead of holding a reference to those fields), so the AFM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, space between " and (
GaryQian
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, with a few nits
batch edits (flutter#21534)", reverted in (flutter#22434) This reverts commit 23b6310.
Description
Make the
Editableheld by both the input connection and the text input plugin listenable and allows for batch edits. I might have reinvented the wheel since there're already mechanisms likeTextWatcherandSpanWatcher, but they don't seem to account for batch editing.Most of the time when the editing state changes we need to notify the input method manager or the autofill manager. They do not care where each change comes from (framework or input method or autofill), nor do they directly modify the current editing state.
Now
TextInputPluginandInputConnectionAdaptorboth listen to the sharedListenableEditingState:TextInputPluginsends text editing state update to the framework when a change is detected, also it notifies the autofill manager of text changes.InputConnectionAdaptorsends updates to the input method manager when the editing state is changed.Related PR
Fixes: flutter/flutter#69111
flutter/flutter#66864
#20160
Tests
I added the following tests:
setTextInputEditingState_doesNotInvokeUpdateEditingState
inputConnectionAdaptor_skipCallsAfterEditingValueUpdateFromFramework
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.