Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Make places and roads accessible to VoiceOver #9950

Merged
merged 24 commits into from
Nov 3, 2017

Conversation

1ec5
Copy link
Contributor

@1ec5 1ec5 commented Sep 11, 2017

After zooming in or out using VoiceOver’s one-finger upward or downward swipe gestures, MGLMapView now summarize the visible places and roads in addition to announcing the new zoom level. The places and roads are all part of the list of accessibility elements within the map view’s container, so the user can now navigate among these features to get a better sense of the map’s contents.

streets
“Café du Monde: cafe”

traffic night
“Orleans Ave: divided road, northwest to southeast”

outdoors
“Denali: mountain, 20,313 feet”

These features work in any style that uses the Mapbox Streets source in at least one layer, and it’s mostly localizable (although some parts of the readout are dependent on open-ended OpenStreetMap tags, which are in English). For screen recordings of these features, see this blog post.

Along the way, the annotation accessibility element code has been refactored for better reliability, and the annotations are now sorted by proper geographic distance.

There remain a few problems with this feature, primarily that some of the roads seem to go in and out of the container chain:

[Accessibility] Went all the way up the container chain from @, but could not find any container that was one of the ordered children of @.  This may be acceptable if it happened right around a layout change, but it would be best to double check by swiping left/right to see if you can get to all elements.

More to come:

  • Add convenience methods for querying places and roads in Mapbox Streets–sourced styles
  • Summarize places after zooming
  • Count roads after zooming
  • Refactor accessibility code to work with ranges instead of arithmetic on indices
  • Sort annotation accessibility elements by geographic distance
  • Make places navigable in VoiceOver
  • Make roads navigable in VoiceOver
  • Make compass directions less granular (MGLCompassDirectionFormatter should have granularity option #6872, can be tail work)
  • Fix accessibility warnings
  • Remove custom direction-to implementation in favor of [ios][android] SDK Bindings for Image Sources #9110
  • Include route network in readout for roads with refs (can be tail work)
  • Localize common POI type descriptions (can be tail work)
  • Implement custom rotor for zoom levels on iOS 10 and above (can be tail work)
  • Profile for performance bottlenecks
  • Unit test accessibility values

Fixes #4821.

/cc @fabian-guerra @friedbunny

@1ec5 1ec5 added accessibility Integration with screen readers and other assistive technology iOS Mapbox Maps SDK for iOS MapKit parity For feature parity with MapKit on iOS or macOS labels Sep 11, 2017
@1ec5 1ec5 self-assigned this Sep 11, 2017
@1ec5 1ec5 added this to the ios-v3.7.0 milestone Sep 18, 2017
@1ec5 1ec5 changed the base branch from release-ios-v3.6.0-android-v5.1.0 to master September 28, 2017 20:00
@boundsj boundsj self-requested a review October 2, 2017 16:10
@1ec5 1ec5 changed the base branch from master to release-agua October 6, 2017 04:20
@friedbunny
Copy link
Contributor

friedbunny commented Oct 11, 2017

I’m not very familiar with VoiceOver, but in terms of usability:

  • The settings button kept stealing focus when I tried to swipe zoom. Then I would have trouble tapping on any other element — map or UI. Swiping left would sometimes work. Other times, swiping through UI elements would never take me to the map view.
  • Performance seems pretty bad (at least, in a debug build) — when using the 100 views option and attempting to swipe between them, it can take several seconds to update to the next one.

typedef struct {
MGLLocationRadians latitude;
MGLLocationRadians longitude;
} MGLRadianCoordinate2D;
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I completely forgot we had implemented this in #9110. Yes, I’ll add this to the to-do list.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually it was #8713 😜

MGLLocationRadians longitude;
} MGLRadianCoordinate2D;

MGLRadianCoordinate2D MGLRadianCoordinate2DMake(MGLLocationRadians latitude, MGLLocationRadians longitude) {
Copy link
Contributor

Choose a reason for hiding this comment

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

}

/** Returns the direction from one coordinate to another. */
CLLocationDirection MGLDirectionBetweenCoordinates(CLLocationCoordinate2D firstCoordinate, CLLocationCoordinate2D secondCoordinate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@1ec5
Copy link
Contributor Author

1ec5 commented Oct 12, 2017

The settings button kept stealing focus when I tried to swipe zoom. Then I would have trouble tapping on any other element — map or UI. Swiping left would sometimes work. Other times, swiping through UI elements would never take me to the map view.

Tapping an element isn’t the normal mode of operation for VoiceOver. When the focus goes back to the first element on screen (which just happens to be the Settings button in iosapp), swipe rightward repeatedly to navigate through the accessibility elements. For best results, enable user location tracking.

Performance seems pretty bad (at least, in a debug build) — when using the 100 views option and attempting to swipe between them, it can take several seconds to update to the next one.

I wonder how this compares to master with VoiceOver enabled. Unfortunately, it is expected that performance with VoiceOver enabled is poorer than with VoiceOver disabled when there are many accessibility elements. In particular, the only difference between no annotations and 100 view-backed annotations should be the cost of querying the map for visible annotations; the map view leaves the annotation views in charge of providing accessibility information about themselves.

@1ec5
Copy link
Contributor Author

1ec5 commented Oct 14, 2017

One thing I need to look into is that, after zooming in or out, the listed places and roads sometimes reflect the previous zoom level. I think this may be a race condition where feature querying kicks off before the map finishes loading at the new zoom level.

@1ec5
Copy link
Contributor Author

1ec5 commented Oct 16, 2017

One thing I need to look into is that, after zooming in or out, the listed places and roads sometimes reflect the previous zoom level. I think this may be a race condition where feature querying kicks off before the map finishes loading at the new zoom level.

Fixed in 8e135a8.

@1ec5 1ec5 added the beta blocker Blocks the next beta release label Oct 26, 2017
Copy link
Contributor

@fabian-guerra fabian-guerra left a comment

Choose a reason for hiding this comment

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

LGTM 👍🏼

After zooming, MGLMapView’s accessibility value now indicates the number of visible roads and lists out a few places visible in the current viewport, starting with the features at the highest z-index (not necessarily the largest or the closest to the center of the view). Avoid saying that no annotations are visible.
Split out a separate header for the various accessibility elements tied to MGLMapView. Wrap place features in accessibility elements and insert them into the narration order after the visible annotations but before the attribution button. Refactored MGLMapView’s accessibility code to rely on ranges to avoid off-by-one errors.
Post a layout change notification when fully finishing a map render.
Sort annotation accessibility elements by screen distance, not the hypotenuse of coordinates, which can yield incorrect results when the map is rotated or tilted or when the user is located at high latitudes. Sort place feature accessibility elements by screen distance as well.
Improved accessibility performance after changing the map camera. MGLMapView no longer queries the map for place features once per place feature.
Wrap visible road features in accessibility elements described by the road name, route number, and general direction of travel.
Also fixed an issue causing road feature accessibility elements to get treated like place feature accessibility elements.
Announce the direction of a divided road based on the direction of its first polyline.
A 100-millisecond delay is enough for the post-zooming announcement to reflect the new zoom level rather than the previous zoom level.
Adopted MGLGeometry_Private.h in the accessibility code, forcing a conversion to Objective-C++. Avoid inlining some of the more complex geometric functions.
NSLocale.scriptCode is only set when the locale identifier explicitly specifies a script. Use NSOrthography to identify the dominant orthography regardless of locale.

Also added a unit test of feature accessibility element labels.
A road feature’s accessibility value now indicates whether the road is a one-way road.
@1ec5
Copy link
Contributor Author

1ec5 commented Nov 3, 2017

b585ccf and 096d486 add unit tests of the features’ accessibility labels and values.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accessibility Integration with screen readers and other assistive technology beta blocker Blocks the next beta release iOS Mapbox Maps SDK for iOS MapKit parity For feature parity with MapKit on iOS or macOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants