@@ -75,6 +75,16 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
75
75
private static final float SCROLL_POSITION_CAP_FOR_INFINITY = 70000.0f ;
76
76
private static final int ROOT_NODE_ID = 0 ;
77
77
78
+ // The minimal ID for an engine generated AccessibilityNodeInfo.
79
+ //
80
+ // The AccessibilityNodeInfo node IDs are generated by the framework for most Flutter semantic nodes.
81
+ // When embedding platform views, the framework does not have the accessibility information for the embedded view;
82
+ // in this case the engine generates AccessibilityNodeInfo that mirrors the a11y information exposed by the platform
83
+ // view. To avoid the need of synchronizing the framework and engine mechanisms for generating the next ID, we split
84
+ // the 32bit range of virtual node IDs into 2. The least significant 16 bits are used for framework generated IDs
85
+ // and the most significant 16 bits are used for engine generated IDs.
86
+ private static final int MIN_ENGINE_GENERATED_NODE_ID = 1 <<16 ;
87
+
78
88
/// Value is derived from ACTION_TYPE_MASK in AccessibilityNodeInfo.java
79
89
private static int FIRST_RESOURCE_ID = 267386881 ;
80
90
@@ -92,6 +102,9 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
92
102
@ NonNull
93
103
private final AccessibilityManager accessibilityManager ;
94
104
105
+ @ NonNull
106
+ private final AccessibilityViewEmbedder accessibilityViewEmbedder ;
107
+
95
108
// The delegate for interacting with embedded platform views. Used to embed accessibility data for an embedded
96
109
// view in the accessibility tree.
97
110
@ NonNull
@@ -363,6 +376,7 @@ public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) {
363
376
if (platformViewsAccessibilityDelegate != null ) {
364
377
platformViewsAccessibilityDelegate .attachAccessibilityBridge (this );
365
378
}
379
+ accessibilityViewEmbedder = new AccessibilityViewEmbedder (rootAccessibilityView , MIN_ENGINE_GENERATED_NODE_ID );
366
380
}
367
381
368
382
/**
@@ -456,6 +470,11 @@ private boolean shouldSetCollectionInfo(final SemanticsNode semanticsNode) {
456
470
@ Override
457
471
@ SuppressWarnings ("deprecation" )
458
472
public AccessibilityNodeInfo createAccessibilityNodeInfo (int virtualViewId ) {
473
+ if (virtualViewId >= MIN_ENGINE_GENERATED_NODE_ID ) {
474
+ // The node is in the engine generated range, and is provided by the accessibility view embedder.
475
+ return accessibilityViewEmbedder .createAccessibilityNodeInfo (virtualViewId );
476
+ }
477
+
459
478
if (virtualViewId == View .NO_ID ) {
460
479
AccessibilityNodeInfo result = AccessibilityNodeInfo .obtain (rootAccessibilityView );
461
480
rootAccessibilityView .onInitializeAccessibilityNodeInfo (result );
@@ -472,6 +491,13 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
472
491
return null ;
473
492
}
474
493
494
+ if (semanticsNode .platformViewId != -1 ) {
495
+ // For platform views we delegate the node creation to the accessibility view embedder.
496
+ View embeddedView = platformViewsAccessibilityDelegate .getPlatformViewById (semanticsNode .platformViewId );
497
+ Rect bounds = semanticsNode .getGlobalRect ();
498
+ return accessibilityViewEmbedder .getRootNode (embeddedView , semanticsNode .id , bounds );
499
+ }
500
+
475
501
AccessibilityNodeInfo result = AccessibilityNodeInfo .obtain (rootAccessibilityView , virtualViewId );
476
502
// Work around for https://github.com/flutter/flutter/issues/2101
477
503
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .JELLY_BEAN_MR2 ) {
0 commit comments