Fix Android accessibility for editable text fields
For text fields we need to set the text using setText, not setContentDescription, and we also need to call setEditable(true), both on the AccessibilityNodeInfo for the editable text field. See bug for details, this allows you to use cursor controls in TalkBack. BUG=592297 Review URL: https://codereview.chromium.org/1872013002 Cr-Commit-Position: refs/heads/master@{#387054}
This commit is contained in:
content
browser
accessibility
public
android
java
src
org
chromium
content
browser
accessibility
test
data
accessibility
@@ -153,7 +153,7 @@ class CONTENT_EXPORT BrowserAccessibility {
|
||||
|
||||
// This is to handle the cases such as ARIA textbox, where the value should
|
||||
// be calculated from the object's inner text.
|
||||
base::string16 GetValue() const;
|
||||
virtual base::string16 GetValue() const;
|
||||
|
||||
// Searches in the given text and from the given offset until the start of
|
||||
// the next or previous word is found and returns its position.
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
const base::char16 kSecurePasswordBullet = 0x2022;
|
||||
|
||||
// These are enums from android.text.InputType in Java:
|
||||
enum {
|
||||
ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0,
|
||||
@@ -66,6 +68,22 @@ void BrowserAccessibilityAndroid::OnLocationChanged() {
|
||||
manager()->NotifyAccessibilityEvent(ui::AX_EVENT_LOCATION_CHANGED, this);
|
||||
}
|
||||
|
||||
base::string16 BrowserAccessibilityAndroid::GetValue() const {
|
||||
base::string16 value = BrowserAccessibility::GetValue();
|
||||
|
||||
// Optionally replace entered password text with bullet characters
|
||||
// based on a user preference.
|
||||
if (IsPassword()) {
|
||||
bool should_expose = static_cast<BrowserAccessibilityManagerAndroid*>(
|
||||
manager())->ShouldExposePasswordText();
|
||||
if (!should_expose) {
|
||||
value = base::string16(value.size(), kSecurePasswordBullet);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool BrowserAccessibilityAndroid::PlatformIsLeaf() const {
|
||||
if (BrowserAccessibility::PlatformIsLeaf())
|
||||
return true;
|
||||
|
@@ -20,6 +20,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
|
||||
void OnDataChanged() override;
|
||||
bool IsNative() const override;
|
||||
void OnLocationChanged() override;
|
||||
base::string16 GetValue() const override;
|
||||
|
||||
bool PlatformIsLeaf() const override;
|
||||
|
||||
|
@@ -181,6 +181,16 @@ void BrowserAccessibilityManagerAndroid::SetContentViewCore(
|
||||
content_view_core.obj()).obj());
|
||||
}
|
||||
|
||||
bool BrowserAccessibilityManagerAndroid::ShouldExposePasswordText() {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager();
|
||||
if (obj.is_null())
|
||||
return false;
|
||||
|
||||
return Java_BrowserAccessibilityManager_shouldExposePasswordText(
|
||||
env, obj.obj());
|
||||
}
|
||||
|
||||
void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
|
||||
ui::AXEvent event_type,
|
||||
BrowserAccessibility* node) {
|
||||
@@ -403,13 +413,11 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
|
||||
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoClassName(
|
||||
env, obj, info,
|
||||
base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj());
|
||||
if (!node->IsPassword() ||
|
||||
Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
|
||||
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoContentDescription(
|
||||
env, obj, info,
|
||||
base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(),
|
||||
node->IsLink());
|
||||
}
|
||||
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoText(
|
||||
env, obj, info,
|
||||
base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(),
|
||||
node->IsLink(),
|
||||
node->IsEditableText());
|
||||
base::string16 element_id;
|
||||
if (node->GetHtmlAttribute("id", &element_id)) {
|
||||
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoViewIdResourceName(
|
||||
@@ -506,12 +514,8 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
|
||||
|
||||
switch (event_type) {
|
||||
case ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED: {
|
||||
base::string16 before_text, text;
|
||||
if (!node->IsPassword() ||
|
||||
Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
|
||||
before_text = node->GetTextChangeBeforeText();
|
||||
text = node->GetText();
|
||||
}
|
||||
base::string16 before_text = node->GetTextChangeBeforeText();
|
||||
base::string16 text = node->GetText();
|
||||
Java_BrowserAccessibilityManager_setAccessibilityEventTextChangedAttrs(
|
||||
env, obj, event,
|
||||
node->GetTextChangeFromIndex(),
|
||||
@@ -523,11 +527,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
|
||||
break;
|
||||
}
|
||||
case ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED: {
|
||||
base::string16 text;
|
||||
if (!node->IsPassword() ||
|
||||
Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
|
||||
text = node->GetText();
|
||||
}
|
||||
base::string16 text = node->GetText();
|
||||
Java_BrowserAccessibilityManager_setAccessibilityEventSelectionAttrs(
|
||||
env, obj, event,
|
||||
node->GetSelectionStart(),
|
||||
@@ -744,11 +744,7 @@ jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
|
||||
int end_index = -1;
|
||||
if (NextAtGranularity(granularity, cursor_index, node,
|
||||
&start_index, &end_index)) {
|
||||
base::string16 text;
|
||||
if (!node->IsPassword() ||
|
||||
Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
|
||||
text = node->GetText();
|
||||
}
|
||||
base::string16 text = node->GetText();
|
||||
Java_BrowserAccessibilityManager_finishGranularityMove(
|
||||
env, obj, base::android::ConvertUTF16ToJavaString(
|
||||
env, text).obj(),
|
||||
|
@@ -74,6 +74,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
|
||||
}
|
||||
bool prune_tree_for_screen_reader() { return prune_tree_for_screen_reader_; }
|
||||
|
||||
bool ShouldExposePasswordText();
|
||||
|
||||
// Implementation of BrowserAccessibilityManager.
|
||||
void NotifyAccessibilityEvent(ui::AXEvent event_type,
|
||||
BrowserAccessibility* node) override;
|
||||
|
@@ -854,14 +854,20 @@ public class BrowserAccessibilityManager {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@CalledByNative
|
||||
private void setAccessibilityNodeInfoContentDescription(
|
||||
AccessibilityNodeInfo node, String contentDescription, boolean annotateAsLink) {
|
||||
private void setAccessibilityNodeInfoText(
|
||||
AccessibilityNodeInfo node, String text, boolean annotateAsLink,
|
||||
boolean isEditableText) {
|
||||
CharSequence charSequence = text;
|
||||
if (annotateAsLink) {
|
||||
SpannableString spannable = new SpannableString(contentDescription);
|
||||
SpannableString spannable = new SpannableString(text);
|
||||
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
|
||||
node.setContentDescription(spannable);
|
||||
charSequence = spannable;
|
||||
}
|
||||
if (isEditableText) {
|
||||
node.setText(charSequence);
|
||||
node.setEditable(true);
|
||||
} else {
|
||||
node.setContentDescription(contentDescription);
|
||||
node.setContentDescription(charSequence);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
android.webkit.WebView focusable scrollable
|
||||
++android.view.View
|
||||
++++android.widget.EditText clickable editable_text focusable focused password name='secret' input_type=225 text_change_added_count=6
|
||||
++++android.widget.EditText clickable editable_text focusable focused password name='••••••' input_type=225 text_change_added_count=6
|
||||
|
||||
|
Reference in New Issue
Block a user