-
Notifications
You must be signed in to change notification settings - Fork 6k
unhide uitextinput when focused #23776
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
gaaclarke
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.
Nice detective work. I can't think of why this wouldn't be an acceptable fix. My biggest concern would be that we could swipe to have voiceover announce a widget that should be hidden after showTextInput is called but before hideTextInput. I'd make sure that couldn't happen with manual testing.
| // mimic the semantics tree from Flutter. We want the text field to be represented as a | ||
| // `TextInputSemanticsObject` in that `SemanticsObject` tree rather than in this | ||
| // `FlutterTextInputView` bridge which doesn't appear above a text field from the Flutter side. |
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 should update this comment.
| @property(nonatomic, readonly) CATransform3D editableTransform; | ||
| @property(nonatomic, assign) CGRect markedRect; | ||
| @property(nonatomic) BOOL isVisibleToAutofill; | ||
| @property(nonatomic) BOOL hidden; |
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.
This should be called something like accessibilityHidden.
|
@gaaclarke thanks for reminding, this PR doesn't work, i am able to swipe to focus the FlutterTextInputView. I couldn't find a way to be able to make voiceover respond to UITextInput event while keeping the FlutterTextInputView hidden from accessibility focus. At this moment, I am thinking whether there is a way to point the TextInputSemanticsObject to the FlutterTextInputView |
|
@chunhtai: Based on your last comment, it looks like this PR is not quite ready to land. Is that accurate? Can we close it or mark it WIP? |
f796fc9 to
1f26688
Compare
|
I have revised this pr. Test will be added once we confirm we want to proceed with this fix There are three fail-safes I added to the
|
|
@gaaclarke @xster Can you take another look whether this is what we want to do? I will add more tests once we confirm that. |
gaaclarke
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.
Jeez, this is hard to review. I understand it's a hack. Why did you choose 0.5s? If the problem we are trying to fix is the missing of the announcement of typed characters it seems like 0.5s could be ample time to miss a character.
| // with a semantics update sent to the engine. The voiceover will focus | ||
| // the newly attached active view while performing accessibility update. | ||
| // This results in accessibility focus stuck at the FlutterTextInputView. | ||
| [NSTimer scheduledTimerWithTimeInterval:_kUITextInputAccessibilityEnablingDelaySeconds |
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.
This causes the plugin to live beyond the point it would be dealloc'd previously. If you do this you should maintain a reference to the timer and invalidate it in dealloc.
| + (UIAccessibilityElement*)backingTextInputAccessibilityObject { | ||
| return _backingTextInputAccessibilityObject; | ||
| } | ||
|
|
||
| + (void)setBackingTextInputAccessibilityObject:(UIAccessibilityElement*)element { | ||
| _backingTextInputAccessibilityObject = element; | ||
| } |
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.
There is no need to make these methods, this should just be a property.
| * There are other cases the `FlutterTextInputView` may receive | ||
| * focus. One example is during screen changes, the accessibility | ||
| * tree will undergo a dramatic structural update. The Voiceover may | ||
| * decide to focus the `FlutterTextInputView` that is not involved | ||
| * in the structural update instead. If that happens, the | ||
| * `FlutterTextInputView` will make a best effort to direct the | ||
| * focus back to the `SemanticsObject`. |
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.
Couldn't this result in duplicate Voiceover announcements? One for the FlutterTextInputView and one SemanticsObject?
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.
that is true, that is why i put the first two fail safe and hope it can catch all of the corner cases.
If this text view does receive the focus, duplicate announcement is still much better than focus just stuck at this textview.
I have tried a number of different hack such as changing the trait and label of this text view to prevent voiceover from pronouncing any word when the text view is focused, but none of them work. If you have a textview without any trait or label, it will pronounce some random phrase such as "blue sky" when it is focused.
| // with a semantics update sent to the engine. The voiceover will focus | ||
| // the newly attached active view while performing accessibility update. | ||
| // This results in accessibility focus stuck at the FlutterTextInputView. | ||
| [NSTimer scheduledTimerWithTimeInterval:_kUITextInputAccessibilityEnablingDelaySeconds |
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 proper constant name in objective-c doesn't have a _ at the beginning.
I apologize for putting out such confusing workaround. I couldn't find a more systematic wait for delay this enable. The 0.5s is an eye ball value. we can probably decrease it even more, but overall do you think this is something we want to do? Another idea is that we can wait until we detect any flutter semantics object has received focus before we enable the text view, but it will be much bigger than 0.5s. |
|
@gaaclarke Hi 0.5 seems to be the lowest possible timeout; otherwise, the may still focus the textfield. I am not sure if this is device specific, but if the other low end iOS device can still focus textfield with 0.5 delay, they will be caught in fail safe 3. |
|
I will do some more clean up, but i think this is the best we can do for now. |
9101a8f to
2d9e990
Compare
|
@gaaclarke Does your previous approval need to be revised? If so, can you review again please? |
| NSTimer* _enableFlutterTextInputViewAccessibilityTimer; | ||
|
|
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.
This is a global variable as written, you need to put this in braces.
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.
oops nice catch. will update
| - (void)removeEnableFlutterTextInputViewAccessibilityTimer { | ||
| if (_enableFlutterTextInputViewAccessibilityTimer) { | ||
| [_enableFlutterTextInputViewAccessibilityTimer invalidate]; | ||
| _enableFlutterTextInputViewAccessibilityTimer = nil; |
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.
This is a leak, sorry i didn't see it earlier. You need to retain this below, and release this here.
| - (void)dealloc { | ||
| [self hideTextInput]; | ||
| [_reusableInputView release]; | ||
| [_inputHider release]; |
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.
there needs to be [_enableFlutterTextInputViewAccessibilityTimer release] as well =)
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.
that will be trigger by hideTextInput, my thinking is that the timer is created in showtextinput, so it should be removed in hidetextinput
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.
Yea, I think in practice you are right since the timer will retain the FlutterTextInputPlugin until the timer fires.
| if (_activeView.isFirstResponder) { | ||
| _activeView.accessibilityEnabled = YES; | ||
| } | ||
| _enableFlutterTextInputViewAccessibilityTimer = nil; |
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.
there needs to be a release here... maybe it would just be easier if you used a property for this.
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.
thanks for reminding.
65537df to
822c05c
Compare
|
This pull request is not suitable for automatic merging in its current state.
|
|
Can i request that this change get cherry picked into the 1.26 release? |
To make the UITextInput work properly, its accessibilityElementsHidden must return NO.
This pr makes sure to toggle it on or off when it is focused. However, I am not sure if there will be any side effect when doing this. Will write test once we confirm this is what we want to do.
Fixes flutter/flutter#71885
Pre-launch Checklist
writing and running engine tests.
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.