Flutter Engine
The Flutter Engine
Classes | Public Member Functions | Package Functions | List of all members
io.flutter.view.AccessibilityViewEmbedder Class Reference

Public Member Functions

AccessibilityNodeInfo getRootNode ( @NonNull View embeddedView, int flutterId, @NonNull Rect displayBounds)
 
AccessibilityNodeInfo createAccessibilityNodeInfo (int flutterId)
 
boolean requestSendAccessibilityEvent ( @NonNull View embeddedView, @NonNull View eventOrigin, @NonNull AccessibilityEvent event)
 
boolean performAction (int flutterId, int accessibilityAction, @Nullable Bundle arguments)
 
Integer getRecordFlutterId ( @NonNull View embeddedView, @NonNull AccessibilityRecord record)
 
boolean onAccessibilityHoverEvent (int rootFlutterId, @NonNull MotionEvent event)
 
View platformViewOfNode (int flutterId)
 

Package Functions

 AccessibilityViewEmbedder (@NonNull View rootAccessibiiltyView, int firstVirtualNodeId)
 

Detailed Description

Facilitates embedding of platform views in the accessibility tree generated by the accessibility bridge.

Embedding is done by mirroring the accessibility tree of the platform view as a subtree of the flutter accessibility tree.

This class relies on hidden system APIs to extract the accessibility information and does not work starting Android P; If the reflection accessors are not available we fail silently by embedding a null node, the app continues working but the accessibility information for the platform view will not be embedded.

We use the term flutterId for virtual accessibility node IDs in the FlutterView tree, and the term originId for the virtual accessibility node IDs in the platform view's tree. Internally this class maintains a bidirectional mapping between flutterIds and the corresponding platform view and originId.

Definition at line 49 of file AccessibilityViewEmbedder.java.

Constructor & Destructor Documentation

◆ AccessibilityViewEmbedder()

io.flutter.view.AccessibilityViewEmbedder.AccessibilityViewEmbedder ( @NonNull View  rootAccessibiiltyView,
int  firstVirtualNodeId 
)
inlinepackage

Definition at line 71 of file AccessibilityViewEmbedder.java.

71 {
72 reflectionAccessors = new ReflectionAccessors();
73 flutterIdToOrigin = new SparseArray<>();
74 this.rootAccessibilityView = rootAccessibiiltyView;
75 nextFlutterId = firstVirtualNodeId;
76 originToFlutterId = new HashMap<>();
77 embeddedViewToDisplayBounds = new HashMap<>();
78 }

Member Function Documentation

◆ createAccessibilityNodeInfo()

AccessibilityNodeInfo io.flutter.view.AccessibilityViewEmbedder.createAccessibilityNodeInfo ( int  flutterId)
inline

Creates the accessibility node info for the node identified with flutterId.

Definition at line 101 of file AccessibilityViewEmbedder.java.

101 {
102 ViewAndId origin = flutterIdToOrigin.get(flutterId);
103 if (origin == null) {
104 return null;
105 }
106 if (!embeddedViewToDisplayBounds.containsKey(origin.view)) {
107 // This might happen if the embedded view is sending accessibility event before the first
108 // Flutter semantics
109 // tree was sent to the accessibility bridge. In this case we don't return a node as we do not
110 // know the
111 // bounds yet.
112 // https://github.com/flutter/flutter/issues/30068
113 return null;
114 }
115 AccessibilityNodeProvider provider = origin.view.getAccessibilityNodeProvider();
116 if (provider == null) {
117 // The provider is null for views that don't have a virtual accessibility tree.
118 // We currently only support embedding virtual hierarchies in the Flutter tree.
119 // TODO(amirh): support embedding non virtual hierarchies.
120 // https://github.com/flutter/flutter/issues/29717
121 return null;
122 }
123 AccessibilityNodeInfo originNode =
124 origin.view.getAccessibilityNodeProvider().createAccessibilityNodeInfo(origin.id);
125 if (originNode == null) {
126 return null;
127 }
128 return convertToFlutterNode(originNode, flutterId, origin.view);
129 }

◆ getRecordFlutterId()

Integer io.flutter.view.AccessibilityViewEmbedder.getRecordFlutterId ( @NonNull View  embeddedView,
@NonNull AccessibilityRecord  record 
)
inline

Returns a flutterID for an accessibility record, or null if no mapping exists.

Parameters
embeddedViewthe embedded view that the record is associated with.

Definition at line 331 of file AccessibilityViewEmbedder.java.

332 {
333 Long originPackedId = reflectionAccessors.getRecordSourceNodeId(record);
334 if (originPackedId == null) {
335 return null;
336 }
337 int originVirtualId = ReflectionAccessors.getVirtualNodeId(originPackedId);
338 return originToFlutterId.get(new ViewAndId(embeddedView, originVirtualId));
339 }

◆ getRootNode()

AccessibilityNodeInfo io.flutter.view.AccessibilityViewEmbedder.getRootNode ( @NonNull View  embeddedView,
int  flutterId,
@NonNull Rect  displayBounds 
)
inline

Returns the root accessibility node for an embedded platform view.

Parameters
flutterIdthe virtual accessibility ID for the node in flutter accessibility tree
displayBoundsthe display bounds for the node in screen coordinates

Definition at line 86 of file AccessibilityViewEmbedder.java.

87 {
88 AccessibilityNodeInfo originNode = embeddedView.createAccessibilityNodeInfo();
89 Long originPackedId = reflectionAccessors.getSourceNodeId(originNode);
90 if (originPackedId == null) {
91 return null;
92 }
93 embeddedViewToDisplayBounds.put(embeddedView, displayBounds);
94 int originId = ReflectionAccessors.getVirtualNodeId(originPackedId);
95 cacheVirtualIdMappings(embeddedView, originId, flutterId);
96 return convertToFlutterNode(originNode, flutterId, embeddedView);
97 }

