Upstream version 10.38.208.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.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;
21
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;
26
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
30
31 /**
32  * Native accessibility for a {@link ContentViewCore}.
33  *
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
37  * accessibility.
38  */
39 @JNINamespace("content")
40 public class BrowserAccessibilityManager {
41     private static final String TAG = "BrowserAccessibilityManager";
42
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;
55
56     /**
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.
62      */
63     @CalledByNative
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);
71
72         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
73             return new JellyBeanBrowserAccessibilityManager(
74                     nativeBrowserAccessibilityManagerAndroid, contentViewCore);
75         } else {
76             return new BrowserAccessibilityManager(
77                     nativeBrowserAccessibilityManagerAndroid, contentViewCore);
78         }
79     }
80
81     protected BrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
82             ContentViewCore contentViewCore) {
83         mNativeObj = nativeBrowserAccessibilityManagerAndroid;
84         mContentViewCore = contentViewCore;
85         mContentViewCore.setBrowserAccessibilityManager(this);
86         mAccessibilityFocusId = View.NO_ID;
87         mIsHovering = false;
88         mCurrentRootId = View.NO_ID;
89         mView = mContentViewCore.getContainerView();
90         mRenderCoordinates = mContentViewCore.getRenderCoordinates();
91         mAccessibilityManager =
92             (AccessibilityManager) mContentViewCore.getContext()
93             .getSystemService(Context.ACCESSIBILITY_SERVICE);
94     }
95
96     @CalledByNative
97     private void onNativeObjectDestroyed() {
98         if (mContentViewCore.getBrowserAccessibilityManager() == this) {
99             mContentViewCore.setBrowserAccessibilityManager(null);
100         }
101         mNativeObj = 0;
102         mContentViewCore = null;
103     }
104
105     /**
106      * @return An AccessibilityNodeProvider on JellyBean, and null on previous versions.
107      */
108     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
109         return null;
110     }
111
112     /**
113      * @see AccessibilityNodeProvider#createAccessibilityNodeInfo(int)
114      */
115     protected AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
116         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
117             return null;
118         }
119
120         int rootId = nativeGetRootId(mNativeObj);
121
122         if (virtualViewId == View.NO_ID) {
123             return createNodeForHost(rootId);
124         }
125
126         if (!isFrameInfoInitialized()) {
127             return null;
128         }
129
130         final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(mView);
131         info.setPackageName(mContentViewCore.getContext().getPackageName());
132         info.setSource(mView, virtualViewId);
133
134         if (virtualViewId == rootId) {
135             info.setParent(mView);
136         }
137
138         if (nativePopulateAccessibilityNodeInfo(mNativeObj, info, virtualViewId)) {
139             return info;
140         } else {
141             info.recycle();
142             return null;
143         }
144     }
145
146     /**
147      * @see AccessibilityNodeProvider#findAccessibilityNodeInfosByText(String, int)
148      */
149     protected List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
150             int virtualViewId) {
151         return new ArrayList<AccessibilityNodeInfo>();
152     }
153
154     /**
155      * @see AccessibilityNodeProvider#performAction(int, int, Bundle)
156      */
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)) {
162             return false;
163         }
164
165         switch (action) {
166             case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
167                 if (mAccessibilityFocusId == virtualViewId) {
168                     return true;
169                 }
170
171                 mAccessibilityFocusId = virtualViewId;
172                 sendAccessibilityEvent(mAccessibilityFocusId,
173                         AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
174                 if (!mIsHovering) {
175                     nativeScrollToMakeNodeVisible(
176                             mNativeObj, mAccessibilityFocusId);
177                 } else {
178                     mPendingScrollToMakeNodeVisible = true;
179                 }
180                 return 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;
186                 }
187                 return true;
188             case AccessibilityNodeInfo.ACTION_CLICK:
189                 nativeClick(mNativeObj, virtualViewId);
190                 sendAccessibilityEvent(virtualViewId,
191                         AccessibilityEvent.TYPE_VIEW_CLICKED);
192                 return true;
193             case AccessibilityNodeInfo.ACTION_FOCUS:
194                 nativeFocus(mNativeObj, virtualViewId);
195                 return true;
196             case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS:
197                 nativeBlur(mNativeObj);
198                 return true;
199
200             case AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT: {
201                 if (arguments == null)
202                     return false;
203                 String elementType = arguments.getString(
204                     AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
205                 if (elementType == null)
206                     return false;
207                 elementType = elementType.toUpperCase(Locale.US);
208                 return jumpToElementType(elementType, true);
209             }
210             case AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT: {
211                 if (arguments == null)
212                     return false;
213                 String elementType = arguments.getString(
214                     AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING);
215                 if (elementType == null)
216                     return false;
217                 elementType = elementType.toUpperCase(Locale.US);
218                 return jumpToElementType(elementType, false);
219             }
220
221             default:
222                 break;
223         }
224         return false;
225     }
226
227     /**
228      * @see View#onHoverEvent(MotionEvent)
229      */
230     public boolean onHoverEvent(MotionEvent event) {
231         if (!mAccessibilityManager.isEnabled() || mNativeObj == 0) {
232             return false;
233         }
234
235         if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
236             mIsHovering = false;
237             if (mPendingScrollToMakeNodeVisible) {
238                 nativeScrollToMakeNodeVisible(
239                         mNativeObj, mAccessibilityFocusId);
240             }
241             mPendingScrollToMakeNodeVisible = false;
242             return true;
243         }
244
245         mIsHovering = true;
246         mUserHasTouchExplored = true;
247         float x = event.getX();
248         float y = event.getY();
249
250         // Convert to CSS coordinates.
251         int cssX = (int) (mRenderCoordinates.fromPixToLocalCss(x));
252         int cssY = (int) (mRenderCoordinates.fromPixToLocalCss(y));
253
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);
257         return true;
258     }
259
260     /**
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.
264      */
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);
269
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);
275         }
276     }
277
278     private boolean jumpToElementType(String elementType, boolean forwards) {
279         int id = nativeFindElementType(mNativeObj, mAccessibilityFocusId, elementType, forwards);
280         if (id == 0)
281             return false;
282
283         mAccessibilityFocusId = id;
284         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
285         return true;
286     }
287
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()) {
294             return;
295         }
296
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();
302
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);
307             return;
308         }
309
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)) {
314             event.recycle();
315             return;
316         }
317
318         mView.requestSendAccessibilityEvent(mView, event);
319     }
320
321     private Bundle getOrCreateBundleForAccessibilityEvent(AccessibilityEvent event) {
322         Bundle bundle = (Bundle) event.getParcelableData();
323         if (bundle == null) {
324             bundle = new Bundle();
325             event.setParcelableData(bundle);
326         }
327         return bundle;
328     }
329
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);
336
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);
343
344         // Set up the parent view, if applicable.
345         final ViewParent parent = mView.getParentForAccessibility();
346         if (parent instanceof View) {
347             result.setParent((View) parent);
348         }
349
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());
355
356         // Add the Chrome root node.
357         if (isFrameInfoInitialized()) {
358             result.addChild(mView, rootId);
359         }
360
361         return result;
362     }
363
364     private boolean isFrameInfoInitialized() {
365         return mRenderCoordinates.getContentWidthCss() != 0.0 ||
366                mRenderCoordinates.getContentHeightCss() != 0.0;
367     }
368
369     @CalledByNative
370     private void handlePageLoaded(int id) {
371         if (mUserHasTouchExplored) return;
372
373         if (mContentViewCore.shouldSetAccessibilityFocusOnPageLoad()) {
374             mAccessibilityFocusId = id;
375             sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
376         }
377     }
378
379     @CalledByNative
380     private void handleFocusChanged(int id) {
381         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_FOCUSED);
382
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;
387         }
388     }
389
390     @CalledByNative
391     private void handleCheckStateChanged(int id) {
392         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
393     }
394
395     @CalledByNative
396     private void handleTextSelectionChanged(int id) {
397         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
398     }
399
400     @CalledByNative
401     private void handleEditableTextChanged(int id) {
402         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
403     }
404
405     @CalledByNative
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);
411         } else {
412             sendAccessibilityEvent(id, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
413         }
414     }
415
416     @CalledByNative
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);
422     }
423
424     @CalledByNative
425     private void handleScrollPositionChanged(int id) {
426         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED);
427     }
428
429     @CalledByNative
430     private void handleScrolledToAnchor(int id) {
431         if (mAccessibilityFocusId == id) {
432             return;
433         }
434
435         mAccessibilityFocusId = id;
436         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
437     }
438
439     @CalledByNative
440     private void handleHover(int id) {
441         if (mLastHoverId == id) return;
442
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);
446         mLastHoverId = id;
447     }
448
449     @CalledByNative
450     private void announceLiveRegionText(String text) {
451         mView.announceForAccessibility(text);
452     }
453
454     @CalledByNative
455     private void setAccessibilityNodeInfoParent(AccessibilityNodeInfo node, int parentId) {
456         node.setParent(mView, parentId);
457     }
458
459     @CalledByNative
460     private void addAccessibilityNodeInfoChild(AccessibilityNodeInfo node, int childId) {
461         node.addChild(mView, childId);
462     }
463
464     @CalledByNative
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);
479
480         node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
481         node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
482
483         if (focusable) {
484             if (focused) {
485                 node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
486             } else {
487                 node.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
488             }
489         }
490
491         if (mAccessibilityFocusId == virtualViewId) {
492             node.setAccessibilityFocused(true);
493             node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
494         } else {
495             node.setAccessibilityFocused(false);
496             node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
497         }
498
499         if (clickable) {
500             node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
501         }
502     }
503
504     @CalledByNative
505     private void setAccessibilityNodeInfoClassName(AccessibilityNodeInfo node,
506             String className) {
507         node.setClassName(className);
508     }
509
510     @CalledByNative
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);
517         } else {
518             node.setContentDescription(contentDescription);
519         }
520     }
521
522     @CalledByNative
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);
529         if (isRootNode) {
530             // Offset of the web content relative to the View.
531             boundsInParent.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
532         }
533         node.setBoundsInParent(boundsInParent);
534
535         // Now set the absolute rect, which requires several transformations.
536         Rect rect = new Rect(absoluteLeft, absoluteTop, absoluteLeft + width, absoluteTop + height);
537
538         // Offset by the scroll position.
539         rect.offset(-(int) mRenderCoordinates.getScrollX(),
540                     -(int) mRenderCoordinates.getScrollY());
541
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);
547
548         // Offset by the location of the web content within the view.
549         rect.offset(0,
550                     (int) mRenderCoordinates.getContentOffsetYPix());
551
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]);
556
557         node.setBoundsInScreen(rect);
558     }
559
560     @CalledByNative
561     protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
562             boolean canOpenPopup,
563             boolean contentInvalid,
564             boolean dismissable,
565             boolean multiLine,
566             int inputType,
567             int liveRegion) {
568         // Requires KitKat or higher.
569     }
570
571     @CalledByNative
572     protected void setAccessibilityNodeInfoCollectionInfo(AccessibilityNodeInfo node,
573             int rowCount, int columnCount, boolean hierarchical) {
574         // Requires KitKat or higher.
575     }
576
577     @CalledByNative
578     protected void setAccessibilityNodeInfoCollectionItemInfo(AccessibilityNodeInfo node,
579             int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) {
580         // Requires KitKat or higher.
581     }
582
583     @CalledByNative
584     protected void setAccessibilityNodeInfoRangeInfo(AccessibilityNodeInfo node,
585             int rangeType, float min, float max, float current) {
586         // Requires KitKat or higher.
587     }
588
589     @CalledByNative
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);
596     }
597
598     @CalledByNative
599     private void setAccessibilityEventClassName(AccessibilityEvent event, String className) {
600         event.setClassName(className);
601     }
602
603     @CalledByNative
604     private void setAccessibilityEventListAttributes(AccessibilityEvent event,
605             int currentItemIndex, int itemCount) {
606         event.setCurrentItemIndex(currentItemIndex);
607         event.setItemCount(itemCount);
608     }
609
610     @CalledByNative
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);
617     }
618
619     @CalledByNative
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);
627     }
628
629     @CalledByNative
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);
636     }
637
638     @CalledByNative
639     protected void setAccessibilityEventKitKatAttributes(AccessibilityEvent event,
640             boolean canOpenPopup,
641             boolean contentInvalid,
642             boolean dismissable,
643             boolean multiLine,
644             int inputType,
645             int liveRegion) {
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);
654     }
655
656     @CalledByNative
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);
664     }
665
666     @CalledByNative
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);
676     }
677
678     @CalledByNative
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);
687     }
688
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,
696         int eventType);
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);
704 }