Fine-tune the widget of "Allow rich content in Accessibility Settings" for security.
1. Remove tag checker in HtmlTextPreference. 2. Set the max height for AnimatedImagePreference. Bug: 149516547 Test: manaul test Change-Id: I98f49d055db9427d91a3f1ca816e94a11d29cd3d
This commit is contained in:
@@ -21,9 +21,11 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
|
|||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
@@ -350,4 +352,32 @@ final class AccessibilityUtil {
|
|||||||
"Unsupported userShortcutType " + shortcutType);
|
"Unsupported userShortcutType " + shortcutType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the width of the screen.
|
||||||
|
*
|
||||||
|
* @param context the current context.
|
||||||
|
* @return the width of the screen in terms of pixels.
|
||||||
|
*/
|
||||||
|
public static int getScreenWidthPixels(Context context) {
|
||||||
|
final Resources resources = context.getResources();
|
||||||
|
final int screenWidthDp = resources.getConfiguration().screenWidthDp;
|
||||||
|
|
||||||
|
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenWidthDp,
|
||||||
|
resources.getDisplayMetrics()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height of the screen.
|
||||||
|
*
|
||||||
|
* @param context the current context.
|
||||||
|
* @return the height of the screen in terms of pixels.
|
||||||
|
*/
|
||||||
|
public static int getScreenHeightPixels(Context context) {
|
||||||
|
final Resources resources = context.getResources();
|
||||||
|
final int screenHeightDp = resources.getConfiguration().screenHeightDp;
|
||||||
|
|
||||||
|
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp,
|
||||||
|
resources.getDisplayMetrics()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ import com.android.settings.R;
|
|||||||
public class AnimatedImagePreference extends Preference {
|
public class AnimatedImagePreference extends Preference {
|
||||||
|
|
||||||
private Uri mImageUri;
|
private Uri mImageUri;
|
||||||
|
private int mMaxHeight = -1;
|
||||||
|
|
||||||
AnimatedImagePreference(Context context) {
|
AnimatedImagePreference(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -45,20 +46,26 @@ public class AnimatedImagePreference extends Preference {
|
|||||||
super.onBindViewHolder(holder);
|
super.onBindViewHolder(holder);
|
||||||
|
|
||||||
final ImageView imageView = holder.itemView.findViewById(R.id.animated_img);
|
final ImageView imageView = holder.itemView.findViewById(R.id.animated_img);
|
||||||
if (imageView != null && mImageUri != null) {
|
if (imageView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImageUri != null) {
|
||||||
imageView.setImageURI(mImageUri);
|
imageView.setImageURI(mImageUri);
|
||||||
|
|
||||||
final Drawable drawable = imageView.getDrawable();
|
final Drawable drawable = imageView.getDrawable();
|
||||||
if (drawable != null) {
|
if (drawable instanceof AnimatedImageDrawable) {
|
||||||
if (drawable instanceof AnimatedImageDrawable) {
|
((AnimatedImageDrawable) drawable).start();
|
||||||
((AnimatedImageDrawable) drawable).start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mMaxHeight > -1) {
|
||||||
|
imageView.setMaxWidth(mMaxHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set image uri to display image in {@link ImageView}
|
* Sets image uri to display image in {@link ImageView}
|
||||||
*
|
*
|
||||||
* @param imageUri the Uri of an image
|
* @param imageUri the Uri of an image
|
||||||
*/
|
*/
|
||||||
@@ -68,4 +75,16 @@ public class AnimatedImagePreference extends Preference {
|
|||||||
notifyChanged();
|
notifyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum height of the view.
|
||||||
|
*
|
||||||
|
* @param maxHeight the maximum height of ImageView in terms of pixels.
|
||||||
|
*/
|
||||||
|
public void setMaxHeight(int maxHeight) {
|
||||||
|
if (maxHeight != mMaxHeight) {
|
||||||
|
mMaxHeight = maxHeight;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,9 +23,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom {@link android.widget.TextView} preference that shows html text with a custom tag
|
* A custom {@link android.widget.TextView} preference that shows html text with a custom tag
|
||||||
* filter.
|
* filter.
|
||||||
@@ -35,7 +32,6 @@ public final class HtmlTextPreference extends StaticTextPreference {
|
|||||||
private int mFlag = Html.FROM_HTML_MODE_COMPACT;
|
private int mFlag = Html.FROM_HTML_MODE_COMPACT;
|
||||||
private Html.ImageGetter mImageGetter;
|
private Html.ImageGetter mImageGetter;
|
||||||
private Html.TagHandler mTagHandler;
|
private Html.TagHandler mTagHandler;
|
||||||
private List<String> mUnsupportedTagList;
|
|
||||||
|
|
||||||
HtmlTextPreference(Context context) {
|
HtmlTextPreference(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -47,8 +43,8 @@ public final class HtmlTextPreference extends StaticTextPreference {
|
|||||||
|
|
||||||
final TextView summaryView = holder.itemView.findViewById(android.R.id.summary);
|
final TextView summaryView = holder.itemView.findViewById(android.R.id.summary);
|
||||||
if (summaryView != null && !TextUtils.isEmpty(getSummary())) {
|
if (summaryView != null && !TextUtils.isEmpty(getSummary())) {
|
||||||
final String filteredText = getFilteredText(getSummary().toString());
|
summaryView.setText(
|
||||||
summaryView.setText(Html.fromHtml(filteredText, mFlag, mImageGetter, mTagHandler));
|
Html.fromHtml(getSummary().toString(), mFlag, mImageGetter, mTagHandler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,39 +83,4 @@ public final class HtmlTextPreference extends StaticTextPreference {
|
|||||||
notifyChanged();
|
notifyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets unsupported tag list, the text will be filtered though this list in advanced.
|
|
||||||
*
|
|
||||||
* @param unsupportedTagList the list of unsupported tags
|
|
||||||
*/
|
|
||||||
public void setUnsupportedTagList(List<String> unsupportedTagList) {
|
|
||||||
if (unsupportedTagList != null && !unsupportedTagList.equals(mUnsupportedTagList)) {
|
|
||||||
mUnsupportedTagList = unsupportedTagList;
|
|
||||||
notifyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFilteredText(String text) {
|
|
||||||
if (mUnsupportedTagList == null) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
for (String tag : mUnsupportedTagList) {
|
|
||||||
if (!TextUtils.isEmpty(text)) {
|
|
||||||
final String index = String.valueOf(i++);
|
|
||||||
final String targetStart1 = "(?i)<" + tag + " ";
|
|
||||||
final String targetStart2 = "(?i)<" + tag + ">";
|
|
||||||
final String replacementStart1 = "<unsupportedtag" + index + " ";
|
|
||||||
final String replacementStart2 = "<unsupportedtag" + index + ">";
|
|
||||||
final String targetEnd = "(?i)</" + tag + ">";
|
|
||||||
final String replacementEnd = "</unsupportedtag" + index + ">";
|
|
||||||
text = Pattern.compile(targetStart1).matcher(text).replaceAll(replacementStart1);
|
|
||||||
text = Pattern.compile(targetStart2).matcher(text).replaceAll(replacementStart2);
|
|
||||||
text = Pattern.compile(targetEnd).matcher(text).replaceAll(replacementEnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.android.settings.accessibility.AccessibilityUtil.getScreenHeightPixels;
|
||||||
|
import static com.android.settings.accessibility.AccessibilityUtil.getScreenWidthPixels;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -80,7 +83,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
protected CharSequence mPackageName;
|
protected CharSequence mPackageName;
|
||||||
protected Uri mImageUri;
|
protected Uri mImageUri;
|
||||||
protected CharSequence mHtmlDescription;
|
protected CharSequence mHtmlDescription;
|
||||||
private static final String ANCHOR_TAG = "a";
|
|
||||||
private static final String DRAWABLE_FOLDER = "drawable";
|
private static final String DRAWABLE_FOLDER = "drawable";
|
||||||
protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service";
|
protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service";
|
||||||
protected static final String KEY_GENERAL_CATEGORY = "general_categories";
|
protected static final String KEY_GENERAL_CATEGORY = "general_categories";
|
||||||
@@ -94,9 +96,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
private CheckBox mSoftwareTypeCheckBox;
|
private CheckBox mSoftwareTypeCheckBox;
|
||||||
private CheckBox mHardwareTypeCheckBox;
|
private CheckBox mHardwareTypeCheckBox;
|
||||||
|
|
||||||
// For html description of accessibility service, third party developer must follow the rule,
|
// For html description of accessibility service, must follow the rule, such as
|
||||||
// such as <img src="R.drawable.fileName"/>, a11y settings will get third party resources
|
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
|
||||||
// by this.
|
|
||||||
private static final String IMG_PREFIX = "R.drawable.";
|
private static final String IMG_PREFIX = "R.drawable.";
|
||||||
|
|
||||||
private ImageView mImageGetterCacheView;
|
private ImageView mImageGetterCacheView;
|
||||||
@@ -147,10 +148,12 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
|
|
||||||
PreferenceScreen preferenceScreen = getPreferenceScreen();
|
PreferenceScreen preferenceScreen = getPreferenceScreen();
|
||||||
if (mImageUri != null) {
|
if (mImageUri != null) {
|
||||||
|
final int screenHalfHeight = getScreenHeightPixels(getPrefContext()) / /* half */ 2;
|
||||||
final AnimatedImagePreference animatedImagePreference = new AnimatedImagePreference(
|
final AnimatedImagePreference animatedImagePreference = new AnimatedImagePreference(
|
||||||
getPrefContext());
|
getPrefContext());
|
||||||
animatedImagePreference.setImageUri(mImageUri);
|
animatedImagePreference.setImageUri(mImageUri);
|
||||||
animatedImagePreference.setSelectable(false);
|
animatedImagePreference.setSelectable(false);
|
||||||
|
animatedImagePreference.setMaxHeight(screenHalfHeight);
|
||||||
preferenceScreen.addPreference(animatedImagePreference);
|
preferenceScreen.addPreference(animatedImagePreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,14 +198,9 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
introductionCategory.setTitle(title);
|
introductionCategory.setTitle(title);
|
||||||
preferenceScreen.addPreference(introductionCategory);
|
preferenceScreen.addPreference(introductionCategory);
|
||||||
|
|
||||||
// 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(getPrefContext());
|
final HtmlTextPreference htmlTextPreference = new HtmlTextPreference(getPrefContext());
|
||||||
htmlTextPreference.setSummary(mHtmlDescription);
|
htmlTextPreference.setSummary(mHtmlDescription);
|
||||||
htmlTextPreference.setImageGetter(mImageGetter);
|
htmlTextPreference.setImageGetter(mImageGetter);
|
||||||
htmlTextPreference.setUnsupportedTagList(unsupportedTagList);
|
|
||||||
htmlTextPreference.setSelectable(false);
|
htmlTextPreference.setSelectable(false);
|
||||||
introductionCategory.addPreference(htmlTextPreference);
|
introductionCategory.addPreference(htmlTextPreference);
|
||||||
}
|
}
|
||||||
@@ -383,14 +381,24 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
mImageGetterCacheView.setAdjustViewBounds(true);
|
mImageGetterCacheView.setAdjustViewBounds(true);
|
||||||
mImageGetterCacheView.setImageURI(imageUri);
|
mImageGetterCacheView.setImageURI(imageUri);
|
||||||
|
|
||||||
final Drawable drawable = mImageGetterCacheView.getDrawable().mutate();
|
if (mImageGetterCacheView.getDrawable() == null) {
|
||||||
if (drawable != null) {
|
return null;
|
||||||
drawable.setBounds(/* left= */0, /* top= */0, drawable.getIntrinsicWidth(),
|
|
||||||
drawable.getIntrinsicHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Drawable drawable =
|
||||||
|
mImageGetterCacheView.getDrawable().mutate().getConstantState().newDrawable();
|
||||||
mImageGetterCacheView.setImageURI(null);
|
mImageGetterCacheView.setImageURI(null);
|
||||||
mImageGetterCacheView.setImageDrawable(null);
|
final int imageWidth = drawable.getIntrinsicWidth();
|
||||||
|
final int imageHeight = drawable.getIntrinsicHeight();
|
||||||
|
final int screenHalfHeight = getScreenHeightPixels(getPrefContext()) / /* half */ 2;
|
||||||
|
if ((imageWidth > getScreenWidthPixels(getPrefContext()))
|
||||||
|
|| (imageHeight > screenHalfHeight)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawable.setBounds(/* left= */0, /* top= */0, drawable.getIntrinsicWidth(),
|
||||||
|
drawable.getIntrinsicHeight());
|
||||||
|
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,6 @@ import android.text.Editable;
|
|||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
@@ -36,9 +35,6 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.xml.sax.XMLReader;
|
import org.xml.sax.XMLReader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** Tests for {@link HtmlTextPreference} */
|
/** Tests for {@link HtmlTextPreference} */
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class HtmlTextPreferenceTest {
|
public final class HtmlTextPreferenceTest {
|
||||||
@@ -65,21 +61,13 @@ public final class HtmlTextPreferenceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnsupportedTagList_keepRealContentWithoutTag() {
|
public void testTagHandler() {
|
||||||
final List<String> testUnsupportedTagList = new ArrayList<>();
|
|
||||||
testUnsupportedTagList.add("testTag");
|
|
||||||
final String testStr = "<testTag>Real description</testTag>";
|
final String testStr = "<testTag>Real description</testTag>";
|
||||||
final String expectedStr = "Real description";
|
|
||||||
final String expectedTag = "unsupportedtag1";
|
|
||||||
|
|
||||||
mHtmlTextPreference.setUnsupportedTagList(testUnsupportedTagList);
|
|
||||||
mHtmlTextPreference.setSummary(testStr);
|
mHtmlTextPreference.setSummary(testStr);
|
||||||
mHtmlTextPreference.setTagHandler(mTagHandler);
|
mHtmlTextPreference.setTagHandler(mTagHandler);
|
||||||
mHtmlTextPreference.onBindViewHolder(mPreferenceViewHolder);
|
mHtmlTextPreference.onBindViewHolder(mPreferenceViewHolder);
|
||||||
|
|
||||||
final TextView summaryView = mPreferenceViewHolder.itemView.findViewById(
|
assertThat(mHandledTag).isEqualTo("testTag");
|
||||||
android.R.id.summary);
|
|
||||||
assertThat(summaryView.getText().toString()).isEqualTo(expectedStr);
|
|
||||||
assertThat(mHandledTag).isEqualTo(expectedTag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user