| # Chrome Accessibility on Android |
| |
| Chrome plays an important role on Android - not only is it the default |
| browser, but Chrome powers WebView, which is used by many built-in and |
| third-party apps to display all sorts of content. |
| |
| This document covers some of the technical details of how Chrome |
| implements its accessibility support on Android. |
| |
| As background reading, you should be familiar with |
| [Android Accessibility](https://developer.android.com/guide/topics/ui/accessibility) |
| and in particular |
| [AccessibilityNodeInfo](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo) |
| and |
| [AccessibilityNodeProvider](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeProvider). |
| |
| ## WebContentsAccessibility |
| |
| The main Java class that implements the accessibility protocol in Chrome is |
| [WebContentsAccessibilityImpl.java](https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java). It implements the AccessibilityNodeProvider |
| interface, so a single Android View can be represented by an entire tree |
| of virtual views. Note that WebContentsAccessibilityImpl represents an |
| entire web page, including all frames. The ids in the java code are unique IDs, |
| not frame-local IDs. |
| |
| On most platforms, we create a native object for every AXNode in a web page, |
| and we implement a bunch of methods on that object that assistive technology |
| can query. |
| |
| Android is different - it's more lightweight in one way, in that we only |
| create a native AccessibilityNodeInfo when specifically requested, when |
| an Android accessibility service is exploring the virtual tree. In another |
| sense it's more heavyweight, though, because every time a virtual view is |
| requested we have to populate it with every possible accessibility attribute, |
| and there are quite a few. |
| |
| ## Populating AccessibilityNodeInfo |
| |
| Populating AccessibilityNodeInfo is a bit complicated for reasons of |
| Android version compatibility and also code efficiency. |
| |
| WebContentsAccessibilityImpl.createAccessibilityNodeInfo is the starting |
| point. That's called by the Android framework when we need to provide the |
| info about one virtual view (a web node). |
| |
| We call into C++ code - |
| [web_contents_accessibility_android.cc](https://cs.chromium.org/chromium/src/content/browser/accessibility/web_contents_accessibility_android.cc) from |
| there, because all of the information about the accessibility tree is |
| using the shared C++ BrowserAccessibilityManager code. |
| |
| However, the C++ code then calls back into Java in order to set all of the |
| properties of AccessibilityNodeInfo, because those have to be set in Java. |
| Each of those methods, like setAccessibilityNodeInfoBooleanAttributes, is |
| often overridden by an Android-version-specific subclass to take advantage |
| of newer APIs where available. |
| |
| Having the Java code query C++ for every individual attribute one at a time |
| would be too expensive, we'd be going across the JNI boundary too many times. |
| That's why it's structured the way it is now. |
| |
| ## Touch Exploration |
| |
| The way touch exploration works on Android is complicated: |
| |
| * When the user taps or drags their finger, our View gets a hover event. |
| * Accessibility code sends a hit test action to the renderer process |
| * The renderer process fires a HOVER accessibility event on the accessibility |
| node at that coordinate |
| * WebContentsAccessibilityImpl.handleHover is called with that node. We fire |
| an Android TYPE_VIEW_HOVER_ENTER event on that node and a |
| TYPE_VIEW_HOVER_EXIT event on the previous node. |
| * Finally, TalkBack sets accessibility focus to that node. |