17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// found in the LICENSE file.
47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/browser/accessibility/browser_accessibility_manager_android.h"
67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <cmath>
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/android/jni_android.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/android/jni_string.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/utf_string_conversions.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/values.h"
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/browser/accessibility/browser_accessibility_android.h"
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/common/accessibility_messages.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "jni/BrowserAccessibilityManager_jni.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using base::android::AttachCurrentThread;
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using base::android::ScopedJavaLocalRef;
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace {
227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// These are enums from android.view.accessibility.AccessibilityEvent in Java:
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochenum {
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_CHANGED = 16,
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Restricts |val| to the range [min, max].
307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int Clamp(int val, int min, int max) {
317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return std::min(std::max(val, min), max);
327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // anonymous namespace
357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace content {
377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace aria_strings {
397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const char kAriaLivePolite[] = "polite";
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const char kAriaLiveAssertive[] = "assertive";
417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AccessibilityNodeData& src,
467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibilityDelegate* delegate,
477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibilityFactory* factory) {
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return new BrowserAccessibilityManagerAndroid(ScopedJavaLocalRef<jobject>(),
497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                src, delegate, factory);
507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)BrowserAccessibilityManagerAndroid*
530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)BrowserAccessibilityManager::ToBrowserAccessibilityManagerAndroid() {
540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return static_cast<BrowserAccessibilityManagerAndroid*>(this);
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    ScopedJavaLocalRef<jobject> content_view_core,
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const AccessibilityNodeData& src,
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibilityDelegate* delegate,
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibilityFactory* factory)
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : BrowserAccessibilityManager(src, delegate, factory) {
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  SetContentViewCore(content_view_core);
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  JNIEnv* env = AttachCurrentThread();
687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (obj.is_null())
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_onNativeObjectDestroyed(env, obj.obj());
737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)AccessibilityNodeData BrowserAccessibilityManagerAndroid::GetEmptyDocument() {
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  AccessibilityNodeData empty_document;
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  empty_document.id = 0;
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  empty_document.role = blink::WebAXRoleRootWebArea;
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  empty_document.state = 1 << blink::WebAXStateReadonly;
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return empty_document;
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void BrowserAccessibilityManagerAndroid::SetContentViewCore(
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ScopedJavaLocalRef<jobject> content_view_core) {
860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (content_view_core.is_null())
870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  java_ref_ = JavaObjectWeakGlobalRef(
910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      env, Java_BrowserAccessibilityManager_create(
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          env, reinterpret_cast<intptr_t>(this),
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          content_view_core.obj()).obj());
940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    blink::WebAXEvent event_type,
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibility* node) {
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  JNIEnv* env = AttachCurrentThread();
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (obj.is_null())
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
104d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  if (event_type == blink::WebAXEventHide)
105d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    return;
106d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Always send AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED to notify
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // the Android system that the accessibility hierarchy rooted at this
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // node has changed.
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Java_BrowserAccessibilityManager_handleContentChanged(
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      env, obj.obj(), node->renderer_id());
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  switch (event_type) {
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventLoadComplete:
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_handlePageLoaded(
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(), focus_->renderer_id());
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventFocus:
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_handleFocusChanged(
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(), node->renderer_id());
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventCheckedStateChanged:
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_handleCheckStateChanged(
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(), node->renderer_id());
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventScrolledToAnchor:
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_handleScrolledToAnchor(
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(), node->renderer_id());
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventAlert:
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // An alert is a special case of live region. Fall through to the
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // next case to handle it.
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventShow: {
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // This event is fired when an object appears in a live region.
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Speak its text.
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      BrowserAccessibilityAndroid* android_node =
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          static_cast<BrowserAccessibilityAndroid*>(node);
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_announceLiveRegionText(
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(),
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::android::ConvertUTF16ToJavaString(
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              env, android_node->GetText()).obj());
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventSelectedTextChanged:
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_handleTextSelectionChanged(
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj.obj(), node->renderer_id());
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventChildrenChanged:
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventTextChanged:
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case blink::WebAXEventValueChanged:
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (node->IsEditableText()) {
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        Java_BrowserAccessibilityManager_handleEditableTextChanged(
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            env, obj.obj(), node->renderer_id());
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default:
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // There are some notifications that aren't meaningful on Android.
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // It's okay to skip them.
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)jint BrowserAccessibilityManagerAndroid::GetRootId(JNIEnv* env, jobject obj) {
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return static_cast<jint>(root_->renderer_id());
1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
167d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)jboolean BrowserAccessibilityManagerAndroid::IsNodeValid(
168d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)    JNIEnv* env, jobject obj, jint id) {
169d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)  return GetFromRendererID(id) != NULL;
170d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)}
171d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)jint BrowserAccessibilityManagerAndroid::HitTest(
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    JNIEnv* env, jobject obj, jint x, jint y) {
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BrowserAccessibilityAndroid* result =
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      static_cast<BrowserAccessibilityAndroid*>(
1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          root_->BrowserAccessibilityForPoint(gfx::Point(x, y)));
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!result)
1797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return root_->renderer_id();
1807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (result->IsFocusable())
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return result->renderer_id();
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Examine the children of |result| to find the nearest accessibility focus
1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // candidate
1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BrowserAccessibility* nearest_node = FuzzyHitTest(x, y, result);
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (nearest_node)
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return nearest_node->renderer_id();
1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return root_->renderer_id();
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochjboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    JNIEnv* env, jobject obj, jobject info, jint id) {
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GetFromRendererID(id));
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!node)
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (node->parent()) {
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Java_BrowserAccessibilityManager_setAccessibilityNodeInfoParent(
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        env, obj, info, node->parent()->renderer_id());
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (unsigned i = 0; i < node->PlatformChildCount(); ++i) {
2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    Java_BrowserAccessibilityManager_addAccessibilityNodeInfoChild(
2060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        env, obj, info, node->children()[i]->renderer_id());
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes(
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, info,
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      id,
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsCheckable(),
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsChecked(),
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsClickable(),
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsEnabled(),
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsFocusable(),
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsFocused(),
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsPassword(),
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsScrollable(),
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsSelected(),
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsVisibleToUser());
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityNodeInfoStringAttributes(
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, info,
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj(),
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj());
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect absolute_rect = node->GetLocalBoundsRect();
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Rect parent_relative_rect = absolute_rect;
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (node->parent()) {
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    gfx::Rect parent_rect = node->parent()->GetLocalBoundsRect();
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    parent_relative_rect.Offset(-parent_rect.OffsetFromOrigin());
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool is_root = node->parent() == NULL;
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLocation(
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, info,
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      absolute_rect.x(), absolute_rect.y(),
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      parent_relative_rect.x(), parent_relative_rect.y(),
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      absolute_rect.width(), absolute_rect.height(),
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      is_root);
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // New KitKat APIs
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Java_BrowserAccessibilityManager_setAccessibilityNodeInfoKitKatAttributes(
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      env, obj, info,
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->CanOpenPopup(),
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsContentInvalid(),
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsDismissable(),
246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsMultiLine(),
247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->AndroidInputType(),
248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->AndroidLiveRegionType());
249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsCollection()) {
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityNodeInfoCollectionInfo(
251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, info,
252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowCount(),
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnCount(),
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->IsHierarchical());
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsCollectionItem() || node->IsHeading()) {
257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityNodeInfoCollectionItemInfo(
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, info,
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowIndex(),
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowSpan(),
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnIndex(),
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnSpan(),
263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->IsHeading());
264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsRangeType()) {
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityNodeInfoRangeInfo(
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, info,
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->AndroidRangeType(),
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeMin(),
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeMax(),
271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeCurrentValue());
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochjboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    JNIEnv* env, jobject obj, jobject event, jint id, jint event_type) {
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GetFromRendererID(id));
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!node)
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityEventBooleanAttributes(
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, event,
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsChecked(),
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsEnabled(),
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsPassword(),
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->IsScrollable());
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityEventClassName(
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, event,
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj());
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityEventListAttributes(
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, event,
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetItemIndex(),
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetItemCount());
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_setAccessibilityEventScrollAttributes(
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      env, obj, event,
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetScrollX(),
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetScrollY(),
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetMaxScrollX(),
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      node->GetMaxScrollY());
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (event_type) {
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_CHANGED:
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_setAccessibilityEventTextChangedAttrs(
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj, event,
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetTextChangeFromIndex(),
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetTextChangeAddedCount(),
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetTextChangeRemovedCount(),
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::android::ConvertUTF16ToJavaString(
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              env, node->GetTextChangeBeforeText()).obj(),
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj());
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED:
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      Java_BrowserAccessibilityManager_setAccessibilityEventSelectionAttrs(
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          env, obj, event,
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetSelectionStart(),
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetSelectionEnd(),
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          node->GetEditableTextLength(),
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj());
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default:
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Backwards-compatible fallback for new KitKat APIs.
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Java_BrowserAccessibilityManager_setAccessibilityEventKitKatAttributes(
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      env, obj, event,
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->CanOpenPopup(),
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsContentInvalid(),
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsDismissable(),
333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->IsMultiLine(),
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->AndroidInputType(),
335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      node->AndroidLiveRegionType());
336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsCollection()) {
337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityEventCollectionInfo(
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, event,
339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowCount(),
340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnCount(),
341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->IsHierarchical());
342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsCollectionItem() || node->IsHeading()) {
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityEventCollectionItemInfo(
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, event,
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowIndex(),
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RowSpan(),
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnIndex(),
349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->ColumnSpan(),
350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->IsHeading());
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (node->IsRangeType()) {
353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Java_BrowserAccessibilityManager_setAccessibilityEventRangeInfo(
354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        env, obj, event,
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->AndroidRangeType(),
356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeMin(),
357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeMax(),
358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        node->RangeCurrentValue());
359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BrowserAccessibilityManagerAndroid::Click(
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    JNIEnv* env, jobject obj, jint id) {
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserAccessibility* node = GetFromRendererID(id);
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (node)
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DoDefaultAction(*node);
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BrowserAccessibilityManagerAndroid::Focus(
372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    JNIEnv* env, jobject obj, jint id) {
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserAccessibility* node = GetFromRendererID(id);
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (node)
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SetFocus(node, true);
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BrowserAccessibilityManagerAndroid::Blur(JNIEnv* env, jobject obj) {
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetFocus(root_, true);
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BrowserAccessibility* BrowserAccessibilityManagerAndroid::FuzzyHitTest(
3837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int x, int y, BrowserAccessibility* start_node) {
3847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BrowserAccessibility* nearest_node = NULL;
3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int min_distance = INT_MAX;
3867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  FuzzyHitTestImpl(x, y, start_node, &nearest_node, &min_distance);
3877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return nearest_node;
3887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
3917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BrowserAccessibilityManagerAndroid::FuzzyHitTestImpl(
3927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int x, int y, BrowserAccessibility* start_node,
3937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BrowserAccessibility** nearest_candidate, int* nearest_distance) {
3947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BrowserAccessibilityAndroid* node =
3957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      static_cast<BrowserAccessibilityAndroid*>(start_node);
3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int distance = CalculateDistanceSquared(x, y, node);
3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (node->IsFocusable()) {
3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (distance < *nearest_distance) {
4007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      *nearest_candidate = node;
4017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      *nearest_distance = distance;
4027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Don't examine any more children of focusable node
4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // TODO(aboxhall): what about focusable children?
4057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!node->GetText().empty()) {
4097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (distance < *nearest_distance) {
4107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      *nearest_candidate = node;
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      *nearest_distance = distance;
4127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
4147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
4157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (uint32 i = 0; i < node->PlatformChildCount(); i++) {
4170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    BrowserAccessibility* child = node->PlatformGetChild(i);
4180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    FuzzyHitTestImpl(x, y, child, nearest_candidate, nearest_distance);
4197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static
4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int BrowserAccessibilityManagerAndroid::CalculateDistanceSquared(
4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int x, int y, BrowserAccessibility* node) {
4257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  gfx::Rect node_bounds = node->GetLocalBoundsRect();
4267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int nearest_x = Clamp(x, node_bounds.x(), node_bounds.right());
4277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int nearest_y = Clamp(y, node_bounds.y(), node_bounds.bottom());
4287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int dx = std::abs(x - nearest_x);
4297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  int dy = std::abs(y - nearest_y);
4307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return dx * dx + dy * dy;
4317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BrowserAccessibilityManagerAndroid::NotifyRootChanged() {
434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  JNIEnv* env = AttachCurrentThread();
435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (obj.is_null())
437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Java_BrowserAccessibilityManager_handleNavigate(env, obj.obj());
4407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool
4437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() {
4447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // The Java layer handles the root scroll offset.
4457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return false;
4467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return RegisterNativesImpl(env);
4507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
4517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace content
453