Skip to content

Commit c6015df

Browse files
Charles ChenAndroid (Google) Code Review
authored andcommitted
Merge "Add actions to non-JavaScript accessibility handler." into jb-dev
2 parents 9a9a041 + 6a62b77 commit c6015df

File tree

2 files changed

+99
-24
lines changed

2 files changed

+99
-24
lines changed

core/java/android/webkit/AccessibilityInjector.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class AccessibilityInjector {
6363

6464
// Lazily loaded helper objects.
6565
private AccessibilityManager mAccessibilityManager;
66-
private AccessibilityInjectorFallback mAccessibilityInjector;
66+
private AccessibilityInjectorFallback mAccessibilityInjectorFallback;
6767
private JSONObject mAccessibilityJSONObject;
6868

6969
// Whether the accessibility script has been injected into the current page.
@@ -200,10 +200,9 @@ public boolean performAccessibilityAction(int action, Bundle arguments) {
200200
if (mAccessibilityScriptInjected) {
201201
return sendActionToAndroidVox(action, arguments);
202202
}
203-
204-
if (mAccessibilityInjector != null) {
205-
// TODO: Implement actions for non-JS handler.
206-
return false;
203+
204+
if (mAccessibilityInjectorFallback != null) {
205+
return mAccessibilityInjectorFallback.performAccessibilityAction(action, arguments);
207206
}
208207

209208
return false;
@@ -238,11 +237,11 @@ public boolean handleKeyEventIfNecessary(KeyEvent event) {
238237
return true;
239238
}
240239

241-
if (mAccessibilityInjector != null) {
240+
if (mAccessibilityInjectorFallback != null) {
242241
// if an accessibility injector is present (no JavaScript enabled or
243242
// the site opts out injecting our JavaScript screen reader) we let
244243
// it decide whether to act on and consume the event.
245-
return mAccessibilityInjector.onKeyEvent(event);
244+
return mAccessibilityInjectorFallback.onKeyEvent(event);
246245
}
247246

248247
return false;
@@ -255,8 +254,8 @@ public boolean handleKeyEventIfNecessary(KeyEvent event) {
255254
* @param selectionString The selection string.
256255
*/
257256
public void handleSelectionChangedIfNecessary(String selectionString) {
258-
if (mAccessibilityInjector != null) {
259-
mAccessibilityInjector.onSelectionStringChange(selectionString);
257+
if (mAccessibilityInjectorFallback != null) {
258+
mAccessibilityInjectorFallback.onSelectionStringChange(selectionString);
260259
}
261260
}
262261

@@ -304,10 +303,10 @@ public void onPageFinished(String url) {
304303
* {@code false} to disable it.
305304
*/
306305
private void toggleFallbackAccessibilityInjector(boolean enabled) {
307-
if (enabled && (mAccessibilityInjector == null)) {
308-
mAccessibilityInjector = new AccessibilityInjectorFallback(mWebViewClassic);
306+
if (enabled && (mAccessibilityInjectorFallback == null)) {
307+
mAccessibilityInjectorFallback = new AccessibilityInjectorFallback(mWebViewClassic);
309308
} else {
310-
mAccessibilityInjector = null;
309+
mAccessibilityInjectorFallback = null;
311310
}
312311
}
313312

core/java/android/webkit/AccessibilityInjectorFallback.java

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616

1717
package android.webkit;
1818

19+
import android.os.Bundle;
1920
import android.provider.Settings;
2021
import android.text.TextUtils;
2122
import android.text.TextUtils.SimpleStringSplitter;
2223
import android.util.Log;
2324
import android.view.KeyEvent;
2425
import android.view.accessibility.AccessibilityEvent;
2526
import android.view.accessibility.AccessibilityManager;
27+
import android.view.accessibility.AccessibilityNodeInfo;
2628
import android.webkit.WebViewCore.EventHub;
2729

2830
import java.util.ArrayList;
@@ -48,7 +50,7 @@
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

Comments
 (0)