Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copied Apple's semantics for switches, made checkboxes the same. #16211

Merged
merged 11 commits into from
Feb 5, 2020

Conversation

gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented Jan 29, 2020

Related issue: flutter/flutter#49259

Started delegating accessibility calls to a real UISwitch in order to get the same behavior from flutter switches as UISwitch with respect to VoiceOver.

@goderbauer
Copy link
Member

If I focus on a native switch in iOS it does says something like "on/off, double tap to toggle setting". It doesn't say "0/1, Button".

0 or 1 does not seem like an appropriate announcement for a switch.

@gaaclarke
Copy link
Member Author

If I focus on a native switch in iOS it does says something like "on/off, double tap to toggle setting". It doesn't say "0/1, Button".

0 or 1 does not seem like an appropriate announcement for a switch.

It absolutely does, I'm not just making stuff up Michael, lol. See the attached XCode project and Accessibility Inspector screenshot. If it says anything else that is a customization of the semantics from the app developer. We can't make it say anything else unless we want to tackle localization of "on" and "off". It makes more sense that an app developer would handle that, that's why I only supply "1" and "0" if a value isn't already specified.

Screen Shot 2020-01-29 at 5 28 16 PM

Switch.zip

@gaaclarke
Copy link
Member Author

@goderbauer and I looked at this on device, Accessibility Inspector and the device report different results.

@chinmaygarde
Copy link
Member

looked at this on device, Accessibility Inspector and the device report different results.

Wonderful.

@chinmaygarde chinmaygarde self-requested a review January 30, 2020 19:30
@gaaclarke
Copy link
Member Author

@goderbauer I made the changes we talked about in person, please review.

@gaaclarke
Copy link
Member Author

gaaclarke commented Jan 30, 2020

Also, I kept the old logic in. It shouldn't get hit because FlutterSwitchSemanticsObject will override those calls, but it is more correct and safer in case something breaks.

/// A proxy class for SemanticsObject and UISwitch. For most Accessibility and
/// SemanticsObject methods it delegates to the semantics object, otherwise it
/// sends messages to the UISwitch.
@interface FlutterSwitchSemanticsObject : UISwitch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely lack some context here which is making it hard for me to review this. Why is this object a switch subclass? It is not going to be ever used as a switch. That is, it is not in the view hierarchy and you have already overridden most of ally methods. If you wanted to delegate to the base classes implementation of the a11y methods, the responses will be based on a switch in its default state (and not how it appears in the Flutter view hierarchy). Towards that end, shouldn't it be on the implementation to override all the a11y methods as necessary here?

Again. I could be missing something but the base class and the forwarding I don't get the point of.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I can explain. There is magic that happens on iOS for UISwitch with respect to VoiceOver. If you look at the results of a UISwitch's accessibility methods, it doesn't match up to what VoiceOver actually says. In order to get the magic the SemanticsObject has to be a UISwitch (it has undocumented methods or there is some reflection happening). We do something similar for text fields.

@goderbauer
Copy link
Member

Can you update the PR description with what's actually announced for a switch now?

return @([self node].value.data());
}

