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, |