diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 3b0667d1e377d..316a018ef214f 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -22,6 +22,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
@@ -61,6 +62,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.regex.Pattern;
/**
* This class describes an {@link AccessibilityService}. The system notifies an
@@ -552,6 +554,13 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
private int mHtmlDescriptionRes;
+ // Used for html description of accessibility service. The
src tag must follow the
+ // prefix rule. e.g.
+ private static final String IMG_PREFIX = "R.drawable.";
+ private static final String ANCHOR_TAG = "a";
+ private static final List UNSUPPORTED_TAG_LIST = new ArrayList<>(
+ Collections.singletonList(ANCHOR_TAG));
+
/**
* Creates a new instance.
*/
@@ -782,12 +791,10 @@ public class AccessibilityServiceInfo implements Parcelable {
}
/**
- * The animated image resource id.
- *
- * Statically set from
- * {@link AccessibilityService#SERVICE_META_DATA meta-data}.
- *
+ * Gets the animated image resource id.
+ *
* @return The animated image resource id.
+ *
* @hide
*/
public int getAnimatedImageRes() {
@@ -797,10 +804,12 @@ public class AccessibilityServiceInfo implements Parcelable {
/**
* The animated image drawable.
*
+ * Image can not exceed the screen size.
* Statically set from
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.
*
- * @return The animated image drawable.
+ * @return The animated image drawable, or null if the resource is invalid or the image
+ * exceed the screen size.
*/
@Nullable
public Drawable loadAnimatedImage(@NonNull Context context) {
@@ -808,11 +817,8 @@ public class AccessibilityServiceInfo implements Parcelable {
return null;
}
- final PackageManager packageManager = context.getPackageManager();
- final String packageName = mComponentName.getPackageName();
- final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo;
-
- return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+ return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo,
+ mAnimatedImageRes);
}
/**
@@ -924,16 +930,17 @@ public class AccessibilityServiceInfo implements Parcelable {
}
/**
- * The localized html description of the accessibility service.
+ * The localized and restricted html description of the accessibility service.
*
+ * Filters the
tag which do not meet the custom specification and the tag.
* Statically set from
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.
*
- * @return The localized html description.
+ * @return The localized and restricted html description.
*/
@Nullable
public String loadHtmlDescription(@NonNull PackageManager packageManager) {
- if (mHtmlDescriptionRes == 0) {
+ if (mHtmlDescriptionRes == /* invalid */ 0) {
return null;
}
@@ -941,7 +948,7 @@ public class AccessibilityServiceInfo implements Parcelable {
final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName,
mHtmlDescriptionRes, serviceInfo.applicationInfo);
if (htmlDescription != null) {
- return htmlDescription.toString().trim();
+ return getFilteredHtmlText(htmlDescription.toString().trim());
}
return null;
}
@@ -1414,4 +1421,103 @@ public class AccessibilityServiceInfo implements Parcelable {
return new AccessibilityServiceInfo[size];
}
};
+
+ /**
+ * Gets the filtered html string for
+ * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+ * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It filters
+ * the
tag which do not meet the custom specification and the tag.
+ *
+ * @param text the target text is html format.
+ * @return the filtered html string.
+ *
+ * @hide
+ */
+ public static @NonNull String getFilteredHtmlText(@NonNull String text) {
+ final String replacementStart = ")";
+ final String regexEnd = "(?i)" + tag + "\\s*>";
+ text = Pattern.compile(regexStart).matcher(text).replaceAll(replacementStart);
+ text = Pattern.compile(regexEnd).matcher(text).replaceAll(replacementEnd);
+ }
+
+ final String regexInvalidImgTag = "(?i)
getScreenWidthPixels(context);
+ final boolean isImageHeightOverScreenLength =
+ bannerDrawable.getIntrinsicHeight() > getScreenHeightPixels(context);
+
+ return (isImageWidthOverScreenLength || isImageHeightOverScreenLength)
+ ? null
+ : bannerDrawable;
+ }
+
+ /**
+ * Gets the width of the screen.
+ *
+ * @param context the current context.
+ * @return the width of the screen in term of pixels.
+ *
+ * @hide
+ */
+ private static int getScreenWidthPixels(@NonNull 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 term of pixels.
+ *
+ * @hide
+ */
+ private static int getScreenHeightPixels(@NonNull 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()));
+ }
}
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 62096792d764d..a812f29a8bc72 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -18,6 +18,7 @@ package android.accessibilityservice;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,13 +29,19 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
/**
* Activities of interest to users with accessibility needs may request to be targets of the
@@ -87,6 +94,13 @@ public final class AccessibilityShortcutInfo {
*/
private final int mHtmlDescriptionRes;
+ // Used for html description of accessibility service. The
src tag must follow the
+ // prefix rule. e.g.
+ private static final String IMG_PREFIX = "R.drawable.";
+ private static final String ANCHOR_TAG = "a";
+ private static final List UNSUPPORTED_TAG_LIST = new ArrayList<>(
+ Collections.singletonList(ANCHOR_TAG));
+
/**
* Creates a new instance.
*
@@ -134,7 +148,7 @@ public final class AccessibilityShortcutInfo {
// Gets animated image
mAnimatedImageRes = asAttributes.getResourceId(
com.android.internal.R.styleable
- .AccessibilityShortcutTarget_animatedImageDrawable, 0);
+ .AccessibilityShortcutTarget_animatedImageDrawable, /* defValue= */ 0);
// Gets html description
mHtmlDescriptionRes = asAttributes.getResourceId(
com.android.internal.R.styleable.AccessibilityShortcutTarget_htmlDescription,
@@ -192,7 +206,7 @@ public final class AccessibilityShortcutInfo {
}
/**
- * The animated image resource id of the accessibility shortcut target.
+ * Gets the animated image resource id.
*
* @return The animated image resource id.
*
@@ -205,7 +219,8 @@ public final class AccessibilityShortcutInfo {
/**
* The animated image drawable of the accessibility shortcut target.
*
- * @return The animated image drawable.
+ * @return The animated image drawable, or null if the resource is invalid or the image
+ * exceed the screen size.
*/
@Nullable
public Drawable loadAnimatedImage(@NonNull Context context) {
@@ -213,21 +228,20 @@ public final class AccessibilityShortcutInfo {
return null;
}
- final PackageManager packageManager = context.getPackageManager();
- final String packageName = mComponentName.getPackageName();
- final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo;
-
- return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+ return loadSafeAnimatedImage(context, mActivityInfo.applicationInfo, mAnimatedImageRes);
}
/**
- * The localized html description of the accessibility shortcut target.
+ * The localized and restricted html description of the accessibility shortcut target.
+ * It filters the
tag which do not meet the custom specification and the tag.
*
- * @return The localized html description.
+ * @return The localized and restricted html description.
*/
@Nullable
public String loadHtmlDescription(@NonNull PackageManager packageManager) {
- return loadResourceString(packageManager, mActivityInfo, mHtmlDescriptionRes);
+ final String htmlDescription = loadResourceString(packageManager, mActivityInfo,
+ mHtmlDescriptionRes);
+ return TextUtils.isEmpty(htmlDescription) ? null : getFilteredHtmlText(htmlDescription);
}
/**
@@ -291,4 +305,103 @@ public final class AccessibilityShortcutInfo {
stringBuilder.append("]");
return stringBuilder.toString();
}
+
+ /**
+ * Gets the filtered html string for
+ * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+ * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It filters
+ * the
tag which do not meet the custom specification and the tag.
+ *
+ * @param text the target text is html format.
+ * @return the filtered html string.
+ *
+ * @hide
+ */
+ public static @NonNull String getFilteredHtmlText(@NonNull String text) {
+ final String replacementStart = ")";
+ final String regexEnd = "(?i)" + tag + "\\s*>";
+ text = Pattern.compile(regexStart).matcher(text).replaceAll(replacementStart);
+ text = Pattern.compile(regexEnd).matcher(text).replaceAll(replacementEnd);
+ }
+
+ final String regexInvalidImgTag = "(?i)
getScreenWidthPixels(context);
+ final boolean isImageHeightOverScreenLength =
+ bannerDrawable.getIntrinsicHeight() > getScreenHeightPixels(context);
+
+ return (isImageWidthOverScreenLength || isImageHeightOverScreenLength)
+ ? null
+ : bannerDrawable;
+ }
+
+ /**
+ * Gets the width of the screen.
+ *
+ * @param context the current context.
+ * @return the width of the screen in term of pixels.
+ *
+ * @hide
+ */
+ private static int getScreenWidthPixels(@NonNull 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 term of pixels.
+ *
+ * @hide
+ */
+ private static int getScreenHeightPixels(@NonNull 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()));
+ }
}