if ([self node].HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this code and just continue to use the UIAccessibilityTraitSelected as a fallback? (That code should also get a comment explaining why it should never trigger)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was there was wrong for 3 reasons:

  1. 'Selected' has wholly different semantics for users of VoiceOver
  2. The VoiceOver never explained the negative state, only the positive
  3. There was no indication that you could interact with the object

The way things are setup this should never happen, but {false: ("Autosave", "0", "Button") true: ("Autosave", "1", "Button")} is more informative and correct than {false:("Autosave") true:{"Selected", "Autosave"}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments.

@@ -765,6 +848,13 @@ - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction {
!node.HasFlag(flutter::SemanticsFlags::kIsReadOnly)) {
// Text fields are backed by objects that implement UITextInput.
object = [[[TextInputSemanticsObject alloc] initWithBridge:GetWeakPtr() uid:uid] autorelease];
} else if (node.HasFlag(flutter::SemanticsFlags::kHasToggledState) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll probably also have to add some code below to handle the case where a SemanticsNode switches from having these flags to not having them and vice versa.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can that happen that a node will have kHasToggledState and then it doesn't? That seems like it would be immutable in practice since a new SemanticsObject would get generated for a new entity that is no longer a switch. Are we recycling SemanticsObjects?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While unlikely, the framework supports switching the role of a SemanticsObject, that's why we have the code below for text fields.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think it's pretty weird to accommodate for something that shouldn't happen, but done.

@gaaclarke
Copy link
Member Author

Can you update the PR description with what's actually announced for a switch now?

Done

@gaaclarke
Copy link
Member Author

@chinmaygarde Can you give this another glance? I had to make a few changes for @goderbauer and he would like someone with objc chops to review it.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG, but please get somebody an ObjC expert to take a look as well.

if (DidFlagChange(object.node, node, flutter::SemanticsFlags::kIsTextField) ||
DidFlagChange(object.node, node, flutter::SemanticsFlags::kIsReadOnly) ||
DidFlagChange(object.node, node, flutter::SemanticsFlags::kHasCheckedState) ||
DidFlagChange(object.node, node, flutter::SemanticsFlags::kHasToggledState)) {
// The node changed its type from text field to something else, or vice versa. In this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update this comment? It's not just text fields.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM stamp from a Japanese personal seal

@gaaclarke
Copy link
Member Author

landing on red (appears to be a fuchsia flake)

@gaaclarke gaaclarke merged commit 036c370 into flutter:master Feb 5, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 5, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 5, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 6, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 6, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 6, 2020
jason-simmons pushed a commit to flutter/flutter that referenced this pull request Feb 6, 2020
* 9347c93 Roll src/third_party/dart c8ed304e979a..3414b5167554 (52 commits) (flutter/engine#16362)

* 16cd6f0 Roll fuchsia/sdk/core/mac-amd64 from 6h3IH... to Ke00Y... (flutter/engine#16360)

* 8c6cc65 Fix runtime type errors when running with canvaskit (flutter/engine#16312)

* 677b563 Refactor of Vulkan GPUSurface code (flutter/engine#16224)

* 7ca44d3 Kill the test harness if any test exceeds a timeout. (flutter/engine#16349)

* 7f6149c Revert "Remove use of the deprecated AccessibilityNodeInfo boundsInPa… (flutter/engine#16355)

* 488f489 Roll fuchsia/sdk/core/linux-amd64 from Tszo5... to VJv0H... (flutter/engine#16363)

* 7c9b11a Roll src/third_party/skia 71ce449d2814..2aee7d24da8f (5 commits) (flutter/engine#16364)

* 7e1d144 Expose enable-service-port-fallback switch (flutter/engine#16366)

* 4cda916 Expose the dart kernel snapshot target and copied assets as a public dependency (flutter/engine#16266)

* 73c5130 Roll src/third_party/dart 3414b5167554..68e904e444dc (17 commits) (flutter/engine#16367)

* 1cd8f3b Fix and consolidate wstring conversion utils (flutter/engine#16342)

* b98a39e Add docs (flutter/engine#16368)

* e3e6de2 Roll buildroot to c44791c89d2b51bfce864ab2cf5228d41ece1fcc (flutter/engine#16371)

* e24ec59 Fuchsia a11y actions (flutter/engine#16321)

* d8400c9 Roll src/third_party/skia 2aee7d24da8f..14d64afaa8a3 (10 commits) (flutter/engine#16374)

* eeabd4d Roll src/third_party/dart 68e904e444dc..48808f7dce81 (17 commits) (flutter/engine#16377)

* 22b994c Roll fuchsia/sdk/core/mac-amd64 from Ke00Y... to ubThi... (flutter/engine#16378)

* 0471f44 Roll src/third_party/skia 14d64afaa8a3..6c9b1fd6663e (7 commits) (flutter/engine#16380)

* 852d824 Roll src/third_party/dart 48808f7dce81..34893faa6079 (7 commits) (flutter/engine#16381)

* 4aa2083 Roll src/third_party/skia 6c9b1fd6663e..bc3307c395e2 (1 commits) (flutter/engine#16383)

* 036c370 Copied Apple's semantics for switches, made checkboxes the same. (flutter/engine#16211)

* c107969 fix build_id logic for fuchsia symbols (flutter/engine#16397)

* 11b7704 [fuchsia] Migrate flutter runner to use Present2 (flutter/engine#14162)

* 646ec35 Update license output (flutter/engine#16379)

* 925c60b Fix Windows embedding issues caught by clang (flutter/engine#16369)

* 31bf3e1 Roll src/third_party/dart 34893faa6079..b3396cbdcae1 (36 commits) (flutter/engine#16422)

* 8f89bac [web] Fixes incorrect transform when context save and transforms are deferred. (flutter/engine#16412)

* f34bc65 use percent for golden diff rates; tighten the values (flutter/engine#16430)
NoamDev added a commit to NoamDev/engine that referenced this pull request Feb 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants