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

Allow delegation of a11y events from nodes that were not yet traversed #8333

Merged
merged 1 commit into from
Mar 27, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ class AccessibilityViewEmbedder {
// Maps a platform view and originId to a corresponding flutterID.
private final Map<ViewAndId, Integer> originToFlutterId;

// Maps the flutterId of an accessibility node to the screen bounds of
// the root semantic node for the embedded view.
// Maps an embedded view to it's screen bounds.
// This is used to translate the coordinates of the accessibility node subtree to the main display's coordinate
// system.
private final SparseArray<Rect> flutterIdToDisplayBounds;
private final Map<View, Rect> embeddedViewToDisplayBounds;

private int nextFlutterId;

Expand All @@ -64,8 +63,8 @@ class AccessibilityViewEmbedder {
flutterIdToOrigin = new SparseArray<>();
this.rootAccessibilityView = rootAccessibiiltyView;
nextFlutterId = firstVirtualNodeId;
flutterIdToDisplayBounds = new SparseArray<>();
originToFlutterId = new HashMap<>();
embeddedViewToDisplayBounds = new HashMap<>();
}

/**
Expand All @@ -80,10 +79,9 @@ public AccessibilityNodeInfo getRootNode(@NonNull View embeddedView, int flutter
if (originPackedId == null) {
return null;
}
embeddedViewToDisplayBounds.put(embeddedView, displayBounds);
int originId = ReflectionAccessors.getVirtualNodeId(originPackedId);
flutterIdToOrigin.put(flutterId, new ViewAndId(embeddedView, originId));
flutterIdToDisplayBounds.put(flutterId, displayBounds);
originToFlutterId.put(new ViewAndId(embeddedView, originId), flutterId);
cacheVirtualIdMappings(embeddedView, originId, flutterId);
return convertToFlutterNode(originNode, flutterId, embeddedView);
}

Expand All @@ -96,6 +94,13 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int flutterId) {
if (origin == null) {
return null;
}
if (!embeddedViewToDisplayBounds.containsKey(origin.view)) {
// This might happen if the embedded view is sending accessibility event before the first Flutter semantics
// tree was sent to the accessibility bridge. In this case we don't return a node as we do not know the
// bounds yet.
// https://github.com/flutter/flutter/issues/30068
return null;
}
AccessibilityNodeProvider provider = origin.view.getAccessibilityNodeProvider();
if (provider == null) {
// The provider is null for views that don't have a virtual accessibility tree.
Expand Down Expand Up @@ -127,7 +132,7 @@ private AccessibilityNodeInfo convertToFlutterNode(
result.setSource(rootAccessibilityView, flutterId);
result.setClassName(originNode.getClassName());

Rect displayBounds = flutterIdToDisplayBounds.get(flutterId);
Rect displayBounds = embeddedViewToDisplayBounds.get(embeddedView);

copyAccessibilityFields(originNode, result);
setFlutterNodesTranslateBounds(originNode, displayBounds, result);
Expand Down Expand Up @@ -172,14 +177,21 @@ private void addChildrenToFlutterNode(
childFlutterId = originToFlutterId.get(origin);
} else {
childFlutterId = nextFlutterId++;
originToFlutterId.put(origin, childFlutterId);
flutterIdToOrigin.put(childFlutterId, origin);
flutterIdToDisplayBounds.put(childFlutterId, displayBounds);
cacheVirtualIdMappings(embeddedView, originId, childFlutterId);
}
resultNode.addChild(rootAccessibilityView, childFlutterId);
}
}

// Caches a bidirectional mapping of (embeddedView, originId)<-->flutterId.
// Where originId is a virtual node ID in the embeddedView's tree, and flutterId is the ID
// of the corresponding node in the Flutter virtual accessibility nodes tree.
private void cacheVirtualIdMappings(@NonNull View embeddedView, int originId, int flutterId) {
ViewAndId origin = new ViewAndId(embeddedView, originId);
originToFlutterId.put(origin, flutterId);
flutterIdToOrigin.put(flutterId, origin);
}

private void setFlutterNodesTranslateBounds(
@NonNull AccessibilityNodeInfo originNode,
@NonNull Rect displayBounds,
Expand Down Expand Up @@ -265,7 +277,8 @@ public boolean requestSendAccessibilityEvent(
int originVirtualId = ReflectionAccessors.getVirtualNodeId(originPackedId);
Integer flutterId = originToFlutterId.get(new ViewAndId(embeddedView, originVirtualId));
if (flutterId == null) {
return false;
flutterId = nextFlutterId++;
cacheVirtualIdMappings(embeddedView, originVirtualId, flutterId);
}
translatedEvent.setSource(rootAccessibilityView, flutterId);
translatedEvent.setClassName(event.getClassName());
Expand Down Expand Up @@ -333,7 +346,7 @@ public boolean onAccessibilityHoverEvent(int rootFlutterId, @NonNull MotionEvent
if (origin == null) {
return false;
}
Rect displayBounds = flutterIdToDisplayBounds.get(rootFlutterId);
Rect displayBounds = embeddedViewToDisplayBounds.get(origin.view);
int pointerCount = event.getPointerCount();
MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[pointerCount];
MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
Expand Down