0

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:
dmazzoni
2016-04-13 11:55:14 -07:00
committed by Commit bot
parent fd602ac882
commit a21c5040b4
7 changed files with 54 additions and 30 deletions

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