1616
1717package android .webkit ;
1818
19+ import android .os .Bundle ;
1920import android .provider .Settings ;
2021import android .text .TextUtils ;
2122import android .text .TextUtils .SimpleStringSplitter ;
2223import android .util .Log ;
2324import android .view .KeyEvent ;
2425import android .view .accessibility .AccessibilityEvent ;
2526import android .view .accessibility .AccessibilityManager ;
27+ import android .view .accessibility .AccessibilityNodeInfo ;
2628import android .webkit .WebViewCore .EventHub ;
2729
2830import java .util .ArrayList ;
4850 * {@link #setCurrentAxis(int, boolean, String)}, or
4951 * {@link #traverseCurrentAxis(int, boolean, String)}
5052 * {@link #traverseGivenAxis(int, int, boolean, String)}
51- * {@link #prefromAxisTransition (int, int, boolean, String)}
53+ * {@link #performAxisTransition (int, int, boolean, String)}
5254 * referred via the values of:
5355 * {@link #ACTION_SET_CURRENT_AXIS},
5456 * {@link #ACTION_TRAVERSE_CURRENT_AXIS},
@@ -72,15 +74,30 @@ class AccessibilityInjectorFallback {
7274 private static final int ACTION_PERFORM_AXIS_TRANSITION = 3 ;
7375 private static final int ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS = 4 ;
7476
75- // the default WebView behavior abstracted as a navigation axis
77+ // WebView navigation axes from WebViewCore.h, plus an additional axis for
78+ // the default behavior.
79+ private static final int NAVIGATION_AXIS_CHARACTER = 0 ;
80+ private static final int NAVIGATION_AXIS_WORD = 1 ;
81+ private static final int NAVIGATION_AXIS_SENTENCE = 2 ;
82+ @ SuppressWarnings ("unused" )
83+ private static final int NAVIGATION_AXIS_HEADING = 3 ;
84+ private static final int NAVIGATION_AXIS_SIBLING = 5 ;
85+ @ SuppressWarnings ("unused" )
86+ private static final int NAVIGATION_AXIS_PARENT_FIRST_CHILD = 5 ;
87+ private static final int NAVIGATION_AXIS_DOCUMENT = 6 ;
7688 private static final int NAVIGATION_AXIS_DEFAULT_WEB_VIEW_BEHAVIOR = 7 ;
7789
90+ // WebView navigation directions from WebViewCore.h.
91+ private static final int NAVIGATION_DIRECTION_BACKWARD = 0 ;
92+ private static final int NAVIGATION_DIRECTION_FORWARD = 1 ;
93+
7894 // these are the same for all instances so make them process wide
7995 private static ArrayList <AccessibilityWebContentKeyBinding > sBindings =
8096 new ArrayList <AccessibilityWebContentKeyBinding >();
8197
8298 // handle to the WebViewClassic this injector is associated with.
8399 private final WebViewClassic mWebView ;
100+ private final WebView mWebViewInternal ;
84101
85102 // events scheduled for sending as soon as we receive the selected text
86103 private final Stack <AccessibilityEvent > mScheduledEventStack = new Stack <AccessibilityEvent >();
@@ -104,6 +121,7 @@ class AccessibilityInjectorFallback {
104121 */
105122 public AccessibilityInjectorFallback (WebViewClassic webView ) {
106123 mWebView = webView ;
124+ mWebViewInternal = mWebView .getWebView ();
107125 ensureWebContentKeyBindings ();
108126 }
109127
@@ -176,7 +194,7 @@ public boolean onKeyEvent(KeyEvent event) {
176194 int fromAxis = binding .getFirstArgument (i );
177195 int toAxis = binding .getSecondArgument (i );
178196 sendEvent = (binding .getThirdArgument (i ) == 1 );
179- prefromAxisTransition (fromAxis , toAxis , sendEvent , contentDescription );
197+ performAxisTransition (fromAxis , toAxis , sendEvent , contentDescription );
180198 mLastDownEventHandled = true ;
181199 break ;
182200 case ACTION_TRAVERSE_DEFAULT_WEB_VIEW_BEHAVIOR_AXIS :
@@ -214,7 +232,8 @@ public boolean onKeyEvent(KeyEvent event) {
214232 private void setCurrentAxis (int axis , boolean sendEvent , String contentDescription ) {
215233 mCurrentAxis = axis ;
216234 if (sendEvent ) {
217- AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent ();
235+ final AccessibilityEvent event = getPartialyPopulatedAccessibilityEvent (
236+ AccessibilityEvent .TYPE_ANNOUNCEMENT );
218237 event .getText ().add (String .valueOf (axis ));
219238 event .setContentDescription (contentDescription );
220239 sendAccessibilityEvent (event );
@@ -229,7 +248,7 @@ private void setCurrentAxis(int axis, boolean sendEvent, String contentDescripti
229248 * @param sendEvent Flag if to send an event to announce successful transition.
230249 * @param contentDescription A description of the performed action.
231250 */
232- private void prefromAxisTransition (int fromAxis , int toAxis , boolean sendEvent ,
251+ private void performAxisTransition (int fromAxis , int toAxis , boolean sendEvent ,
233252 String contentDescription ) {
234253 if (mCurrentAxis == fromAxis ) {
235254 setCurrentAxis (toAxis , sendEvent , contentDescription );
@@ -249,6 +268,62 @@ private boolean traverseCurrentAxis(int direction, boolean sendEvent,
249268 String contentDescription ) {
250269 return traverseGivenAxis (direction , mCurrentAxis , sendEvent , contentDescription );
251270 }
271+
272+ boolean performAccessibilityAction (int action , Bundle arguments ) {
273+ switch (action ) {
274+ case AccessibilityNodeInfo .ACTION_NEXT_AT_MOVEMENT_GRANULARITY :
275+ case AccessibilityNodeInfo .ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY :
276+ final int direction = getDirectionForAction (action );
277+ final int axis = getAxisForGranularity (arguments .getInt (
278+ AccessibilityNodeInfo .ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT ));
279+ return traverseGivenAxis (direction , axis , true , null );
280+ default :
281+ return false ;
282+ }
283+ }
284+
285+ /**
286+ * Returns the {@link WebView}-defined direction for the given
287+ * {@link AccessibilityNodeInfo}-defined action.
288+ *
289+ * @param action An accessibility action identifier.
290+ * @return A web view navigation direction.
291+ */
292+ private static int getDirectionForAction (int action ) {
293+ switch (action ) {
294+ case AccessibilityNodeInfo .ACTION_NEXT_AT_MOVEMENT_GRANULARITY :
295+ return NAVIGATION_DIRECTION_FORWARD ;
296+ case AccessibilityNodeInfo .ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY :
297+ return NAVIGATION_DIRECTION_BACKWARD ;
298+ default :
299+ return -1 ;
300+ }
301+ }
302+
303+ /**
304+ * Returns the {@link WebView}-defined axis for the given
305+ * {@link AccessibilityNodeInfo}-defined granularity.
306+ *
307+ * @param granularity An accessibility granularity identifier.
308+ * @return A web view navigation axis.
309+ */
310+ private static int getAxisForGranularity (int granularity ) {
311+ switch (granularity ) {
312+ case AccessibilityNodeInfo .MOVEMENT_GRANULARITY_CHARACTER :
313+ return NAVIGATION_AXIS_CHARACTER ;
314+ case AccessibilityNodeInfo .MOVEMENT_GRANULARITY_WORD :
315+ return NAVIGATION_AXIS_WORD ;
316+ case AccessibilityNodeInfo .MOVEMENT_GRANULARITY_LINE :
317+ return NAVIGATION_AXIS_SENTENCE ;
318+ case AccessibilityNodeInfo .MOVEMENT_GRANULARITY_PARAGRAPH :
319+ // TODO: Figure out what nextSibling() actually means.
320+ return NAVIGATION_AXIS_SIBLING ;
321+ case AccessibilityNodeInfo .MOVEMENT_GRANULARITY_PAGE :
322+ return NAVIGATION_AXIS_DOCUMENT ;
323+ default :
324+ return -1 ;
325+ }
326+ }
252327
253328 /**
254329 * Traverse the document along the given navigation axis.
@@ -268,7 +343,8 @@ private boolean traverseGivenAxis(int direction, int axis, boolean sendEvent,
268343
269344 AccessibilityEvent event = null ;
270345 if (sendEvent ) {
271- event = getPartialyPopulatedAccessibilityEvent ();
346+ event = getPartialyPopulatedAccessibilityEvent (
347+ AccessibilityEvent .TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY );
272348 // the text will be set upon receiving the selection string
273349 event .setContentDescription (contentDescription );
274350 }
@@ -296,8 +372,10 @@ public void onSelectionStringChange(String selectionString) {
296372 return ;
297373 }
298374 AccessibilityEvent event = mScheduledEventStack .pop ();
299- if (event != null ) {
375+ if (( event != null ) && ( selectionString != null ) ) {
300376 event .getText ().add (selectionString );
377+ event .setFromIndex (0 );
378+ event .setToIndex (selectionString .length ());
301379 sendAccessibilityEvent (event );
302380 }
303381 }
@@ -323,11 +401,9 @@ private void sendAccessibilityEvent(AccessibilityEvent event) {
323401 * @return An accessibility event whose members are populated except its
324402 * text and content description.
325403 */
326- private AccessibilityEvent getPartialyPopulatedAccessibilityEvent () {
327- AccessibilityEvent event = AccessibilityEvent .obtain (AccessibilityEvent .TYPE_VIEW_SELECTED );
328- event .setClassName (mWebView .getClass ().getName ());
329- event .setPackageName (mWebView .getContext ().getPackageName ());
330- event .setEnabled (mWebView .getWebView ().isEnabled ());
404+ private AccessibilityEvent getPartialyPopulatedAccessibilityEvent (int eventType ) {
405+ AccessibilityEvent event = AccessibilityEvent .obtain (eventType );
406+ mWebViewInternal .onInitializeAccessibilityEvent (event );
331407 return event ;
332408 }
333409
0 commit comments