Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/accessibility/browser_accessibility_manager_android.h" | 5 #include "content/browser/accessibility/browser_accessibility_manager_android.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <cmath> | 9 #include <cmath> |
| 10 | 10 |
| 11 #include "base/android/jni_android.h" | 11 #include "base/android/jni_android.h" |
| 12 #include "base/android/jni_string.h" | 12 #include "base/android/jni_string.h" |
| 13 #include "base/feature_list.h" | |
| 13 #include "base/i18n/char_iterator.h" | 14 #include "base/i18n/char_iterator.h" |
| 14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/values.h" | 17 #include "base/values.h" |
| 18 #include "content/app/strings/grit/content_strings.h" | |
| 17 #include "content/browser/accessibility/browser_accessibility_android.h" | 19 #include "content/browser/accessibility/browser_accessibility_android.h" |
| 18 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" | 20 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" |
| 19 #include "content/common/accessibility_messages.h" | 21 #include "content/common/accessibility_messages.h" |
| 22 #include "content/public/common/content_client.h" | |
| 20 #include "jni/BrowserAccessibilityManager_jni.h" | 23 #include "jni/BrowserAccessibilityManager_jni.h" |
| 21 #include "ui/accessibility/ax_text_utils.h" | 24 #include "ui/accessibility/ax_text_utils.h" |
| 22 | 25 |
| 23 using base::android::AttachCurrentThread; | 26 using base::android::AttachCurrentThread; |
| 24 using base::android::JavaParamRef; | 27 using base::android::JavaParamRef; |
| 25 using base::android::ScopedJavaLocalRef; | 28 using base::android::ScopedJavaLocalRef; |
| 26 | 29 |
| 27 namespace content { | 30 namespace content { |
| 28 | 31 |
| 29 namespace { | 32 namespace { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 InitSearchKeyToPredicateMapIfNeeded(); | 113 InitSearchKeyToPredicateMapIfNeeded(); |
| 111 const auto& iter = g_search_key_to_predicate_map.Get().find(element_type); | 114 const auto& iter = g_search_key_to_predicate_map.Get().find(element_type); |
| 112 if (iter != g_search_key_to_predicate_map.Get().end()) | 115 if (iter != g_search_key_to_predicate_map.Get().end()) |
| 113 return iter->second; | 116 return iter->second; |
| 114 | 117 |
| 115 // If we don't recognize the selector, return any element that a | 118 // If we don't recognize the selector, return any element that a |
| 116 // screen reader should navigate to. | 119 // screen reader should navigate to. |
| 117 return AllInterestingNodesPredicate; | 120 return AllInterestingNodesPredicate; |
| 118 } | 121 } |
| 119 | 122 |
| 123 // The element in the document for which we may be displaying an autofill popup. | |
| 124 int32_t element_hosting_autofill_popup_id_ = -1; | |
|
dmazzoni
2017/03/28 16:47:35
I think globals like this are typically named some
csashi
2017/03/28 17:48:10
Done.
| |
| 125 | |
| 126 // The element that currently has focus. Will be used to set | |
| 127 // |element_hosting_autofill_popup_id_| when we display an autofill popup. | |
| 128 int32_t current_focused_id_ = -1; | |
|
dmazzoni
2017/03/28 16:47:35
You don't need to keep track of this. Just call Ge
| |
| 129 | |
| 130 // Autofill popup will not be part of the |AXTree| that is sent by renderer. | |
| 131 // Hence, we need a proxy |AXNode| to represent the autofill popup. | |
| 132 BrowserAccessibility* autofill_popup_proxy_node_ = nullptr; | |
| 133 ui::AXNode* autofill_popup_proxy_node_ax_node_ = nullptr; | |
| 134 | |
| 120 } // anonymous namespace | 135 } // anonymous namespace |
| 121 | 136 |
| 122 namespace aria_strings { | 137 namespace aria_strings { |
| 123 const char kAriaLivePolite[] = "polite"; | 138 const char kAriaLivePolite[] = "polite"; |
| 124 const char kAriaLiveAssertive[] = "assertive"; | 139 const char kAriaLiveAssertive[] = "assertive"; |
| 125 } | 140 } |
| 126 | 141 |
| 142 const base::Feature kAutofillAccessibility{"AndroidAutofillAccessibility", | |
| 143 base::FEATURE_DISABLED_BY_DEFAULT}; | |
| 144 | |
| 127 // static | 145 // static |
| 128 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 146 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
| 129 const ui::AXTreeUpdate& initial_tree, | 147 const ui::AXTreeUpdate& initial_tree, |
| 130 BrowserAccessibilityDelegate* delegate, | 148 BrowserAccessibilityDelegate* delegate, |
| 131 BrowserAccessibilityFactory* factory) { | 149 BrowserAccessibilityFactory* factory) { |
| 132 return new BrowserAccessibilityManagerAndroid( | 150 return new BrowserAccessibilityManagerAndroid( |
| 133 ScopedJavaLocalRef<jobject>(), initial_tree, delegate, factory); | 151 ScopedJavaLocalRef<jobject>(), initial_tree, delegate, factory); |
| 134 } | 152 } |
| 135 | 153 |
| 136 BrowserAccessibilityManagerAndroid* | 154 BrowserAccessibilityManagerAndroid* |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 610 if (node) | 628 if (node) |
| 611 node->manager()->DoDefaultAction(*node); | 629 node->manager()->DoDefaultAction(*node); |
| 612 } | 630 } |
| 613 | 631 |
| 614 void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env, | 632 void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env, |
| 615 const JavaParamRef<jobject>& obj, | 633 const JavaParamRef<jobject>& obj, |
| 616 jint id) { | 634 jint id) { |
| 617 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 635 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
| 618 if (node) | 636 if (node) |
| 619 node->manager()->SetFocus(*node); | 637 node->manager()->SetFocus(*node); |
| 638 current_focused_id_ = id; | |
| 620 } | 639 } |
| 621 | 640 |
| 622 void BrowserAccessibilityManagerAndroid::Blur( | 641 void BrowserAccessibilityManagerAndroid::Blur( |
| 623 JNIEnv* env, | 642 JNIEnv* env, |
| 624 const JavaParamRef<jobject>& obj) { | 643 const JavaParamRef<jobject>& obj) { |
| 625 SetFocus(*GetRoot()); | 644 SetFocus(*GetRoot()); |
| 626 } | 645 } |
| 627 | 646 |
| 628 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( | 647 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( |
| 629 JNIEnv* env, | 648 JNIEnv* env, |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 736 env, obj, android_node->unique_id()); | 755 env, obj, android_node->unique_id()); |
| 737 } | 756 } |
| 738 } | 757 } |
| 739 | 758 |
| 740 jint BrowserAccessibilityManagerAndroid::FindElementType( | 759 jint BrowserAccessibilityManagerAndroid::FindElementType( |
| 741 JNIEnv* env, | 760 JNIEnv* env, |
| 742 const JavaParamRef<jobject>& obj, | 761 const JavaParamRef<jobject>& obj, |
| 743 jint start_id, | 762 jint start_id, |
| 744 const JavaParamRef<jstring>& element_type_str, | 763 const JavaParamRef<jstring>& element_type_str, |
| 745 jboolean forwards) { | 764 jboolean forwards) { |
| 765 // Navigate forwards to the autofill popup's proxy node if focus is currently | |
| 766 // on the element hosting the autofill popup. Once within the popup, a back | |
| 767 // press will navigate back to the element hosting the popup. | |
| 768 if (forwards && start_id == element_hosting_autofill_popup_id_ && | |
| 769 autofill_popup_proxy_node_) { | |
| 770 return autofill_popup_proxy_node_->unique_id(); | |
| 771 } | |
| 772 | |
| 746 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); | 773 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); |
| 747 if (!start_node) | 774 if (!start_node) |
| 748 return 0; | 775 return 0; |
| 749 | 776 |
| 750 BrowserAccessibilityManager* root_manager = GetRootManager(); | 777 BrowserAccessibilityManager* root_manager = GetRootManager(); |
| 751 if (!root_manager) | 778 if (!root_manager) |
| 752 return 0; | 779 return 0; |
| 753 | 780 |
| 754 BrowserAccessibility* root = root_manager->GetRoot(); | 781 BrowserAccessibility* root = root_manager->GetRoot(); |
| 755 if (!root) | 782 if (!root) |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 911 } | 938 } |
| 912 | 939 |
| 913 return true; | 940 return true; |
| 914 } | 941 } |
| 915 | 942 |
| 916 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( | 943 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( |
| 917 JNIEnv* env, | 944 JNIEnv* env, |
| 918 const JavaParamRef<jobject>& obj, | 945 const JavaParamRef<jobject>& obj, |
| 919 jint id) { | 946 jint id) { |
| 920 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 947 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
| 921 if (!node) | 948 if (node) |
| 922 return; | 949 node->manager()->SetAccessibilityFocus(*node); |
| 923 | |
| 924 node->manager()->SetAccessibilityFocus(*node); | |
| 925 } | 950 } |
| 926 | 951 |
| 927 bool BrowserAccessibilityManagerAndroid::IsSlider( | 952 bool BrowserAccessibilityManagerAndroid::IsSlider( |
| 928 JNIEnv* env, | 953 JNIEnv* env, |
| 929 const JavaParamRef<jobject>& obj, | 954 const JavaParamRef<jobject>& obj, |
| 930 jint id) { | 955 jint id) { |
| 931 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 956 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
| 932 if (!node) | 957 if (!node) |
| 933 return false; | 958 return false; |
| 934 | 959 |
| 935 return node->GetRole() == ui::AX_ROLE_SLIDER; | 960 return node->GetRole() == ui::AX_ROLE_SLIDER; |
| 936 } | 961 } |
| 937 | 962 |
| 963 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDisplayed( | |
| 964 JNIEnv* env, | |
| 965 const JavaParamRef<jobject>& obj) { | |
| 966 if (!base::FeatureList::IsEnabled(kAutofillAccessibility)) | |
| 967 return; | |
| 968 | |
| 969 if (autofill_popup_proxy_node_) { | |
| 970 LOG(ERROR) << "AutofillPopup proxy node exists, unique_id=" | |
|
dmazzoni
2017/03/28 16:47:35
Remove this debugging
csashi
2017/03/28 17:48:10
Done.
| |
| 971 << autofill_popup_proxy_node_->unique_id(); | |
| 972 OnAutofillPopupDismissed(env, obj); | |
| 973 } | |
| 974 | |
| 975 autofill_popup_proxy_node_ = BrowserAccessibility::Create(); | |
|
dmazzoni
2017/03/28 16:47:35
Do we need a check that this doesn't already exist
csashi
2017/03/28 17:48:10
The if statement above checks that.
| |
| 976 autofill_popup_proxy_node_ax_node_ = new ui::AXNode(nullptr, -1, -1); | |
| 977 ui::AXNodeData ax_node_data; | |
| 978 ax_node_data.role = ui::AX_ROLE_MENU; | |
| 979 content::ContentClient* content_client = content::GetContentClient(); | |
| 980 ax_node_data.SetName(content_client->GetLocalizedString( | |
| 981 IDS_AX_AUTOFILL_POPUP_ACCESSIBLE_NODE_DATA)); | |
| 982 ax_node_data.state = 1 << ui::AX_STATE_READ_ONLY; | |
| 983 ax_node_data.state |= 1 << ui::AX_STATE_FOCUSABLE; | |
| 984 ax_node_data.state |= 1 << ui::AX_STATE_SELECTABLE; | |
| 985 autofill_popup_proxy_node_ax_node_->SetData(ax_node_data); | |
| 986 autofill_popup_proxy_node_->Init(this, autofill_popup_proxy_node_ax_node_); | |
| 987 | |
| 988 element_hosting_autofill_popup_id_ = current_focused_id_; | |
|
dmazzoni
2017/03/28 16:47:35
Use GetFocus()->GetId() here
csashi
2017/03/28 17:48:10
Done.
| |
| 989 } | |
| 990 | |
| 991 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDismissed( | |
| 992 JNIEnv* env, | |
| 993 const JavaParamRef<jobject>& obj) { | |
| 994 element_hosting_autofill_popup_id_ = -1; | |
| 995 | |
| 996 if (autofill_popup_proxy_node_) { | |
|
dmazzoni
2017/03/28 16:47:35
Do we also need to clean this up if
BrowserAccessi
csashi
2017/03/28 17:48:10
Done.
| |
| 997 autofill_popup_proxy_node_->Destroy(); | |
| 998 delete autofill_popup_proxy_node_ax_node_; | |
| 999 autofill_popup_proxy_node_ = nullptr; | |
| 1000 } | |
| 1001 } | |
| 1002 | |
| 1003 jboolean BrowserAccessibilityManagerAndroid::IsAutofillPopupNode( | |
| 1004 JNIEnv* env, | |
| 1005 const JavaParamRef<jobject>& obj, | |
| 1006 jint id) { | |
| 1007 return autofill_popup_proxy_node_ && | |
| 1008 autofill_popup_proxy_node_->unique_id() == id; | |
| 1009 } | |
| 1010 | |
| 1011 jint BrowserAccessibilityManagerAndroid::GetElementHostingAutofillPopupId( | |
| 1012 JNIEnv* env, | |
| 1013 const base::android::JavaParamRef<jobject>& obj) { | |
| 1014 return autofill_popup_proxy_node_ ? autofill_popup_proxy_node_->unique_id() | |
| 1015 : -1; | |
| 1016 } | |
| 1017 | |
| 938 bool BrowserAccessibilityManagerAndroid::Scroll( | 1018 bool BrowserAccessibilityManagerAndroid::Scroll( |
| 939 JNIEnv* env, | 1019 JNIEnv* env, |
| 940 const JavaParamRef<jobject>& obj, | 1020 const JavaParamRef<jobject>& obj, |
| 941 jint id, | 1021 jint id, |
| 942 int direction) { | 1022 int direction) { |
| 943 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 1023 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
| 944 if (!node) | 1024 if (!node) |
| 945 return false; | 1025 return false; |
| 946 | 1026 |
| 947 return node->Scroll(direction); | 1027 return node->Scroll(direction); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 986 | 1066 |
| 987 JNIEnv* env = AttachCurrentThread(); | 1067 JNIEnv* env = AttachCurrentThread(); |
| 988 return root_manager->java_ref().get(env); | 1068 return root_manager->java_ref().get(env); |
| 989 } | 1069 } |
| 990 | 1070 |
| 991 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { | 1071 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { |
| 992 return RegisterNativesImpl(env); | 1072 return RegisterNativesImpl(env); |
| 993 } | 1073 } |
| 994 | 1074 |
| 995 } // namespace content | 1075 } // namespace content |
| OLD | NEW |