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 Rect mAccessibilityFocusRect;
49 private boolean mIsHovering;
50 private int mLastHoverId = View.NO_ID;
51 private int mCurrentRootId;
52 private final int[] mTempLocation = new int[2];
53 private final ViewGroup mView;
54 private boolean mUserHasTouchExplored;
55 private boolean mPendingScrollToMakeNodeVisible;
56 private boolean mNotifyFrameInfoInitializedCalled;
59 * Create a BrowserAccessibilityManager object, which is owned by the C++
60 * BrowserAccessibilityManagerAndroid instance, and connects to the content view.
61 * @param nativeBrowserAccessibilityManagerAndroid A pointer to the counterpart native
62 * C++ object that owns this object.
63 * @param contentViewCore The content view that this object provides accessibility for.
66 private static BrowserAccessibilityManager create(long nativeBrowserAccessibilityManagerAndroid,
67 ContentViewCore contentViewCore) {
68 // A bug in the KitKat framework prevents us from using these new APIs.
69 // http://crbug.com/348088/
70 // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
71 // return new KitKatBrowserAccessibilityManager(
72 // nativeBrowserAccessibilityManagerAndroid, contentViewCore);
74 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
75 return new JellyBeanBrowserAccessibilityManager(
76 nativeBrowserAccessibilityManagerAndroid, contentViewCore);
78 return new BrowserAccessibilityManager(
79 nativeBrowserAccessibilityManagerAndroid, contentViewCore);
83 protected BrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
84 ContentViewCore contentViewCore) {
85 mNativeObj = nativeBrowserAccessibilityManagerAndroid;
86 mContentViewCore = contentViewCore;
87 mContentViewCore.setBrowserAccessibilityManager(this);
88 mAccessibilityFocusId = View.NO_ID;
90 mCurrentRootId = View.NO_ID;
91 mView = mContentViewCore.getContainerView();
92 mRenderCoordinates = mContentViewCore.getRenderCoordinates();
93 mAccessibilityManager =
94 (AccessibilityManager) mContentViewCore.getContext()
95 .getSystemService(Context.ACCESSIBILITY_SERVICE);
99 private void onNativeObjectDestroyed() {
100 if (mContentViewCore.getBrowserAccessibilityManager() == this) {
101 mContentViewCore.setBrowserAccessibilityManager(null);
104 mContentViewCore = null;
108 * @return An AccessibilityNodeProvider on JellyBean, and null on previous versions.
110 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
115 * @see AccessibilityNodeProvider#createAccessibilityNodeInfo(int)
117 protected AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
118 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
122 int rootId = nativeGetRootId(mNativeObj);
124 if (virtualViewId == View.NO_ID) {
125 return createNodeForHost(rootId);
128 if (!isFrameInfoInitialized()) {
132 final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(mView);
133 info.setPackageName(mContentViewCore.getContext().getPackageName());
134 info.setSource(mView, virtualViewId);
136 if (virtualViewId == rootId) {
137 info.setParent(mView);
140 if (nativePopulateAccessibilityNodeInfo(mNativeObj, info, virtualViewId)) {
149 * @see AccessibilityNodeProvider#findAccessibilityNodeInfosByText(String, int)
151 protected List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
153 return new ArrayList<AccessibilityNodeInfo>();
157 * @see AccessibilityNodeProvider#performAction(int, int, Bundle)
159 protected boolean performAction(int virtualViewId, int action, Bundle arguments) {
160 // We don't support any actions on the host view or nodes
161 // that are not (any longer) in the tree.
162 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
163 || !nativeIsNodeValid(mNativeObj, virtualViewId)) {
168 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
169 if (!moveAccessibilityFocusToId(virtualViewId)) return true;
172 nativeScrollToMakeNodeVisible(
173 mNativeObj, mAccessibilityFocusId);
175 mPendingScrollToMakeNodeVisible = true;
178 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
179 if (mAccessibilityFocusId == virtualViewId) {
180 sendAccessibilityEvent(mAccessibilityFocusId,
181 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
182 mAccessibilityFocusId = View.NO_ID;
183 mAccessibilityFocusRect = null;
186 case AccessibilityNodeInfo.ACTION_CLICK:
187 nativeClick(mNativeObj, virtualViewId);
188 sendAccessibilityEvent(virtualViewId,
189 AccessibilityEvent.TYPE_VIEW_CLICKED);
191 case AccessibilityNodeInfo.ACTION_FOCUS:
192 nativeFocus(mNativeObj, virtualViewId);
194 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS:
195 nativeBlur(mNativeObj);
198 case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT: {
199 if (arguments == null)
201 String elementType = arguments.getString(
202 AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
203 if (elementType == null)
205 elementType = elementType.toUpperCase(Locale.US);
206 return jumpToElementType(elementType, true);
208 case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT: {
209 if (arguments == null)
211 String elementType = arguments.getString(
212 AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
213 if (elementType == null)
215 elementType = elementType.toUpperCase(Locale.US);
216 return jumpToElementType(elementType, false);
226 * @see View#onHoverEvent(MotionEvent)
228 public boolean onHoverEvent(MotionEvent event) {
229 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
233 if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
235 if (mPendingScrollToMakeNodeVisible) {
236 nativeScrollToMakeNodeVisible(
237 mNativeObj, mAccessibilityFocusId);
239 mPendingScrollToMakeNodeVisible = false;
244 mUserHasTouchExplored = true;
245 float x = event.getX();
246 float y = event.getY();
248 // Convert to CSS coordinates.
249 int cssX = (int) (mRenderCoordinates.fromPixToLocalCss(x));
250 int cssY = (int) (mRenderCoordinates.fromPixToLocalCss(y));
252 // This sends an IPC to the render process to do the hit testing.
253 // The response is handled by handleHover.
254 nativeHitTest(mNativeObj, cssX, cssY);
259 * Called by ContentViewCore to notify us when the frame info is initialized,
260 * the first time, since until that point, we can't use mRenderCoordinates to transform
261 * web coordinates to screen coordinates.
263 public void notifyFrameInfoInitialized() {
264 if (mNotifyFrameInfoInitializedCalled)
267 mNotifyFrameInfoInitializedCalled = true;
269 // Invalidate the container view, since the chrome accessibility tree is now
270 // ready and listed as the child of the container view.
271 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
273 // (Re-) focus focused element, since we weren't able to create an
274 // AccessibilityNodeInfo for this element before.
275 if (mAccessibilityFocusId != View.NO_ID) {
276 moveAccessibilityFocusToIdAndRefocusIfNeeded(mAccessibilityFocusId);
280 private boolean jumpToElementType(String elementType, boolean forwards) {
281 int id = nativeFindElementType(mNativeObj, mAccessibilityFocusId, elementType, forwards);
285 moveAccessibilityFocusToId(id);
289 private boolean moveAccessibilityFocusToId(int newAccessibilityFocusId) {
290 if (newAccessibilityFocusId == mAccessibilityFocusId)
293 mAccessibilityFocusId = newAccessibilityFocusId;
294 mAccessibilityFocusRect = null;
295 sendAccessibilityEvent(mAccessibilityFocusId,
296 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
300 private void moveAccessibilityFocusToIdAndRefocusIfNeeded(int newAccessibilityFocusId) {
301 // Work around a bug in the Android framework where it doesn't fully update the object
302 // with accessibility focus even if you send it a WINDOW_CONTENT_CHANGED. To work around
303 // this, clear focus and then set focus again.
304 if (newAccessibilityFocusId == mAccessibilityFocusId) {
305 sendAccessibilityEvent(newAccessibilityFocusId,
306 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
307 mAccessibilityFocusId = View.NO_ID;
310 moveAccessibilityFocusToId(newAccessibilityFocusId);
313 private void sendAccessibilityEvent(int virtualViewId, int eventType) {
314 // If we don't have any frame info, then the virtual hierarchy
315 // doesn't exist in the view of the Android framework, so should
316 // never send any events.
317 if (!mAccessibilityManager.isEnabled() || mNativeObj == 0
318 || !isFrameInfoInitialized()) {
322 // This is currently needed if we want Android to draw the yellow box around
323 // the item that has accessibility focus. In practice, this doesn't seem to slow
324 // things down, because it's only called when the accessibility focus moves.
325 // TODO(dmazzoni): remove this if/when Android framework fixes bug.
326 mView.postInvalidate();
328 // The container view is indicated by a virtualViewId of NO_ID; post these events directly
329 // since there's no web-specific information to attach.
330 if (virtualViewId == View.NO_ID) {
331 mView.sendAccessibilityEvent(eventType);
335 final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
336 event.setPackageName(mContentViewCore.getContext().getPackageName());
337 event.setSource(mView, virtualViewId);
338 if (!nativePopulateAccessibilityEvent(mNativeObj, event, virtualViewId, eventType)) {
343 mView.requestSendAccessibilityEvent(mView, event);
346 private Bundle getOrCreateBundleForAccessibilityEvent(AccessibilityEvent event) {
347 Bundle bundle = (Bundle) event.getParcelableData();
348 if (bundle == null) {
349 bundle = new Bundle();
350 event.setParcelableData(bundle);
355 private AccessibilityNodeInfo createNodeForHost(int rootId) {
356 // Since we don't want the parent to be focusable, but we can't remove
357 // actions from a node, copy over the necessary fields.
358 final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(mView);
359 final AccessibilityNodeInfo source = AccessibilityNodeInfo.obtain(mView);
360 mView.onInitializeAccessibilityNodeInfo(source);
362 // Copy over parent and screen bounds.
363 Rect rect = new Rect();
364 source.getBoundsInParent(rect);
365 result.setBoundsInParent(rect);
366 source.getBoundsInScreen(rect);
367 result.setBoundsInScreen(rect);
369 // Set up the parent view, if applicable.
370 final ViewParent parent = mView.getParentForAccessibility();
371 if (parent instanceof View) {
372 result.setParent((View) parent);
375 // Populate the minimum required fields.
376 result.setVisibleToUser(source.isVisibleToUser());
377 result.setEnabled(source.isEnabled());
378 result.setPackageName(source.getPackageName());
379 result.setClassName(source.getClassName());
381 // Add the Chrome root node.
382 if (isFrameInfoInitialized()) {
383 result.addChild(mView, rootId);
390 * Returns whether or not the frame info is initialized, meaning we can safely
391 * convert web coordinates to screen coordinates. When this is first initialized,
392 * notifyFrameInfoInitialized is called - but we shouldn't check whether or not
393 * that method was called as a way to determine if frame info is valid because
394 * notifyFrameInfoInitialized might not be called at all if mRenderCoordinates
395 * gets initialized first.
397 private boolean isFrameInfoInitialized() {
398 return mRenderCoordinates.getContentWidthCss() != 0.0 ||
399 mRenderCoordinates.getContentHeightCss() != 0.0;
403 private void handlePageLoaded(int id) {
404 if (mUserHasTouchExplored) return;
406 if (mContentViewCore.shouldSetAccessibilityFocusOnPageLoad()) {
407 moveAccessibilityFocusToIdAndRefocusIfNeeded(id);
412 private void handleFocusChanged(int id) {
413 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_FOCUSED);
414 moveAccessibilityFocusToId(id);
418 private void handleCheckStateChanged(int id) {
419 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
423 private void handleTextSelectionChanged(int id) {
424 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
428 private void handleEditableTextChanged(int id) {
429 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
433 private void handleContentChanged(int id) {
434 int rootId = nativeGetRootId(mNativeObj);
435 if (rootId != mCurrentRootId) {
436 mCurrentRootId = rootId;
437 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
439 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
444 private void handleNavigate() {
445 mAccessibilityFocusId = View.NO_ID;
446 mAccessibilityFocusRect = null;
447 mUserHasTouchExplored = false;
448 // Invalidate the host, since its child is now gone.
449 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
453 private void handleScrollPositionChanged(int id) {
454 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED);
458 private void handleScrolledToAnchor(int id) {
459 moveAccessibilityFocusToId(id);
463 private void handleHover(int id) {
464 if (mLastHoverId == id) return;
466 // Always send the ENTER and then the EXIT event, to match a standard Android View.
467 sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
468 sendAccessibilityEvent(mLastHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
473 private void announceLiveRegionText(String text) {
474 mView.announceForAccessibility(text);
478 private void setAccessibilityNodeInfoParent(AccessibilityNodeInfo node, int parentId) {
479 node.setParent(mView, parentId);
483 private void addAccessibilityNodeInfoChild(AccessibilityNodeInfo node, int childId) {
484 node.addChild(mView, childId);
488 private void setAccessibilityNodeInfoBooleanAttributes(AccessibilityNodeInfo node,
489 int virtualViewId, boolean checkable, boolean checked, boolean clickable,
490 boolean enabled, boolean focusable, boolean focused, boolean password,
491 boolean scrollable, boolean selected, boolean visibleToUser) {
492 node.setCheckable(checkable);
493 node.setChecked(checked);
494 node.setClickable(clickable);
495 node.setEnabled(enabled);
496 node.setFocusable(focusable);
497 node.setFocused(focused);
498 node.setPassword(password);
499 node.setScrollable(scrollable);
500 node.setSelected(selected);
501 node.setVisibleToUser(visibleToUser);
503 node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
504 node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
508 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
510 node.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
514 if (mAccessibilityFocusId == virtualViewId) {
515 node.setAccessibilityFocused(true);
516 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
518 node.setAccessibilityFocused(false);
519 node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
523 node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
528 private void setAccessibilityNodeInfoClassName(AccessibilityNodeInfo node,
530 node.setClassName(className);
534 private void setAccessibilityNodeInfoContentDescription(
535 AccessibilityNodeInfo node, String contentDescription, boolean annotateAsLink) {
536 if (annotateAsLink) {
537 SpannableString spannable = new SpannableString(contentDescription);
538 spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
539 node.setContentDescription(spannable);
541 node.setContentDescription(contentDescription);
546 private void setAccessibilityNodeInfoLocation(AccessibilityNodeInfo node,
547 final int virtualViewId,
548 int absoluteLeft, int absoluteTop, int parentRelativeLeft, int parentRelativeTop,
549 int width, int height, boolean isRootNode) {
550 // First set the bounds in parent.
551 Rect boundsInParent = new Rect(parentRelativeLeft, parentRelativeTop,
552 parentRelativeLeft + width, parentRelativeTop + height);
554 // Offset of the web content relative to the View.
555 boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
557 node.setBoundsInParent(boundsInParent);
559 // Now set the absolute rect, which requires several transformations.
560 Rect rect = new Rect(absoluteLeft, absoluteTop, absoluteLeft + width, absoluteTop + height);
562 // Offset by the scroll position.
563 rect.offset(-(int) mRenderCoordinates.getScrollX(),
564 -(int) mRenderCoordinates.getScrollY());
566 // Convert CSS (web) pixels to Android View pixels
567 rect.left = (int) mRenderCoordinates.fromLocalCssToPix(rect.left);
568 rect.top = (int) mRenderCoordinates.fromLocalCssToPix(rect.top);
569 rect.bottom = (int) mRenderCoordinates.fromLocalCssToPix(rect.bottom);
570 rect.right = (int) mRenderCoordinates.fromLocalCssToPix(rect.right);
572 // Offset by the location of the web content within the view.
574 (int) mRenderCoordinates.getContentOffsetYPix());
576 // Finally offset by the location of the view within the screen.
577 final int[] viewLocation = new int[2];
578 mView.getLocationOnScreen(viewLocation);
579 rect.offset(viewLocation[0], viewLocation[1]);
581 node.setBoundsInScreen(rect);
583 // Work around a bug in the Android framework where if the object with accessibility
584 // focus moves, the accessibility focus rect is not updated - both the visual highlight,
585 // and the location on the screen that's clicked if you double-tap. To work around this,
586 // when we know the object with accessibility focus moved, move focus away and then
587 // move focus right back to it, which tricks Android into updating its bounds.
588 if (virtualViewId == mAccessibilityFocusId && virtualViewId != mCurrentRootId) {
589 if (mAccessibilityFocusRect == null) {
590 mAccessibilityFocusRect = rect;
591 } else if (!mAccessibilityFocusRect.equals(rect)) {
592 mAccessibilityFocusRect = rect;
593 moveAccessibilityFocusToIdAndRefocusIfNeeded(virtualViewId);
599 protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
600 boolean canOpenPopup,
601 boolean contentInvalid,
606 // Requires KitKat or higher.
610 protected void setAccessibilityNodeInfoCollectionInfo(AccessibilityNodeInfo node,
611 int rowCount, int columnCount, boolean hierarchical) {
612 // Requires KitKat or higher.
616 protected void setAccessibilityNodeInfoCollectionItemInfo(AccessibilityNodeInfo node,
617 int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
618 // Requires KitKat or higher.
622 protected void setAccessibilityNodeInfoRangeInfo(AccessibilityNodeInfo node,
623 int rangeType, float min, float max, float current) {
624 // Requires KitKat or higher.
628 private void setAccessibilityEventBooleanAttributes(AccessibilityEvent event,
629 boolean checked, boolean enabled, boolean password, boolean scrollable) {
630 event.setChecked(checked);
631 event.setEnabled(enabled);
632 event.setPassword(password);
633 event.setScrollable(scrollable);
637 private void setAccessibilityEventClassName(AccessibilityEvent event, String className) {
638 event.setClassName(className);
642 private void setAccessibilityEventListAttributes(AccessibilityEvent event,
643 int currentItemIndex, int itemCount) {
644 event.setCurrentItemIndex(currentItemIndex);
645 event.setItemCount(itemCount);
649 private void setAccessibilityEventScrollAttributes(AccessibilityEvent event,
650 int scrollX, int scrollY, int maxScrollX, int maxScrollY) {
651 event.setScrollX(scrollX);
652 event.setScrollY(scrollY);
653 event.setMaxScrollX(maxScrollX);
654 event.setMaxScrollY(maxScrollY);
658 private void setAccessibilityEventTextChangedAttrs(AccessibilityEvent event,
659 int fromIndex, int addedCount, int removedCount, String beforeText, String text) {
660 event.setFromIndex(fromIndex);
661 event.setAddedCount(addedCount);
662 event.setRemovedCount(removedCount);
663 event.setBeforeText(beforeText);
664 event.getText().add(text);
668 private void setAccessibilityEventSelectionAttrs(AccessibilityEvent event,
669 int fromIndex, int addedCount, int itemCount, String text) {
670 event.setFromIndex(fromIndex);
671 event.setAddedCount(addedCount);
672 event.setItemCount(itemCount);
673 event.getText().add(text);
677 protected void setAccessibilityEventKitKatAttributes(AccessibilityEvent event,
678 boolean canOpenPopup,
679 boolean contentInvalid,
684 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
685 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
686 bundle.putBoolean("AccessibilityNodeInfo.canOpenPopup", canOpenPopup);
687 bundle.putBoolean("AccessibilityNodeInfo.contentInvalid", contentInvalid);
688 bundle.putBoolean("AccessibilityNodeInfo.dismissable", dismissable);
689 bundle.putBoolean("AccessibilityNodeInfo.multiLine", multiLine);
690 bundle.putInt("AccessibilityNodeInfo.inputType", inputType);
691 bundle.putInt("AccessibilityNodeInfo.liveRegion", liveRegion);
695 protected void setAccessibilityEventCollectionInfo(AccessibilityEvent event,
696 int rowCount, int columnCount, boolean hierarchical) {
697 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
698 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
699 bundle.putInt("AccessibilityNodeInfo.CollectionInfo.rowCount", rowCount);
700 bundle.putInt("AccessibilityNodeInfo.CollectionInfo.columnCount", columnCount);
701 bundle.putBoolean("AccessibilityNodeInfo.CollectionInfo.hierarchical", hierarchical);
705 protected void setAccessibilityEventCollectionItemInfo(AccessibilityEvent event,
706 int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
707 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
708 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
709 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowIndex", rowIndex);
710 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.rowSpan", rowSpan);
711 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnIndex", columnIndex);
712 bundle.putInt("AccessibilityNodeInfo.CollectionItemInfo.columnSpan", columnSpan);
713 bundle.putBoolean("AccessibilityNodeInfo.CollectionItemInfo.heading", heading);
717 protected void setAccessibilityEventRangeInfo(AccessibilityEvent event,
718 int rangeType, float min, float max, float current) {
719 // Backwards compatibility for KitKat AccessibilityNodeInfo fields.
720 Bundle bundle = getOrCreateBundleForAccessibilityEvent(event);
721 bundle.putInt("AccessibilityNodeInfo.RangeInfo.type", rangeType);
722 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.min", min);
723 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.max", max);
724 bundle.putFloat("AccessibilityNodeInfo.RangeInfo.current", current);
727 private native int nativeGetRootId(long nativeBrowserAccessibilityManagerAndroid);
728 private native boolean nativeIsNodeValid(long nativeBrowserAccessibilityManagerAndroid, int id);
729 private native void nativeHitTest(long nativeBrowserAccessibilityManagerAndroid, int x, int y);
730 private native boolean nativePopulateAccessibilityNodeInfo(
731 long nativeBrowserAccessibilityManagerAndroid, AccessibilityNodeInfo info, int id);
732 private native boolean nativePopulateAccessibilityEvent(
733 long nativeBrowserAccessibilityManagerAndroid, AccessibilityEvent event, int id,
735 private native void nativeClick(long nativeBrowserAccessibilityManagerAndroid, int id);
736 private native void nativeFocus(long nativeBrowserAccessibilityManagerAndroid, int id);
737 private native void nativeBlur(long nativeBrowserAccessibilityManagerAndroid);
738 private native void nativeScrollToMakeNodeVisible(
739 long nativeBrowserAccessibilityManagerAndroid, int id);
740 private native int nativeFindElementType(long nativeBrowserAccessibilityManagerAndroid,
741 int startId, String elementType, boolean forwards);