未验证 提交 37947f96 编写于 作者: A Amir Hardon 提交者: GitHub

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

The AccessibilityViewEmbedder was not delegating a11y events coming virtual nodes(of the embedded view) that were not previously traversed by the a11y framework.

It turns out the a11y framework might leave parts of the tree untraversed in some circumstances, changed the behavior to create an originId<-->flutterId mapping on the fly when an event is delegated from a not previously traversed node.

Fixes flutter/flutter#30010.
上级 deeb7a74
......@@ -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;
......@@ -64,8 +63,8 @@ class AccessibilityViewEmbedder {
flutterIdToOrigin = new SparseArray<>();
this.rootAccessibilityView = rootAccessibiiltyView;
nextFlutterId = firstVirtualNodeId;
flutterIdToDisplayBounds = new SparseArray<>();
originToFlutterId = new HashMap<>();
embeddedViewToDisplayBounds = new HashMap<>();
}
/**
......@@ -80,10 +79,9 @@ class AccessibilityViewEmbedder {
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);
}
......@@ -96,6 +94,13 @@ class AccessibilityViewEmbedder {
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.
......@@ -127,7 +132,7 @@ class AccessibilityViewEmbedder {
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);
......@@ -172,14 +177,21 @@ class AccessibilityViewEmbedder {
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,
......@@ -265,7 +277,8 @@ class AccessibilityViewEmbedder {
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());
......@@ -333,7 +346,7 @@ class AccessibilityViewEmbedder {
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];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册