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.
5 package org.chromium.content.browser.accessibility;
7 import android.content.Context;
8 import android.graphics.Rect;
9 import android.os.Build;
10 import android.os.Bundle;
11 import android.text.SpannableString;
12 import android.text.style.URLSpan;
13 import android.view.MotionEvent;
14 import android.view.View;
15 import android.view.ViewGroup;
16 import android.view.ViewParent;
17 import android.view.accessibility.AccessibilityEvent;
18 import android.view.accessibility.AccessibilityManager;
19 import android.view.accessibility.AccessibilityNodeInfo;
20 import android.view.accessibility.AccessibilityNodeProvider;
22 import org.chromium.base.CalledByNative;
23 import org.chromium.base.JNINamespace;
24 import org.chromium.content.browser.ContentViewCore;
25 import org.chromium.content.browser.RenderCoordinates;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
32 * Native accessibility for a {@link ContentViewCore}.
34 * This class is safe to load on ICS and can be used to run tests, but
35 * only the subclass, JellyBeanBrowserAccessibilityManager, actually
36 * has a AccessibilityNodeProvider implementation needed for native
39 @JNINamespace("content")
40 public class BrowserAccessibilityManager {
41 private static final String TAG = "BrowserAccessibilityManager";
43 private ContentViewCore mContentViewCore;
44 private final AccessibilityManager mAccessibilityManager;
45 private final RenderCoordinates mRenderCoordinates;
46 private long mNativeObj;
47 private int mAccessibilityFocusId;
48 private boolean mIsHovering;
49 private int mLastHoverId = View.NO_ID;
50 private int mCurrentRootId;
51 private final int[] mTempLocation = new int[2];
52 private final ViewGroup mView;
53 private boolean mUserHasTouchExplored;
54 private boolean mPendingScrollToMakeNodeVisible;
57 * Create a BrowserAccessibilityManager object, which is owned by the C++
58 * BrowserAccessibilityManagerAndroid instance, and connects to the content view.
59 * @param nativeBrowserAccessibilityManagerAndroid A pointer to the counterpart native
60 * C++ object that owns this object.
61 * @param contentViewCore The content view that this object provides accessibility for.
64 private static BrowserAccessibilityManager create(long nativeBrowserAccessibilityManagerAndroid,
65 ContentViewCore contentViewCore) {
66 // A bug in the KitKat framework prevents us from using these new APIs.
67 // http://crbug.com/348088/
68 // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
69 // return new KitKatBrowserAccessibilityManager(
70 // nativeBrowserAccessibilityManagerAndroid, contentViewCore);
72 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
73 return new JellyBeanBrowserAccessibilityManager(
74 nativeBrowserAccessibilityManagerAndroid, contentViewCore);
76 return new BrowserAccessibilityManager(
77 nativeBrowserAccessibilityManagerAndroid, contentViewCore);
81 protected BrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
82 ContentViewCore contentViewCore) {
83 mNativeObj = nativeBrowserAccessibilityManagerAndroid;
84 mContentViewCore = contentViewCore;
85 mContentViewCore.setBrowserAccessibilityManager(this);
86 mAccessibilityFocusId = View.NO_ID;
88 mCurrentRootId = View.NO_ID;
89 mView = mContentViewCore.getContainerView();
90 mRenderCoordinates = mContentViewCore.getRenderCoordinates();
91 mAccessibilityManager =
92 (AccessibilityManager) mContentViewCore.getContext()
93 .getSystemService(Context.ACCESSIBILITY_SERVICE);
97 private void onNativeObjectDestroyed() {
98 if (mContentViewCore.getBrowserAccessibilityManager() == this) {
99 mContentViewCore.setBrowserAccessibilityManager(null);
102 mContentViewCore = null;
106 * @return An AccessibilityNodeProvider on JellyBean, and null on previous versions.
108 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
113 * @see AccessibilityNodeProvider#createAccessibilityNodeInfo(int)
115 protected AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
116 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
120 int rootId = nativeGetRootId(mNativeObj);
122 if (virtualViewId == View.NO_ID) {
123 return createNodeForHost(rootId);
126 if (!isFrameInfoInitialized()) {
130 final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(mView);
131 info.setPackageName(mContentViewCore.getContext().getPackageName());
132 info.setSource(mView, virtualViewId);
134 if (virtualViewId == rootId) {
135 info.setParent(mView);
138 if (nativePopulateAccessibilityNodeInfo(mNativeObj, info, virtualViewId)) {
147 * @see AccessibilityNodeProvider#findAccessibilityNodeInfosByText(String, int)
149 protected List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
151 return new ArrayList<AccessibilityNodeInfo>();
155 * @see AccessibilityNodeProvider#performAction(int, int, Bundle)
157 protected boolean performAction(int virtualViewId, int action, Bundle arguments) {
158 // We don't support any actions on the host view or nodes
159 // that are not (any longer) in the tree.
160 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
161 || !nativeIsNodeValid(mNativeObj, virtualViewId)) {
166 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
167 if (mAccessibilityFocusId == virtualViewId) {
171 mAccessibilityFocusId = virtualViewId;
172 sendAccessibilityEvent(mAccessibilityFocusId,
173 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
175 nativeScrollToMakeNodeVisible(
176 mNativeObj, mAccessibilityFocusId);
178 mPendingScrollToMakeNodeVisible = true;
181 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
182 if (mAccessibilityFocusId == virtualViewId) {
183 sendAccessibilityEvent(mAccessibilityFocusId,
184 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
185 mAccessibilityFocusId = View.NO_ID;
188 case AccessibilityNodeInfo.ACTION_CLICK:
189 nativeClick(mNativeObj, virtualViewId);
190 sendAccessibilityEvent(virtualViewId,
191 AccessibilityEvent.TYPE_VIEW_CLICKED);
193 case AccessibilityNodeInfo.ACTION_FOCUS:
194 nativeFocus(mNativeObj, virtualViewId);
196 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS:
197 nativeBlur(mNativeObj);
200 case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT: {
201 if (arguments == null)
203 String elementType = arguments.getString(
204 AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
205 if (elementType == null)
207 elementType = elementType.toUpperCase(Locale.US);
208 return jumpToElementType(elementType, true);
210 case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT: {
211 if (arguments == null)
213 String elementType = arguments.getString(
214 AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
215 if (elementType == null)
217 elementType = elementType.toUpperCase(Locale.US);
218 return jumpToElementType(elementType, false);
228 * @see View#onHoverEvent(MotionEvent)
230 public boolean onHoverEvent(MotionEvent event) {
231 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
235 if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
237 if (mPendingScrollToMakeNodeVisible) {
238 nativeScrollToMakeNodeVisible(
239 mNativeObj, mAccessibilityFocusId);
241 mPendingScrollToMakeNodeVisible = false;
246 mUserHasTouchExplored = true;
247 float x = event.getX();
248 float y = event.getY();
250 // Convert to CSS coordinates.
251 int cssX = (int) (mRenderCoordinates.fromPixToLocalCss(x));
252 int cssY = (int) (mRenderCoordinates.fromPixToLocalCss(y));
254 // This sends an IPC to the render process to do the hit testing.
255 // The response is handled by handleHover.
256 nativeHitTest(mNativeObj, cssX, cssY);
261 * Called by ContentViewCore to notify us when the frame info is initialized,
262 * the first time, since until that point, we can't use mRenderCoordinates to transform
263 * web coordinates to screen coordinates.
265 public void notifyFrameInfoInitialized() {
266 // Invalidate the container view, since the chrome accessibility tree is now
267 // ready and listed as the child of the container view.
268 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
270 // (Re-) focus focused element, since we weren't able to create an
271 // AccessibilityNodeInfo for this element before.
272 if (mAccessibilityFocusId != View.NO_ID) {
273 sendAccessibilityEvent(mAccessibilityFocusId,
274 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
278 private boolean jumpToElementType(String elementType, boolean forwards) {
279 int id = nativeFindElementType(mNativeObj, mAccessibilityFocusId, elementType, forwards);
283 mAccessibilityFocusId = id;
284 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
288 private void sendAccessibilityEvent(int virtualViewId, int eventType) {
289 // If we don't have any frame info, then the virtual hierarchy
290 // doesn't exist in the view of the Android framework, so should
291 // never send any events.
292 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
293 || !isFrameInfoInitialized()) {
297 // This is currently needed if we want Android to draw the yellow box around
298 // the item that has accessibility focus. In practice, this doesn't seem to slow
299 // things down, because it's only called when the accessibility focus moves.
300 // TODO(dmazzoni): remove this if/when Android framework fixes bug.
301 mView.postInvalidate();
303 // The container view is indicated by a virtualViewId of NO_ID; post these events directly
304 // since there's no web-specific information to attach.
305 if (virtualViewId == View.NO_ID) {
306 mView.sendAccessibilityEvent(eventType);
310 final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
311 event.setPackageName(mContentViewCore.getContext().getPackageName());
312 event.setSource(mView, virtualViewId);
313 if (!nativePopulateAccessibilityEvent(mNativeObj, event, virtualViewId, eventType)) {
318 mView.requestSendAccessibilityEvent(mView, event);
321 private Bundle getOrCreateBundleForAccessibilityEvent(AccessibilityEvent event) {
322 Bundle bundle = (Bundle) event.getParcelableData();
323 if (bundle == null) {
324 bundle = new Bundle();
325 event.setParcelableData(bundle);
330 private AccessibilityNodeInfo createNodeForHost(int rootId) {
331 // Since we don't want the parent to be focusable, but we can't remove
332 // actions from a node, copy over the necessary fields.
333 final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(mView);
334 final AccessibilityNodeInfo source = AccessibilityNodeInfo.obtain(mView);
335 mView.onInitializeAccessibilityNodeInfo(source);
337 // Copy over parent and screen bounds.
338 Rect rect = new Rect();
339 source.getBoundsInParent(rect);
340 result.setBoundsInParent(rect);
341 source.getBoundsInScreen(rect);
342 result.setBoundsInScreen(rect);
344 // Set up the parent view, if applicable.
345 final ViewParent parent = mView.getParentForAccessibility();
346 if (parent instanceof View) {
347 result.setParent((View) parent);
350 // Populate the minimum required fields.
351 result.setVisibleToUser(source.isVisibleToUser());
352 result.setEnabled(source.isEnabled());
353 result.setPackageName(source.getPackageName());
354 result.setClassName(source.getClassName());
356 // Add the Chrome root node.
357 if (isFrameInfoInitialized()) {
358 result.addChild(mView, rootId);
364 private boolean isFrameInfoInitialized() {
365 return mRenderCoordinates.getContentWidthCss() != 0.0 ||
366 mRenderCoordinates.getContentHeightCss() != 0.0;
370 private void handlePageLoaded(int id) {
371 if (mUserHasTouchExplored) return;
373 if (mContentViewCore.shouldSetAccessibilityFocusOnPageLoad()) {
374 mAccessibilityFocusId = id;
375 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
380 private void handleFocusChanged(int id) {
381 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_FOCUSED);
383 // Update accessibility focus if not already set to this node.
384 if (mAccessibilityFocusId != id) {
385 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
386 mAccessibilityFocusId = id;
391 private void handleCheckStateChanged(int id) {
392 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
396 private void handleTextSelectionChanged(int id) {
397 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
401 private void handleEditableTextChanged(int id) {
402 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
406 private void handleContentChanged(int id) {
407 int rootId = nativeGetRootId(mNativeObj);
408 if (rootId != mCurrentRootId) {
409 mCurrentRootId = rootId;
410 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
412 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
417 private void handleNavigate() {
418 mAccessibilityFocusId = View.NO_ID;
419 mUserHasTouchExplored = false;
420 // Invalidate the host, since its child is now gone.
421 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
425 private void handleScrollPositionChanged(int id) {
426 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED);
430 private void handleScrolledToAnchor(int id) {
431 if (mAccessibilityFocusId == id) {
435 mAccessibilityFocusId = id;
436 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
440 private void handleHover(int id) {
441 if (mLastHoverId == id) return;
443 // Always send the ENTER and then the EXIT event, to match a standard Android View.
444 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
445 sendAccessibilityEvent(mLastHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
450 private void announceLiveRegionText(String text) {
451 mView.announceForAccessibility(text);
455 private void setAccessibilityNodeInfoParent(AccessibilityNodeInfo node, int parentId) {
456 node.setParent(mView, parentId);
460 private void addAccessibilityNodeInfoChild(AccessibilityNodeInfo node, int childId) {
461 node.addChild(mView, childId);
465 private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node,
466 int virtualViewId, boolean checkable, boolean checked, boolean clickable,
467 boolean enabled, boolean focusable, boolean focused, boolean password,
468 boolean scrollable, boolean selected, boolean visibleToUser) {
469 node.setCheckable(checkable);
470 node.setChecked(checked);
471 node.setClickable(clickable);
472 node.setEnabled(enabled);
473 node.setFocusable(focusable);
474 node.setFocused(focused);
475 node.setPassword(password);
476 node.setScrollable(scrollable);
477 node.setSelected(selected);
478 node.setVisibleToUser(visibleToUser);
480 node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
481 node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
485 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
487 node.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
491 if (mAccessibilityFocusId == virtualViewId) {
492 node.setAccessibilityFocused(true);
493 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
495 node.setAccessibilityFocused(false);
496 node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
500 node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
505 private void setAccessibilityNodeInfoClassName(AccessibilityNodeInfo node,
507 node.setClassName(className);
511 private void setAccessibilityNodeInfoContentDescription(
512 AccessibilityNodeInfo node, String contentDescription, boolean annotateAsLink) {
513 if (annotateAsLink) {
514 SpannableString spannable = new SpannableString(contentDescription);
515 spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
516 node.setContentDescription(spannable);
518 node.setContentDescription(contentDescription);
523 private void setAccessibilityNodeInfoLocation(AccessibilityNodeInfo node,
524 int absoluteLeft, int absoluteTop, int parentRelativeLeft, int parentRelativeTop,
525 int width, int height, boolean isRootNode) {
526 // First set the bounds in parent.
527 Rect boundsInParent = new Rect(parentRelativeLeft, parentRelativeTop,
528 parentRelativeLeft + width, parentRelativeTop + height);
530 // Offset of the web content relative to the View.
531 boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
533 node.setBoundsInParent(boundsInParent);
535 // Now set the absolute rect, which requires several transformations.
536 Rect rect = new Rect(absoluteLeft, absoluteTop, absoluteLeft + width, absoluteTop + height);
538 // Offset by the scroll position.
539 rect.offset(-(int) mRenderCoordinates.getScrollX(),
540 -(int) mRenderCoordinates.getScrollY());
542 // Convert CSS (web) pixels to Android View pixels
543 rect.left = (int) mRenderCoordinates.fromLocalCssToPix(rect.left);
544 rect.top = (int) mRenderCoordinates.fromLocalCssToPix(rect.top);
545 rect.bottom = (int) mRenderCoordinates.fromLocalCssToPix(rect.bottom);
546 rect.right = (int) mRenderCoordinates.fromLocalCssToPix(rect.right);
548 // Offset by the location of the web content within the view.
550 (int) mRenderCoordinates.getContentOffsetYPix());
552 // Finally offset by the location of the view within the screen.
553 final int[] viewLocation = new int[2];
554 mView.getLocationOnScreen(viewLocation);
555 rect.offset(viewLocation[0], viewLocation[1]);
557 node.setBoundsInScreen(rect);
561 protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
562 boolean canOpenPopup,
563 boolean contentInvalid,
568 // Requires KitKat or higher.
572 protected void setAccessibilityNodeInfoCollectionInfo(AccessibilityNodeInfo node,
573 int rowCount, int columnCount, boolean hierarchical) {
574 // Requires KitKat or higher.
578 protected void setAccessibilityNodeInfoCollectionItemInfo(AccessibilityNodeInfo node,
579 int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
580 // Requires KitKat or higher.
584 protected void setAccessibilityNodeInfoRangeInfo(AccessibilityNodeInfo node,
585 int rangeType, float min, float max, float current) {
586 // Requires KitKat or higher.
590 private void setAccessibilityEventBooleanAttributes(AccessibilityEvent event,
591 boolean checked, boolean enabled, boolean password, boolean scrollable) {
592 event.setChecked(checked);
593 event.setEnabled(enabled);
594 event.setPassword(password);
595 event.setScrollable(scrollable);
599 private void setAccessibilityEventClassName(AccessibilityEvent event, String className) {
600 event.setClassName(className);
604 private void setAccessibilityEventListAttributes(AccessibilityEvent event,
605 int currentItemIndex, int itemCount) {
606 event.setCurrentItemIndex(currentItemIndex);
607 event.setItemCount(itemCount);
611 private void setAccessibilityEventScrollAttributes(AccessibilityEvent event,
612 int scrollX, int scrollY, int maxScrollX, int maxScrollY) {
613 event.setScrollX(scrollX);
614 event.setScrollY(scrollY);
615 event.setMaxScrollX(maxScrollX);
616 event.setMaxScrollY(maxScrollY);
620 private void setAccessibilityEventTextChangedAttrs(AccessibilityEvent event,
621 int fromIndex, int addedCount, int removedCount, String beforeText, String text) {
622 event.setFromIndex(fromIndex);
623 event.setAddedCount(addedCount);
624 event.setRemovedCount(removedCount);
625 event.setBeforeText(beforeText);
626 event.getText().add(text);
630 private void setAccessibilityEventSelectionAttrs(AccessibilityEvent event,
631 int fromIndex, int addedCount, int itemCount, String text) {
632 event.setFromIndex(fromIndex);
633 event.setAddedCount(addedCount);
634 event.setItemCount(itemCount);
635 event.getText().add(text);
639 protected void setAccessibilityEventKitKatAttributes(AccessibilityEvent event,
640 boolean canOpenPopup,
641 boolean contentInvalid,
646 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
647 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
648 bundle.putBoolean("AccessibilityNodeInfo.canOpenPopup", canOpenPopup);
649 bundle.putBoolean("AccessibilityNodeInfo.contentInvalid", contentInvalid);
650 bundle.putBoolean("AccessibilityNodeInfo.dismissable", dismissable);
651 bundle.putBoolean("AccessibilityNodeInfo.multiLine", multiLine);
652 bundle.putInt("AccessibilityNodeInfo.inputType", inputType);
653 bundle.putInt("AccessibilityNodeInfo.liveRegion", liveRegion);
657 protected void setAccessibilityEventCollectionInfo(AccessibilityEvent event,
658 int rowCount, int columnCount, boolean hierarchical) {
659 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
660 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
661 bundle.putInt("AccessibilityNodeInfo.CollectionInfo.rowCount", rowCount);
662 bundle.putInt("AccessibilityNodeInfo.CollectionInfo.columnCount", columnCount);
663 bundle.putBoolean("AccessibilityNodeInfo.CollectionInfo.hierarchical", hierarchical);
667 protected void setAccessibilityEventCollectionItemInfo(AccessibilityEvent event,
668 int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
669 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
670 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
671 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowIndex", rowIndex);
672 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowSpan", rowSpan);
673 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnIndex", columnIndex);
674 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnSpan", columnSpan);
675 bundle.putBoolean("AccessibilityNodeInfo.CollectionItemInfo.heading", heading);
679 protected void setAccessibilityEventRangeInfo(AccessibilityEvent event,
680 int rangeType, float min, float max, float current) {
681 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
682 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
683 bundle.putInt("AccessibilityNodeInfo.RangeInfo.type", rangeType);
684 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.min", min);
685 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.max", max);
686 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.current", current);
689 private native int nativeGetRootId(long nativeBrowserAccessibilityManagerAndroid);
690 private native boolean nativeIsNodeValid(long nativeBrowserAccessibilityManagerAndroid, int id);
691 private native void nativeHitTest(long nativeBrowserAccessibilityManagerAndroid, int x, int y);
692 private native boolean nativePopulateAccessibilityNodeInfo(
693 long nativeBrowserAccessibilityManagerAndroid, AccessibilityNodeInfo info, int id);
694 private native boolean nativePopulateAccessibilityEvent(
695 long nativeBrowserAccessibilityManagerAndroid, AccessibilityEvent event, int id,
697 private native void nativeClick(long nativeBrowserAccessibilityManagerAndroid, int id);
698 private native void nativeFocus(long nativeBrowserAccessibilityManagerAndroid, int id);
699 private native void nativeBlur(long nativeBrowserAccessibilityManagerAndroid);
700 private native void nativeScrollToMakeNodeVisible(
701 long nativeBrowserAccessibilityManagerAndroid, int id);
702 private native int nativeFindElementType(long nativeBrowserAccessibilityManagerAndroid,
703 int startId, String elementType, boolean forwards);