Support the rich content for accessibility service (1/n)

Goal: 1. let third party developer can use html text that include from their local image file and
         animated image instead of only plain text to rich their content.
      2. Avoid malicious links made by third party developer

Action: 1. Add html, static text, and animated image preferences.
        2. Add android:AnimatedImageDrawable, and android:htmlDescription attributes.
        3. Fine-tune interface and integration
        4. Add custom tag filter

Bug: 136292241
Test: Maunal & make RunSettingsRoboTests
Change-Id: I82cd5319efb7faa1ff7e8354a279828fce5135b8
This commit is contained in:
Peter_Liang
2019-10-31 11:45:16 +08:00
parent d7ba70ee54
commit 64f1374c64
11 changed files with 555 additions and 10 deletions

View File

@@ -16,10 +16,16 @@
package com.android.settings.accessibility;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.view.View;
import android.widget.ImageView;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -29,7 +35,9 @@ import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch;
import com.android.settingslib.widget.FooterPreference;
import java.util.ArrayList;
import java.util.List;
public abstract class ToggleFeaturePreferenceFragment extends SettingsPreferenceFragment {
@@ -40,6 +48,30 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
protected CharSequence mSettingsTitle;
protected Intent mSettingsIntent;
protected ComponentName mComponentName;
protected Uri mImageUri;
protected CharSequence mStaticDescription;
protected CharSequence mHtmlDescription;
private static final String ANCHOR_TAG = "a";
private static final String DRAWABLE_FOLDER = "drawable";
// For html description of accessibility service, third party developer must follow the rule,
// such as <img src="R.drawable.fileName"/>, a11y settings will get third party resources
// by this.
private static final String IMG_PREFIX = "R.drawable.";
private ImageView mImageGetterCacheView;
private final Html.ImageGetter mImageGetter = (String str) -> {
if (str != null && str.startsWith(IMG_PREFIX)) {
final String fileName = str.substring(IMG_PREFIX.length());
return getDrawableFromUri(Uri.parse(
ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ mComponentName.getPackageName() + "/" + DRAWABLE_FOLDER + "/"
+ fileName));
}
return null;
};
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -63,15 +95,45 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
onProcessArguments(getArguments());
updateSwitchBarText(mSwitchBar);
PreferenceScreen preferenceScreen = getPreferenceScreen();
// Show the "Settings" menu as if it were a preference screen
if (mSettingsTitle != null && mSettingsIntent != null) {
PreferenceScreen preferenceScreen = getPreferenceScreen();
Preference settingsPref = new Preference(preferenceScreen.getContext());
settingsPref.setTitle(mSettingsTitle);
settingsPref.setIconSpaceReserved(true);
settingsPref.setIntent(mSettingsIntent);
preferenceScreen.addPreference(settingsPref);
}
if (mImageUri != null) {
final AnimatedImagePreference animatedImagePreference = new AnimatedImagePreference(
preferenceScreen.getContext());
animatedImagePreference.setImageUri(mImageUri);
animatedImagePreference.setDividerAllowedAbove(true);
preferenceScreen.addPreference(animatedImagePreference);
}
if (mStaticDescription != null) {
final StaticTextPreference staticTextPreference = new StaticTextPreference(
preferenceScreen.getContext());
staticTextPreference.setSummary(mStaticDescription);
preferenceScreen.addPreference(staticTextPreference);
}
if (mHtmlDescription != null) {
// For accessibility service, avoid malicious links made by third party developer
final List<String> unsupportedTagList = new ArrayList<>();
unsupportedTagList.add(ANCHOR_TAG);
final HtmlTextPreference htmlTextPreference = new HtmlTextPreference(
preferenceScreen.getContext());
htmlTextPreference.setSummary(mHtmlDescription);
htmlTextPreference.setImageGetter(mImageGetter);
htmlTextPreference.setUnsupportedTagList(unsupportedTagList);
htmlTextPreference.setDividerAllowedAbove(true);
preferenceScreen.addPreference(htmlTextPreference);
}
}
@Override
@@ -139,17 +201,30 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
// Summary.
if (arguments.containsKey(AccessibilitySettings.EXTRA_SUMMARY_RES)) {
final int summary = arguments.getInt(AccessibilitySettings.EXTRA_SUMMARY_RES);
createFooterPreference(getText(summary));
mStaticDescription = getText(summary);
} else if (arguments.containsKey(AccessibilitySettings.EXTRA_SUMMARY)) {
final CharSequence summary = arguments.getCharSequence(
AccessibilitySettings.EXTRA_SUMMARY);
createFooterPreference(summary);
mStaticDescription = summary;
}
}
private void createFooterPreference(CharSequence title) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.addPreference(new FooterPreference.Builder(getActivity()).setTitle(
title).build());
private Drawable getDrawableFromUri(Uri imageUri) {
if (mImageGetterCacheView == null) {
mImageGetterCacheView = new ImageView(getContext());
}
mImageGetterCacheView.setAdjustViewBounds(true);
mImageGetterCacheView.setImageURI(imageUri);
final Drawable drawable = mImageGetterCacheView.getDrawable().mutate();
if (drawable != null) {
drawable.setBounds(/* left= */0, /* top= */0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
}
mImageGetterCacheView.setImageURI(null);
mImageGetterCacheView.setImageDrawable(null);
return drawable;
}
}