Commit b548f9cf authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Expose the language to Android accessibility services using LocaleSpans

TalkBack and other accessibility services on Android now pay attention to
LocaleSpans to determine what language to use when speaking text. Wrap
text in AccessibilityNodeInfo in a LocaleSpan indicating the correct
language, but for efficiency, only do this when it's different than the
system language.

BUG=725134

Review-Url: https://codereview.chromium.org/2902533002
Cr-Commit-Position: refs/heads/master@{#473989}
parent baf703ff
......@@ -495,7 +495,9 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoText(
env, obj, info,
base::android::ConvertUTF16ToJavaString(env, node->GetText()),
node->IsLink(), node->IsEditableText());
node->IsLink(), node->IsEditableText(),
base::android::ConvertUTF16ToJavaString(
env, node->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE)));
base::string16 element_id;
if (node->GetHtmlAttribute("id", &element_id)) {
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoViewIdResourceName(
......
......@@ -57,7 +57,7 @@ public class BrowserAccessibilityManager {
protected static final int ACTION_SCROLL_RIGHT = 0x0102003b;
private final AccessibilityNodeProvider mAccessibilityNodeProvider;
private ContentViewCore mContentViewCore;
protected ContentViewCore mContentViewCore;
private final AccessibilityManager mAccessibilityManager;
private final RenderCoordinates mRenderCoordinates;
private long mNativeObj;
......@@ -955,20 +955,23 @@ public class BrowserAccessibilityManager {
@SuppressLint("NewApi")
@CalledByNative
private void setAccessibilityNodeInfoText(
AccessibilityNodeInfo node, String text, boolean annotateAsLink,
boolean isEditableText) {
CharSequence charSequence = text;
private void setAccessibilityNodeInfoText(AccessibilityNodeInfo node, String text,
boolean annotateAsLink, boolean isEditableText, String language) {
CharSequence computedText = computeText(text, isEditableText, language);
if (isEditableText) {
node.setText(computedText);
} else {
node.setContentDescription(computedText);
}
}
protected CharSequence computeText(String text, boolean annotateAsLink, String language) {
if (annotateAsLink) {
SpannableString spannable = new SpannableString(text);
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
charSequence = spannable;
}
if (isEditableText) {
node.setText(charSequence);
} else {
node.setContentDescription(charSequence);
return spannable;
}
return text;
}
@CalledByNative
......
......@@ -5,7 +5,13 @@
package org.chromium.content.browser.accessibility;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.text.SpannableString;
import android.text.style.LocaleSpan;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
......@@ -14,6 +20,8 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.content.browser.ContentViewCore;
import java.util.Locale;
/**
* Subclass of BrowserAccessibilityManager for Lollipop.
*/
......@@ -22,10 +30,21 @@ import org.chromium.content.browser.ContentViewCore;
public class LollipopBrowserAccessibilityManager extends KitKatBrowserAccessibilityManager {
private static SparseArray<AccessibilityAction> sAccessibilityActionMap =
new SparseArray<AccessibilityAction>();
private String mSystemLanguageTag;
LollipopBrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
ContentViewCore contentViewCore) {
super(nativeBrowserAccessibilityManagerAndroid, contentViewCore);
// Cache the system language and set up a listener for when it changes.
IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
mContentViewCore.getContext().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mSystemLanguageTag = Locale.getDefault().toLanguageTag();
}
}, filter);
mSystemLanguageTag = Locale.getDefault().toLanguageTag();
}
@Override
......@@ -123,4 +142,21 @@ public class LollipopBrowserAccessibilityManager extends KitKatBrowserAccessibil
}
node.addAction(action);
}
@Override
protected CharSequence computeText(String text, boolean annotateAsLink, String language) {
CharSequence charSequence = super.computeText(text, annotateAsLink, language);
if (!language.isEmpty() && !language.equals(mSystemLanguageTag)) {
SpannableString spannable;
if (charSequence instanceof SpannableString) {
spannable = (SpannableString) charSequence;
} else {
spannable = new SpannableString(charSequence);
}
Locale locale = Locale.forLanguageTag(language);
spannable.setSpan(new LocaleSpan(locale), 0, spannable.length(), 0);
return spannable;
}
return charSequence;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment