| Index: content/browser/accessibility/browser_accessibility_manager_android.cc
|
| diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
|
| index 50238249d9767846b77a602dac1fa37e1159bf59..d2b5e70c60bb5c534dc15aecd57544217682a890 100644
|
| --- a/content/browser/accessibility/browser_accessibility_manager_android.cc
|
| +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
|
| @@ -10,13 +10,16 @@
|
|
|
| #include "base/android/jni_android.h"
|
| #include "base/android/jni_string.h"
|
| +#include "base/feature_list.h"
|
| #include "base/i18n/char_iterator.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/values.h"
|
| +#include "content/app/strings/grit/content_strings.h"
|
| #include "content/browser/accessibility/browser_accessibility_android.h"
|
| #include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
|
| #include "content/common/accessibility_messages.h"
|
| +#include "content/public/common/content_features.h"
|
| #include "jni/BrowserAccessibilityManager_jni.h"
|
| #include "ui/accessibility/ax_text_utils.h"
|
|
|
| @@ -117,6 +120,22 @@ AccessibilityMatchPredicate PredicateForSearchKey(
|
| return AllInterestingNodesPredicate;
|
| }
|
|
|
| +// The element in the document for which we may be displaying an autofill popup.
|
| +int32_t g_element_hosting_autofill_popup_unique_id = -1;
|
| +
|
| +// Autofill popup will not be part of the |AXTree| that is sent by renderer.
|
| +// Hence, we need a proxy |AXNode| to represent the autofill popup.
|
| +BrowserAccessibility* g_autofill_popup_proxy_node = nullptr;
|
| +ui::AXNode* g_autofill_popup_proxy_node_ax_node = nullptr;
|
| +
|
| +void DeleteAutofillPopupProxy() {
|
| + if (g_autofill_popup_proxy_node) {
|
| + g_autofill_popup_proxy_node->Destroy();
|
| + delete g_autofill_popup_proxy_node_ax_node;
|
| + g_autofill_popup_proxy_node = nullptr;
|
| + }
|
| +}
|
| +
|
| } // anonymous namespace
|
|
|
| namespace aria_strings {
|
| @@ -155,6 +174,9 @@ BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
|
| if (obj.is_null())
|
| return;
|
|
|
| + // Clean up autofill popup proxy node in case the popup was not dismissed.
|
| + DeleteAutofillPopupProxy();
|
| +
|
| Java_BrowserAccessibilityManager_onNativeObjectDestroyed(
|
| env, obj, reinterpret_cast<intptr_t>(this));
|
| }
|
| @@ -743,6 +765,14 @@ jint BrowserAccessibilityManagerAndroid::FindElementType(
|
| jint start_id,
|
| const JavaParamRef<jstring>& element_type_str,
|
| jboolean forwards) {
|
| + // Navigate forwards to the autofill popup's proxy node if focus is currently
|
| + // on the element hosting the autofill popup. Once within the popup, a back
|
| + // press will navigate back to the element hosting the popup.
|
| + if (forwards && start_id == g_element_hosting_autofill_popup_unique_id &&
|
| + g_autofill_popup_proxy_node) {
|
| + return g_autofill_popup_proxy_node->unique_id();
|
| + }
|
| +
|
| BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id);
|
| if (!start_node)
|
| return 0;
|
| @@ -918,10 +948,8 @@ void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus(
|
| const JavaParamRef<jobject>& obj,
|
| jint id) {
|
| BrowserAccessibilityAndroid* node = GetFromUniqueID(id);
|
| - if (!node)
|
| - return;
|
| -
|
| - node->manager()->SetAccessibilityFocus(*node);
|
| + if (node)
|
| + node->manager()->SetAccessibilityFocus(*node);
|
| }
|
|
|
| bool BrowserAccessibilityManagerAndroid::IsSlider(
|
| @@ -935,6 +963,48 @@ bool BrowserAccessibilityManagerAndroid::IsSlider(
|
| return node->GetRole() == ui::AX_ROLE_SLIDER;
|
| }
|
|
|
| +void BrowserAccessibilityManagerAndroid::OnAutofillPopupDisplayed(
|
| + JNIEnv* env,
|
| + const JavaParamRef<jobject>& obj) {
|
| + if (!base::FeatureList::IsEnabled(features::kAndroidAutofillAccessibility))
|
| + return;
|
| +
|
| + BrowserAccessibility* current_focus = GetFocus();
|
| + if (current_focus == nullptr) {
|
| + return;
|
| + }
|
| +
|
| + DeleteAutofillPopupProxy();
|
| +
|
| + g_autofill_popup_proxy_node = BrowserAccessibility::Create();
|
| + g_autofill_popup_proxy_node_ax_node = new ui::AXNode(nullptr, -1, -1);
|
| + ui::AXNodeData ax_node_data;
|
| + ax_node_data.role = ui::AX_ROLE_MENU;
|
| + ax_node_data.SetName("Autofill");
|
| + ax_node_data.state = 1 << ui::AX_STATE_READ_ONLY;
|
| + ax_node_data.state |= 1 << ui::AX_STATE_FOCUSABLE;
|
| + ax_node_data.state |= 1 << ui::AX_STATE_SELECTABLE;
|
| + g_autofill_popup_proxy_node_ax_node->SetData(ax_node_data);
|
| + g_autofill_popup_proxy_node->Init(this, g_autofill_popup_proxy_node_ax_node);
|
| +
|
| + g_element_hosting_autofill_popup_unique_id = current_focus->unique_id();
|
| +}
|
| +
|
| +void BrowserAccessibilityManagerAndroid::OnAutofillPopupDismissed(
|
| + JNIEnv* env,
|
| + const JavaParamRef<jobject>& obj) {
|
| + g_element_hosting_autofill_popup_unique_id = -1;
|
| + DeleteAutofillPopupProxy();
|
| +}
|
| +
|
| +jboolean BrowserAccessibilityManagerAndroid::IsAutofillPopupNode(
|
| + JNIEnv* env,
|
| + const JavaParamRef<jobject>& obj,
|
| + jint id) {
|
| + return g_autofill_popup_proxy_node &&
|
| + g_autofill_popup_proxy_node->unique_id() == id;
|
| +}
|
| +
|
| bool BrowserAccessibilityManagerAndroid::Scroll(
|
| JNIEnv* env,
|
| const JavaParamRef<jobject>& obj,
|
|
|