Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / accessibility / BrowserAccessibilityManager.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.content.browser.accessibility;
6
7 import android.content.Context;
8 import android.graphics.Rect;
9 import android.os.Build;
10 import android.os.Bundle;
11 import android.view.MotionEvent;
12 import android.view.View;
13 import android.view.ViewParent;
14 import android.view.accessibility.AccessibilityEvent;
15 import android.view.accessibility.AccessibilityManager;
16 import android.view.accessibility.AccessibilityNodeInfo;
17 import android.view.accessibility.AccessibilityNodeProvider;
18
19 import org.chromium.base.CalledByNative;
20 import org.chromium.base.JNINamespace;
21 import org.chromium.content.browser.ContentViewCore;
22 import org.chromium.content.browser.RenderCoordinates;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 /**
28  * Native accessibility for a {@link ContentViewCore}.
29  *
30  * This class is safe to load on ICS and can be used to run tests, but
31  * only the subclass, JellyBeanBrowserAccessibilityManager, actually
32  * has a AccessibilityNodeProvider implementation needed for native
33  * accessibility.
34  */
35 @JNINamespace("content")
36 public class BrowserAccessibilityManager {
37     private static final String TAG = "BrowserAccessibilityManager";
38
39     private ContentViewCore mContentViewCore;
40     private final AccessibilityManager mAccessibilityManager;
41     private final RenderCoordinates mRenderCoordinates;
42     private long mNativeObj;
43     private int mAccessibilityFocusId;
44     private int mCurrentHoverId;
45     private int mCurrentRootId;
46     private final int[] mTempLocation = new int[2];
47     private final View mView;
48     private boolean mUserHasTouchExplored;
49     private boolean mPendingScrollToMakeNodeVisible;
50     private boolean mFrameInfoInitialized;
51
52     /**
53      * Create a BrowserAccessibilityManager object, which is owned by the C++
54      * BrowserAccessibilityManagerAndroid instance, and connects to the content view.
55      * @param nativeBrowserAccessibilityManagerAndroid A pointer to the counterpart native
56      *     C++ object that owns this object.
57      * @param contentViewCore The content view that this object provides accessibility for.
58      */
59     @CalledByNative
60     private static BrowserAccessibilityManager create(long nativeBrowserAccessibilityManagerAndroid,
61             ContentViewCore contentViewCore) {
62         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
63             return new KitKatBrowserAccessibilityManager(
64                     nativeBrowserAccessibilityManagerAndroid, contentViewCore);
65         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
66             return new JellyBeanBrowserAccessibilityManager(
67                     nativeBrowserAccessibilityManagerAndroid, contentViewCore);
68         } else {
69             return new BrowserAccessibilityManager(
70                     nativeBrowserAccessibilityManagerAndroid, contentViewCore);
71         }
72     }
73
74     protected BrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
75             ContentViewCore contentViewCore) {
76         mNativeObj = nativeBrowserAccessibilityManagerAndroid;
77         mContentViewCore = contentViewCore;
78         mContentViewCore.setBrowserAccessibilityManager(this);
79         mAccessibilityFocusId = View.NO_ID;
80         mCurrentHoverId = View.NO_ID;
81         mCurrentRootId = View.NO_ID;
82         mView = mContentViewCore.getContainerView();
83         mRenderCoordinates = mContentViewCore.getRenderCoordinates();
84         mAccessibilityManager =
85             (AccessibilityManager) mContentViewCore.getContext()
86             .getSystemService(Context.ACCESSIBILITY_SERVICE);
87     }
88
89     @CalledByNative
90     private void onNativeObjectDestroyed() {
91         if (mContentViewCore.getBrowserAccessibilityManager() == this) {
92             mContentViewCore.setBrowserAccessibilityManager(null);
93         }
94         mNativeObj = 0;
95         mContentViewCore = null;
96     }
97
98     /**
99      * @return An AccessibilityNodeProvider on JellyBean, and null on previous versions.
100      */
101     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
102         return null;
103     }
104
105     /**
106      * @see AccessibilityNodeProvider#createAccessibilityNodeInfo(int)
107      */
108     protected AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
109         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
110             return null;
111         }
112
113         int rootId = nativeGetRootId(mNativeObj);
114
115         if (virtualViewId == View.NO_ID) {
116             return createNodeForHost(rootId);
117         }
118
119         if (!mFrameInfoInitialized) {
120             return null;
121         }
122
123         final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(mView);
124         info.setPackageName(mContentViewCore.getContext().getPackageName());
125         info.setSource(mView, virtualViewId);
126
127         if (virtualViewId == rootId) {
128             info.setParent(mView);
129         }
130
131         if (nativePopulateAccessibilityNodeInfo(mNativeObj, info, virtualViewId)) {
132             return info;
133         } else {
134             info.recycle();
135             return null;
136         }
137     }
138
139     /**
140      * @see AccessibilityNodeProvider#findAccessibilityNodeInfosByText(String, int)
141      */
142     protected List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
143             int virtualViewId) {
144         return new ArrayList<AccessibilityNodeInfo>();
145     }
146
147     /**
148      * @see AccessibilityNodeProvider#performAction(int, int, Bundle)
149      */
150     protected boolean performAction(int virtualViewId, int action, Bundle arguments) {
151         // We don't support any actions on the host view or nodes
152         // that are not (any longer) in the tree.
153         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
154                 || !nativeIsNodeValid(mNativeObj, virtualViewId)) {
155             return false;
156         }
157
158         switch (action) {
159             case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
160                 if (mAccessibilityFocusId == virtualViewId) {
161                     return true;
162                 }
163
164                 mAccessibilityFocusId = virtualViewId;
165                 sendAccessibilityEvent(mAccessibilityFocusId,
166                         AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
167                 if (mCurrentHoverId == View.NO_ID) {
168                     nativeScrollToMakeNodeVisible(
169                             mNativeObj, mAccessibilityFocusId);
170                 } else {
171                     mPendingScrollToMakeNodeVisible = true;
172                 }
173                 return true;
174             case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
175                 if (mAccessibilityFocusId == virtualViewId) {
176                     sendAccessibilityEvent(mAccessibilityFocusId,
177                             AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
178                     mAccessibilityFocusId = View.NO_ID;
179                 }
180                 return true;
181             case AccessibilityNodeInfo.ACTION_CLICK:
182                 nativeClick(mNativeObj, virtualViewId);
183                 sendAccessibilityEvent(virtualViewId,
184                         AccessibilityEvent.TYPE_VIEW_CLICKED);
185                 return true;
186             case AccessibilityNodeInfo.ACTION_FOCUS:
187                 nativeFocus(mNativeObj, virtualViewId);
188                 return true;
189             case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS:
190                 nativeBlur(mNativeObj);
191                 return true;
192             default:
193                 break;
194         }
195         return false;
196     }
197
198     /**
199      * @see View#onHoverEvent(MotionEvent)
200      */
201     public boolean onHoverEvent(MotionEvent event) {
202         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
203             return false;
204         }
205
206         if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
207             if (mCurrentHoverId != View.NO_ID) {
208                 sendAccessibilityEvent(mCurrentHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
209                 mCurrentHoverId = View.NO_ID;
210             }
211             if (mPendingScrollToMakeNodeVisible) {
212                 nativeScrollToMakeNodeVisible(
213                         mNativeObj, mAccessibilityFocusId);
214             }
215             mPendingScrollToMakeNodeVisible = false;
216             return true;
217         }
218
219         mUserHasTouchExplored = true;
220         float x = event.getX();
221         float y = event.getY();
222
223         // Convert to CSS coordinates.
224         int cssX = (int) (mRenderCoordinates.fromPixToLocalCss(x) +
225                           mRenderCoordinates.getScrollX());
226         int cssY = (int) (mRenderCoordinates.fromPixToLocalCss(y) +
227                           mRenderCoordinates.getScrollY());
228         int id = nativeHitTest(mNativeObj, cssX, cssY);
229         if (mCurrentHoverId != id) {
230             sendAccessibilityEvent(mCurrentHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
231             sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
232             mCurrentHoverId = id;
233         }
234
235         return true;
236     }
237
238     /**
239      * Called by ContentViewCore to notify us when the frame info is initialized,
240      * the first time, since until that point, we can't use mRenderCoordinates to transform
241      * web coordinates to screen coordinates.
242      */
243     public void notifyFrameInfoInitialized() {
244         if (mFrameInfoInitialized) return;
245
246         mFrameInfoInitialized = true;
247         // Invalidate the host, since the chrome accessibility tree is now
248         // ready and listed as the child of the host.
249         mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
250
251         // (Re-) focus focused element, since we weren't able to create an
252         // AccessibilityNodeInfo for this element before.
253         if (mAccessibilityFocusId != View.NO_ID) {
254             sendAccessibilityEvent(mAccessibilityFocusId,
255                                    AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
256         }
257     }
258
259     private void sendAccessibilityEvent(int virtualViewId, int eventType) {
260         // If mFrameInfoInitialized is false, then the virtual hierarchy
261         // doesn't exist in the view of the Android framework, so should
262         // never send any events.
263         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
264                 || !mFrameInfoInitialized) {
265             return;
266         }
267
268         final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
269         event.setPackageName(mContentViewCore.getContext().getPackageName());
270         event.setSource(mView, virtualViewId);
271         if (!nativePopulateAccessibilityEvent(mNativeObj, event, virtualViewId, eventType)) {
272             event.recycle();
273             return;
274         }
275
276         // This is currently needed if we want Android to draw the yellow box around
277         // the item that has accessibility focus. In practice, this doesn't seem to slow
278         // things down, because it's only called when the accessibility focus moves.
279         // TODO(dmazzoni): remove this if/when Android framework fixes bug.
280         mContentViewCore.getContainerView().postInvalidate();
281
282         mContentViewCore.getContainerView().requestSendAccessibilityEvent(mView, event);
283     }
284
285     private Bundle getOrCreateBundleForAccessibilityEvent(AccessibilityEvent event) {
286         Bundle bundle = (Bundle) event.getParcelableData();
287         if (bundle == null) {
288             bundle = new Bundle();
289             event.setParcelableData(bundle);
290         }
291         return bundle;
292     }
293
294     private AccessibilityNodeInfo createNodeForHost(int rootId) {
295         // Since we don't want the parent to be focusable, but we can't remove
296         // actions from a node, copy over the necessary fields.
297         final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(mView);
298         final AccessibilityNodeInfo source = AccessibilityNodeInfo.obtain(mView);
299         mView.onInitializeAccessibilityNodeInfo(source);
300
301         // Copy over parent and screen bounds.
302         Rect rect = new Rect();
303         source.getBoundsInParent(rect);
304         result.setBoundsInParent(rect);
305         source.getBoundsInScreen(rect);
306         result.setBoundsInScreen(rect);
307
308         // Set up the parent view, if applicable.
309         final ViewParent parent = mView.getParentForAccessibility();
310         if (parent instanceof View) {
311             result.setParent((View) parent);
312         }
313
314         // Populate the minimum required fields.
315         result.setVisibleToUser(source.isVisibleToUser());
316         result.setEnabled(source.isEnabled());
317         result.setPackageName(source.getPackageName());
318         result.setClassName(source.getClassName());
319
320         // Add the Chrome root node.
321         if (mFrameInfoInitialized) {
322             result.addChild(mView, rootId);
323         }
324
325         return result;
326     }
327
328     @CalledByNative
329     private void handlePageLoaded(int id) {
330         if (mUserHasTouchExplored) return;
331
332         mAccessibilityFocusId = id;
333         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
334     }
335
336     @CalledByNative
337     private void handleFocusChanged(int id) {
338         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_FOCUSED);
339
340         // Update accessibility focus if not already set to this node.
341         if (mAccessibilityFocusId != id) {
342             sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
343             mAccessibilityFocusId = id;
344         }
345     }
346
347     @CalledByNative
348     private void handleCheckStateChanged(int id) {
349         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
350     }
351
352     @CalledByNative
353     private void handleTextSelectionChanged(int id) {
354         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
355     }
356
357     @CalledByNative
358     private void handleEditableTextChanged(int id) {
359         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
360     }
361
362     @CalledByNative
363     private void handleContentChanged(int id) {
364         int rootId = nativeGetRootId(mNativeObj);
365         if (rootId != mCurrentRootId) {
366             mCurrentRootId = rootId;
367             mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
368         } else {
369             sendAccessibilityEvent(id, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
370         }
371     }
372
373     @CalledByNative
374     private void handleNavigate() {
375         mAccessibilityFocusId = View.NO_ID;
376         mUserHasTouchExplored = false;
377         mFrameInfoInitialized = false;
378         // Invalidate the host, since its child is now gone.
379         mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
380     }
381
382     @CalledByNative
383     private void handleScrolledToAnchor(int id) {
384         if (mAccessibilityFocusId == id) {
385             return;
386         }
387
388         mAccessibilityFocusId = id;
389         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
390     }
391
392     @CalledByNative
393     private void announceLiveRegionText(String text) {
394         mView.announceForAccessibility(text);
395     }
396
397     @CalledByNative
398     private void setAccessibilityNodeInfoParent(AccessibilityNodeInfo node, int parentId) {
399         node.setParent(mView, parentId);
400     }
401
402     @CalledByNative
403     private void addAccessibilityNodeInfoChild(AccessibilityNodeInfo node, int childId) {
404         node.addChild(mView, childId);
405     }
406
407     @CalledByNative
408     private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node,
409             int virtualViewId, boolean checkable, boolean checked, boolean clickable,
410             boolean enabled, boolean focusable, boolean focused, boolean password,
411             boolean scrollable, boolean selected, boolean visibleToUser) {
412         node.setCheckable(checkable);
413         node.setChecked(checked);
414         node.setClickable(clickable);
415         node.setEnabled(enabled);
416         node.setFocusable(focusable);
417         node.setFocused(focused);
418         node.setPassword(password);
419         node.setScrollable(scrollable);
420         node.setSelected(selected);
421         node.setVisibleToUser(visibleToUser);
422
423         if (focusable) {
424             if (focused) {
425                 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
426             } else {
427                 node.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
428             }
429         }
430
431         if (mAccessibilityFocusId == virtualViewId) {
432             node.setAccessibilityFocused(true);
433             node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
434         } else {
435             node.setAccessibilityFocused(false);
436             node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
437         }
438
439         if (clickable) {
440             node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
441         }
442     }
443
444     @CalledByNative
445     private void setAccessibilityNodeInfoStringAttributes(AccessibilityNodeInfo node,
446             String className, String contentDescription) {
447         node.setClassName(className);
448         node.setContentDescription(contentDescription);
449     }
450
451     @CalledByNative
452     private void setAccessibilityNodeInfoLocation(AccessibilityNodeInfo node,
453             int absoluteLeft, int absoluteTop, int parentRelativeLeft, int parentRelativeTop,
454             int width, int height, boolean isRootNode) {
455         // First set the bounds in parent.
456         Rect boundsInParent = new Rect(parentRelativeLeft, parentRelativeTop,
457                 parentRelativeLeft + width, parentRelativeTop + height);
458         if (isRootNode) {
459             // Offset of the web content relative to the View.
460             boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
461         }
462         node.setBoundsInParent(boundsInParent);
463
464         // Now set the absolute rect, which requires several transformations.
465         Rect rect = new Rect(absoluteLeft, absoluteTop, absoluteLeft + width, absoluteTop + height);
466
467         // Offset by the scroll position.
468         rect.offset(-(int) mRenderCoordinates.getScrollX(),
469                     -(int) mRenderCoordinates.getScrollY());
470
471         // Convert CSS (web) pixels to Android View pixels
472         rect.left = (int) mRenderCoordinates.fromLocalCssToPix(rect.left);
473         rect.top = (int) mRenderCoordinates.fromLocalCssToPix(rect.top);
474         rect.bottom = (int) mRenderCoordinates.fromLocalCssToPix(rect.bottom);
475         rect.right = (int) mRenderCoordinates.fromLocalCssToPix(rect.right);
476
477         // Offset by the location of the web content within the view.
478         rect.offset(0,
479                     (int) mRenderCoordinates.getContentOffsetYPix());
480
481         // Finally offset by the location of the view within the screen.
482         final int[] viewLocation = new int[2];
483         mView.getLocationOnScreen(viewLocation);
484         rect.offset(viewLocation[0], viewLocation[1]);
485
486         node.setBoundsInScreen(rect);
487     }
488
489     @CalledByNative
490     protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
491             boolean canOpenPopup,
492             boolean contentInvalid,
493             boolean dismissable,
494             boolean multiLine,
495             int inputType,
496             int liveRegion) {
497         // Requires KitKat or higher.
498     }
499
500     @CalledByNative
501     protected void setAccessibilityNodeInfoCollectionInfo(AccessibilityNodeInfo node,
502             int rowCount, int columnCount, boolean hierarchical) {
503         // Requires KitKat or higher.
504     }
505
506     @CalledByNative
507     protected void setAccessibilityNodeInfoCollectionItemInfo(AccessibilityNodeInfo node,
508             int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
509         // Requires KitKat or higher.
510     }
511
512     @CalledByNative
513     protected void setAccessibilityNodeInfoRangeInfo(AccessibilityNodeInfo node,
514             int rangeType, float min, float max, float current) {
515         // Requires KitKat or higher.
516     }
517
518     @CalledByNative
519     private void setAccessibilityEventBooleanAttributes(AccessibilityEvent event,
520             boolean checked, boolean enabled, boolean password, boolean scrollable) {
521         event.setChecked(checked);
522         event.setEnabled(enabled);
523         event.setPassword(password);
524         event.setScrollable(scrollable);
525     }
526
527     @CalledByNative
528     private void setAccessibilityEventClassName(AccessibilityEvent event, String className) {
529         event.setClassName(className);
530     }
531
532     @CalledByNative
533     private void setAccessibilityEventListAttributes(AccessibilityEvent event,
534             int currentItemIndex, int itemCount) {
535         event.setCurrentItemIndex(currentItemIndex);
536         event.setItemCount(itemCount);
537     }
538
539     @CalledByNative
540     private void setAccessibilityEventScrollAttributes(AccessibilityEvent event,
541             int scrollX, int scrollY, int maxScrollX, int maxScrollY) {
542         event.setScrollX(scrollX);
543         event.setScrollY(scrollY);
544         event.setMaxScrollX(maxScrollX);
545         event.setMaxScrollY(maxScrollY);
546     }
547
548     @CalledByNative
549     private void setAccessibilityEventTextChangedAttrs(AccessibilityEvent event,
550             int fromIndex, int addedCount, int removedCount, String beforeText, String text) {
551         event.setFromIndex(fromIndex);
552         event.setAddedCount(addedCount);
553         event.setRemovedCount(removedCount);
554         event.setBeforeText(beforeText);
555         event.getText().add(text);
556     }
557
558     @CalledByNative
559     private void setAccessibilityEventSelectionAttrs(AccessibilityEvent event,
560             int fromIndex, int addedCount, int itemCount, String text) {
561         event.setFromIndex(fromIndex);
562         event.setAddedCount(addedCount);
563         event.setItemCount(itemCount);
564         event.getText().add(text);
565     }
566
567     @CalledByNative
568     protected void setAccessibilityEventKitKatAttributes(AccessibilityEvent event,
569             boolean canOpenPopup,
570             boolean contentInvalid,
571             boolean dismissable,
572             boolean multiLine,
573             int inputType,
574             int liveRegion) {
575         // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
576         Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
577         bundle.putBoolean("AccessibilityNodeInfo.canOpenPopup", canOpenPopup);
578         bundle.putBoolean("AccessibilityNodeInfo.contentInvalid", contentInvalid);
579         bundle.putBoolean("AccessibilityNodeInfo.dismissable", dismissable);
580         bundle.putBoolean("AccessibilityNodeInfo.multiLine", multiLine);
581         bundle.putInt("AccessibilityNodeInfo.inputType", inputType);
582         bundle.putInt("AccessibilityNodeInfo.liveRegion", liveRegion);
583     }
584
585     @CalledByNative
586     protected void setAccessibilityEventCollectionInfo(AccessibilityEvent event,
587             int rowCount, int columnCount, boolean hierarchical) {
588         // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
589         Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
590         bundle.putInt("AccessibilityNodeInfo.CollectionInfo.rowCount", rowCount);
591         bundle.putInt("AccessibilityNodeInfo.CollectionInfo.columnCount", columnCount);
592         bundle.putBoolean("AccessibilityNodeInfo.CollectionInfo.hierarchical", hierarchical);
593     }
594
595     @CalledByNative
596     protected void setAccessibilityEventCollectionItemInfo(AccessibilityEvent event,
597             int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
598         // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
599         Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
600         bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowIndex", rowIndex);
601         bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowSpan", rowSpan);
602         bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnIndex", columnIndex);
603         bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnSpan", columnSpan);
604         bundle.putBoolean("AccessibilityNodeInfo.CollectionItemInfo.heading", heading);
605     }
606
607     @CalledByNative
608     protected void setAccessibilityEventRangeInfo(AccessibilityEvent event,
609             int rangeType, float min, float max, float current) {
610         // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
611         Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
612         bundle.putInt("AccessibilityNodeInfo.RangeInfo.type", rangeType);
613         bundle.putFloat("AccessibilityNodeInfo.RangeInfo.min", min);
614         bundle.putFloat("AccessibilityNodeInfo.RangeInfo.max", max);
615         bundle.putFloat("AccessibilityNodeInfo.RangeInfo.current", current);
616     }
617
618     private native int nativeGetRootId(long nativeBrowserAccessibilityManagerAndroid);
619     private native boolean nativeIsNodeValid(long nativeBrowserAccessibilityManagerAndroid, int id);
620     private native int nativeHitTest(long nativeBrowserAccessibilityManagerAndroid, int x, int y);
621     private native boolean nativePopulateAccessibilityNodeInfo(
622         long nativeBrowserAccessibilityManagerAndroid, AccessibilityNodeInfo info, int id);
623     private native boolean nativePopulateAccessibilityEvent(
624         long nativeBrowserAccessibilityManagerAndroid, AccessibilityEvent event, int id,
625         int eventType);
626     private native void nativeClick(long nativeBrowserAccessibilityManagerAndroid, int id);
627     private native void nativeFocus(long nativeBrowserAccessibilityManagerAndroid, int id);
628     private native void nativeBlur(long nativeBrowserAccessibilityManagerAndroid);
629     private native void nativeScrollToMakeNodeVisible(
630             long nativeBrowserAccessibilityManagerAndroid, int id);
631 }