-
Notifications
You must be signed in to change notification settings - Fork 6k
Fix accessibility focus loss when first focusing on text field #17803
Conversation
| _nonAutofillInputView = [[FlutterTextInputView alloc] init]; | ||
| _nonAutofillInputView.secureTextEntry = NO; | ||
| _nonAutofillInputView = [[FlutterTextInputView alloc] init]; | ||
| _nonAutofillSecureInputView = [[FlutterTextInputView alloc] init]; |
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 must be a bug
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.
Code looks fine. Did you see it's breaking a unit test? Man, these scenario tests are a mess. There is so many moving pieces it is going to be a nightmare to maintain this if it breaks since the linkage in the code isn't apparent. I wonder if there is some better way we can start organizing them so the dart code and the platform code are in the same folder so it's a bit more clear.
|
|
||
| if (![_activeView isDescendantOfView:_inputHider]) { | ||
| [_inputHider addSubview:_activeView]; | ||
| if (!_activeView.window) { |
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 (_activeView.window != keyWindow) would be a bit safer.
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.
ah right, thanks
| flutterViewController = [[FlutterViewController alloc] initWithEngine:engine | ||
| nibName:nil | ||
| bundle:nil]; | ||
| return [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle: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.
Can you throw a FLUTTER_ASSERT_ARC or FLUTTER_ASSERT_NOT_ARC at the top of this file?
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.
none of the files in testing/ has it. Do you think it's something we'll run into?
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 hard to review files if you don't know if they are ARC or not. You need to import FlutterMacros.h. The line I've highlighted is correct for ARC, a leak for not ARC.
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 just meant whether we've had cases where we built the engine locally or on LUCI without ARC in the past? I would imagine everything failing spectacularly everywhere if we did rather than having to gate on a file-per-file basis. But I don't really have much context, I'm just guessing.
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.
ARC can be turned on and off on a file-by-file basis. The Engine is built without ARC, this file is part of a whole different binary though and looks as if it is being compiled with ARC, which is fine. In a world where some objective-c code is ARC and some is not; it's hard to do code reviews. The macro is helpful until that magical day that will never come where all of our code is ARC.
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.
got it. Thanks for the context. Added
| XCUIElement* textInputSemanticsObject = | ||
| [[[self.application textFields] matchingIdentifier:@"flutter textfield"] element]; | ||
| XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:5]); | ||
| XCTAssertEqual([textInputSemanticsObject valueForKey:@"hasKeyboardFocus"], @(NO)); |
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.
XCTAssertFalse, you are doing pointer comparisons on objects.
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.
FYI alternatively you could use, xctassertequalobjects.
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 think @NO/__objc_no is a singleton and is a true-y (!= nil) value 🤣
But XCTAssertEqualObjects does show a nicer error when it doesn't match. Changed.
| textInputSemanticsObject = | ||
| [[[self.application textFields] matchingIdentifier:@"focused flutter textfield"] element]; | ||
| XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:5]); | ||
| XCTAssertEqual([textInputSemanticsObject valueForKey:@"hasKeyboardFocus"], @(YES)); |
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.
XCTAssertTrue
| // real text entry events to the framework. | ||
| delegateTextInput = [[self.application textViews] element]; | ||
| XCTAssertTrue([delegateTextInput waitForExistenceWithTimeout:5]); | ||
| XCTAssertEqual([delegateTextInput valueForKey:@"hasKeyboardFocus"], @(YES)); |
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.
XCTAssertTrue
| ).buffer.asByteData(), | ||
| callback, | ||
| ); | ||
| } No newline at end of file |
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.
no newline
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.
done
|
|
||
| /// Util method to replicate the behavior of a `MethodChannel` in the Flutter | ||
| /// framework. | ||
| void sendMethodCall({ |
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 use the json codec typically not the standard message codec? maybe the name should reflect json or take in an optional argument of the codec?
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.
oh ya good call. Only our system channels are being weird with json codecs. Good point. Name changed.
| currentValueLength: 0, | ||
| scrollChildren: 0, | ||
| scrollIndex: 0, | ||
| transform: Float64List.fromList(<double>[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 366.5, 0.0, 1.0]), |
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.
Isn't there a function somewhere where you can make a translation matrix? For readabilities sake you should at least have a local one.
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 just copy pasted it from a real run but it doesn't actually matter for the purpose of this test. Removed.
|
oops, I missed a lint. ya I agree, it's a pile on right now. There were so many more things I wanted to do as I was looking at it :) I want to clean up a bit more next |
34688d7 to
636285d
Compare
| // Find the inactive autofillable input field. | ||
| // Find all the FlutterTextInputViews we created. | ||
| NSArray<FlutterTextInputView*>* inputFields = [[[[textInputPlugin textInputView] superview] | ||
| subviews] |
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.
can't believe this is what the autoformatter wants...
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.
lgtm modulo the presubmit failures.
de55c21 to
28f5cca
Compare
flutter/engine@2b94311...4f888d6 git log 2b94311..4f888d6 --first-parent --oneline 2020-04-25 [email protected] Change the repo fetch script used in integration tests (flutter/engine#17943) 2020-04-24 [email protected] Roll src/third_party/skia 1e21d14f2b8b..c12aad9485a9 (20 commits) (flutter/engine#17942) 2020-04-24 [email protected] Roll src/third_party/dart a69cb6d700f5..216e3df4526c (16 commits) (flutter/engine#17945) 2020-04-24 [email protected] Fix accessibility focus loss when first focusing on text field (flutter/engine#17803) 2020-04-24 [email protected] Roll fuchsia/sdk/core/linux-amd64 from _dAFU... to G4HpJ... (flutter/engine#17938) 2020-04-24 [email protected] [web] Fix exception when getting boxes for rich text range (flutter/engine#17933) 2020-04-24 [email protected] [web] Batch systemFontChange messages (flutter/engine#17885) 2020-04-24 [email protected] Roll fuchsia/sdk/core/linux-amd64 from kpECk... to _dAFU... (flutter/engine#17929) 2020-04-24 [email protected] Roll src/third_party/skia b965ff597315..1e21d14f2b8b (25 commits) (flutter/engine#17928) 2020-04-24 [email protected] Roll src/third_party/dart 94178e920ee8..a69cb6d700f5 (22 commits) (flutter/engine#17926)
Fixes flutter/flutter#53065
I hope #17493 had good tests since I had to merge :)
The nature of the bug is that despite vague documentation,
accessibilityElementsHiddenon UIView doesn't seem to also hide its subviews from accessibility. When we first focus on a text field from the Flutter side, we create and add aFlutterTextInputViewonto the view hierarchy above everything else. We intended to hide it but it never worked and since the accessibility bridge also sends various UIAccessibilityPostNotification, the new, higher, invisibleFlutterTextInputViewtakes the focus.I really wanted to have an integration test for this but unfortunately concluded that we can't have an exact test for this because:
UIAccessibilityPostNotification(UIAccessibilityResumeAssistiveTechnologyNotification, UIAccessibilityNotificationVoiceOverIdentifier)crashes on simulator andUIAccessibilityNotificationSwitchControlIdentifieris input only (doesn't have focus highlighting).I added some integration tests for the general accessibility bridge semantics node translation and focusing functionalities, but it doesn't test this issue specifically.