◆ onAccessibilityHoverEvent()

boolean io.flutter.view.AccessibilityViewEmbedder.onAccessibilityHoverEvent ( int  rootFlutterId,
@NonNull MotionEvent  event 
)
inline

Delegates a View::onHoverEvent event from the AccessibilityBridge to an embedded view.

The pointer coordinates are translated to the embedded view's coordinate system.

Definition at line 346 of file AccessibilityViewEmbedder.java.

346 {
347 ViewAndId origin = flutterIdToOrigin.get(rootFlutterId);
348 if (origin == null) {
349 return false;
350 }
351 Rect displayBounds = embeddedViewToDisplayBounds.get(origin.view);
352 int pointerCount = event.getPointerCount();
353 MotionEvent.PointerProperties[] pointerProperties =
354 new MotionEvent.PointerProperties[pointerCount];
355 MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
356 for (int i = 0; i < event.getPointerCount(); i++) {
357 pointerProperties[i] = new MotionEvent.PointerProperties();
358 event.getPointerProperties(i, pointerProperties[i]);
359
360 MotionEvent.PointerCoords originCoords = new MotionEvent.PointerCoords();
361 event.getPointerCoords(i, originCoords);
362
363 pointerCoords[i] = new MotionEvent.PointerCoords(originCoords);
364 pointerCoords[i].x -= displayBounds.left;
365 pointerCoords[i].y -= displayBounds.top;
366 }
367 MotionEvent translatedEvent =
368 MotionEvent.obtain(
369 event.getDownTime(),
370 event.getEventTime(),
371 event.getAction(),
372 event.getPointerCount(),
373 pointerProperties,
374 pointerCoords,
375 event.getMetaState(),
376 event.getButtonState(),
377 event.getXPrecision(),
378 event.getYPrecision(),
379 event.getDeviceId(),
380 event.getEdgeFlags(),
381 event.getSource(),
382 event.getFlags());
383 return origin.view.dispatchGenericMotionEvent(translatedEvent);
384 }
FlKeyEvent * event
TRect< Scalar > Rect
Definition: rect.h:769

◆ performAction()

boolean io.flutter.view.AccessibilityViewEmbedder.performAction ( int  flutterId,
int  accessibilityAction,
@Nullable Bundle  arguments 
)
inline

Delegates anlink AccessibilityNodeProvider::performAction} from the AccessibilityBridge to the embedded view's accessibility node provider.

Returns
True if the action was performed.

Definition at line 312 of file AccessibilityViewEmbedder.java.

312 {
313 ViewAndId origin = flutterIdToOrigin.get(flutterId);
314 if (origin == null) {
315 return false;
316 }
317 View embeddedView = origin.view;
318 AccessibilityNodeProvider provider = embeddedView.getAccessibilityNodeProvider();
319 if (provider == null) {
320 return false;
321 }
322 return provider.performAction(origin.id, accessibilityAction, arguments);
323 }

◆ platformViewOfNode()

View io.flutter.view.AccessibilityViewEmbedder.platformViewOfNode ( int  flutterId)
inline

Returns the View that contains the accessibility node identified by the provided flutterId or null if it doesn't belong to a view.

Definition at line 390 of file AccessibilityViewEmbedder.java.

390 {
391 ViewAndId viewAndId = flutterIdToOrigin.get(flutterId);
392 if (viewAndId == null) {
393 return null;
394 }
395 return viewAndId.view;
396 }

◆ requestSendAccessibilityEvent()

boolean io.flutter.view.AccessibilityViewEmbedder.requestSendAccessibilityEvent ( @NonNull View  embeddedView,
@NonNull View  eventOrigin,
@NonNull AccessibilityEvent  event 
)
inline

Delegates an AccessibilityNodeProvider::requestSendAccessibilityEvent from the AccessibilityBridge to the embedded view.

Returns
True if the event was sent.

Definition at line 269 of file AccessibilityViewEmbedder.java.

270 {
271 AccessibilityEvent translatedEvent = AccessibilityEvent.obtain(event);
272 Long originPackedId = reflectionAccessors.getRecordSourceNodeId(event);
273 if (originPackedId == null) {
274 return false;
275 }
276 int originVirtualId = ReflectionAccessors.getVirtualNodeId(originPackedId);
277 Integer flutterId = originToFlutterId.get(new ViewAndId(embeddedView, originVirtualId));
278 if (flutterId == null) {
279 flutterId = nextFlutterId++;
280 cacheVirtualIdMappings(embeddedView, originVirtualId, flutterId);
281 }
282 translatedEvent.setSource(rootAccessibilityView, flutterId);
283 translatedEvent.setClassName(event.getClassName());
284 translatedEvent.setPackageName(event.getPackageName());
285
286 for (int i = 0; i < translatedEvent.getRecordCount(); i++) {
287 AccessibilityRecord record = translatedEvent.getRecord(i);
288 Long recordOriginPackedId = reflectionAccessors.getRecordSourceNodeId(record);
289 if (recordOriginPackedId == null) {
290 return false;
291 }
292 int recordOriginVirtualID = ReflectionAccessors.getVirtualNodeId(recordOriginPackedId);
293 ViewAndId originViewAndId = new ViewAndId(embeddedView, recordOriginVirtualID);
294 if (!originToFlutterId.containsKey(originViewAndId)) {
295 return false;
296 }
297 int recordFlutterId = originToFlutterId.get(originViewAndId);
298 record.setSource(rootAccessibilityView, recordFlutterId);
299 }
300
301 return rootAccessibilityView
302 .getParent()
303 .requestSendAccessibilityEvent(eventOrigin, translatedEvent);
304 }

The documentation for this class was generated from the following file: