Loading api/current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -37206,8 +37206,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); } api/system-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -40302,8 +40302,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); } api/test-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -37496,8 +37496,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); } core/java/android/service/autofill/ImageTransformation.java +95 −23 Original line number Diff line number Diff line Loading @@ -20,11 +20,12 @@ import static android.view.autofill.Helper.sDebug; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.autofill.AutofillId; import android.widget.ImageView; import android.widget.RemoteViews; Loading @@ -43,9 +44,9 @@ import java.util.regex.Pattern; * * <pre class="prettyprint"> * new ImageTransformation.Builder(ccNumberId, Pattern.compile("^4815.*$"), * R.drawable.ic_credit_card_logo1) * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2) * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3) * R.drawable.ic_credit_card_logo1, "Brand 1") * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2, "Brand 2") * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3, "Brand 3") * .build(); * </pre> * Loading @@ -59,7 +60,7 @@ public final class ImageTransformation extends InternalTransformation implements private static final String TAG = "ImageTransformation"; private final AutofillId mId; private final ArrayList<Pair<Pattern, Integer>> mOptions; private final ArrayList<Option> mOptions; private ImageTransformation(Builder builder) { mId = builder.mId; Loading @@ -82,17 +83,21 @@ public final class ImageTransformation extends InternalTransformation implements } for (int i = 0; i < size; i++) { final Pair<Pattern, Integer> option = mOptions.get(i); final Option option = mOptions.get(i); try { if (option.first.matcher(value).matches()) { if (option.pattern.matcher(value).matches()) { Log.d(TAG, "Found match at " + i + ": " + option); parentTemplate.setImageViewResource(childViewId, option.second); parentTemplate.setImageViewResource(childViewId, option.resId); if (option.contentDescription != null) { parentTemplate.setContentDescription(childViewId, option.contentDescription); } return; } } catch (Exception e) { // Do not log full exception to avoid PII leaking Log.w(TAG, "Error matching regex #" + i + "(" + option.first.pattern() + ") on id " + option.second + ": " + e.getClass()); Log.w(TAG, "Error matching regex #" + i + "(" + option.pattern + ") on id " + option.resId + ": " + e.getClass()); throw e; } Loading @@ -105,24 +110,43 @@ public final class ImageTransformation extends InternalTransformation implements */ public static class Builder { private final AutofillId mId; private final ArrayList<Pair<Pattern, Integer>> mOptions = new ArrayList<>(); private final ArrayList<Option> mOptions = new ArrayList<>(); private boolean mDestroyed; /** * Create a new builder for a autofill id and add a first option. * Creates a new builder for a autofill id and add a first option. * * @param id id of the screen field that will be used to evaluate whether the image should * be used. * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * * @deprecated use * {@link #ImageTransformation.Builder(AutofillId, Pattern, int, CharSequence)} instead. */ @Deprecated public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId) { mId = Preconditions.checkNotNull(id); addOption(regex, resId); } /** * Creates a new builder for a autofill id and add a first option. * * @param id id of the screen field that will be used to evaluate whether the image should * be used. * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * @param contentDescription content description to be applied in the child view. */ public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId, @NonNull CharSequence contentDescription) { mId = Preconditions.checkNotNull(id); addOption(regex, resId, contentDescription); } /** * Adds an option to replace the child view with a different image when the regex matches. * Loading @@ -131,17 +155,43 @@ public final class ImageTransformation extends InternalTransformation implements * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * * @return this build * * @deprecated use {@link #addOption(Pattern, int, CharSequence)} instead. */ @Deprecated public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId) { addOptionInternal(regex, resId, null); return this; } /** * Adds an option to replace the child view with a different image and content description * when the regex matches. * * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * @param contentDescription content description to be applied in the child view. * * @return this build */ public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId, @NonNull CharSequence contentDescription) { addOptionInternal(regex, resId, Preconditions.checkNotNull(contentDescription)); return this; } private void addOptionInternal(@NonNull Pattern regex, @DrawableRes int resId, @Nullable CharSequence contentDescription) { throwIfDestroyed(); Preconditions.checkNotNull(regex); Preconditions.checkArgument(resId != 0); mOptions.add(new Pair<>(regex, resId)); return this; mOptions.add(new Option(regex, resId, contentDescription)); } /** * Creates a new {@link ImageTransformation} instance. */ Loading Loading @@ -178,15 +228,18 @@ public final class ImageTransformation extends InternalTransformation implements parcel.writeParcelable(mId, flags); final int size = mOptions.size(); final Pattern[] regexs = new Pattern[size]; final Pattern[] patterns = new Pattern[size]; final int[] resIds = new int[size]; final CharSequence[] contentDescriptions = new String[size]; for (int i = 0; i < size; i++) { Pair<Pattern, Integer> regex = mOptions.get(i); regexs[i] = regex.first; resIds[i] = regex.second; final Option option = mOptions.get(i); patterns[i] = option.pattern; resIds[i] = option.resId; contentDescriptions[i] = option.contentDescription; } parcel.writeSerializable(regexs); parcel.writeSerializable(patterns); parcel.writeIntArray(resIds); parcel.writeCharSequenceArray(contentDescriptions); } public static final Parcelable.Creator<ImageTransformation> CREATOR = Loading @@ -197,16 +250,23 @@ public final class ImageTransformation extends InternalTransformation implements final Pattern[] regexs = (Pattern[]) parcel.readSerializable(); final int[] resIds = parcel.createIntArray(); final CharSequence[] contentDescriptions = parcel.readCharSequenceArray(); // Always go through the builder to ensure the data ingested by the system obeys the // contract of the builder to avoid attacks using specially crafted parcels. final ImageTransformation.Builder builder = new ImageTransformation.Builder(id, regexs[0], resIds[0]); final CharSequence contentDescription = contentDescriptions[0]; final ImageTransformation.Builder builder = (contentDescription != null) ? new ImageTransformation.Builder(id, regexs[0], resIds[0], contentDescription) : new ImageTransformation.Builder(id, regexs[0], resIds[0]); final int size = regexs.length; for (int i = 1; i < size; i++) { if (contentDescriptions[i] != null) { builder.addOption(regexs[i], resIds[i], contentDescriptions[i]); } else { builder.addOption(regexs[i], resIds[i]); } } return builder.build(); } Loading @@ -216,4 +276,16 @@ public final class ImageTransformation extends InternalTransformation implements return new ImageTransformation[size]; } }; private static final class Option { public final Pattern pattern; public final int resId; public final CharSequence contentDescription; Option(Pattern pattern, int resId, CharSequence contentDescription) { this.pattern = pattern; this.resId = resId; this.contentDescription = TextUtils.trimNoCopySpans(contentDescription); } } } Loading
api/current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -37206,8 +37206,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); }
api/system-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -40302,8 +40302,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); }
api/test-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -37496,8 +37496,10 @@ package android.service.autofill { } public static class ImageTransformation.Builder { ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int); ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence); method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int); method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence); method public android.service.autofill.ImageTransformation build(); }
core/java/android/service/autofill/ImageTransformation.java +95 −23 Original line number Diff line number Diff line Loading @@ -20,11 +20,12 @@ import static android.view.autofill.Helper.sDebug; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.autofill.AutofillId; import android.widget.ImageView; import android.widget.RemoteViews; Loading @@ -43,9 +44,9 @@ import java.util.regex.Pattern; * * <pre class="prettyprint"> * new ImageTransformation.Builder(ccNumberId, Pattern.compile("^4815.*$"), * R.drawable.ic_credit_card_logo1) * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2) * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3) * R.drawable.ic_credit_card_logo1, "Brand 1") * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2, "Brand 2") * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3, "Brand 3") * .build(); * </pre> * Loading @@ -59,7 +60,7 @@ public final class ImageTransformation extends InternalTransformation implements private static final String TAG = "ImageTransformation"; private final AutofillId mId; private final ArrayList<Pair<Pattern, Integer>> mOptions; private final ArrayList<Option> mOptions; private ImageTransformation(Builder builder) { mId = builder.mId; Loading @@ -82,17 +83,21 @@ public final class ImageTransformation extends InternalTransformation implements } for (int i = 0; i < size; i++) { final Pair<Pattern, Integer> option = mOptions.get(i); final Option option = mOptions.get(i); try { if (option.first.matcher(value).matches()) { if (option.pattern.matcher(value).matches()) { Log.d(TAG, "Found match at " + i + ": " + option); parentTemplate.setImageViewResource(childViewId, option.second); parentTemplate.setImageViewResource(childViewId, option.resId); if (option.contentDescription != null) { parentTemplate.setContentDescription(childViewId, option.contentDescription); } return; } } catch (Exception e) { // Do not log full exception to avoid PII leaking Log.w(TAG, "Error matching regex #" + i + "(" + option.first.pattern() + ") on id " + option.second + ": " + e.getClass()); Log.w(TAG, "Error matching regex #" + i + "(" + option.pattern + ") on id " + option.resId + ": " + e.getClass()); throw e; } Loading @@ -105,24 +110,43 @@ public final class ImageTransformation extends InternalTransformation implements */ public static class Builder { private final AutofillId mId; private final ArrayList<Pair<Pattern, Integer>> mOptions = new ArrayList<>(); private final ArrayList<Option> mOptions = new ArrayList<>(); private boolean mDestroyed; /** * Create a new builder for a autofill id and add a first option. * Creates a new builder for a autofill id and add a first option. * * @param id id of the screen field that will be used to evaluate whether the image should * be used. * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * * @deprecated use * {@link #ImageTransformation.Builder(AutofillId, Pattern, int, CharSequence)} instead. */ @Deprecated public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId) { mId = Preconditions.checkNotNull(id); addOption(regex, resId); } /** * Creates a new builder for a autofill id and add a first option. * * @param id id of the screen field that will be used to evaluate whether the image should * be used. * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * @param contentDescription content description to be applied in the child view. */ public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId, @NonNull CharSequence contentDescription) { mId = Preconditions.checkNotNull(id); addOption(regex, resId, contentDescription); } /** * Adds an option to replace the child view with a different image when the regex matches. * Loading @@ -131,17 +155,43 @@ public final class ImageTransformation extends InternalTransformation implements * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * * @return this build * * @deprecated use {@link #addOption(Pattern, int, CharSequence)} instead. */ @Deprecated public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId) { addOptionInternal(regex, resId, null); return this; } /** * Adds an option to replace the child view with a different image and content description * when the regex matches. * * @param regex regular expression defining what should be matched to use this image. * @param resId resource id of the image (in the autofill service's package). The * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. * @param contentDescription content description to be applied in the child view. * * @return this build */ public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId, @NonNull CharSequence contentDescription) { addOptionInternal(regex, resId, Preconditions.checkNotNull(contentDescription)); return this; } private void addOptionInternal(@NonNull Pattern regex, @DrawableRes int resId, @Nullable CharSequence contentDescription) { throwIfDestroyed(); Preconditions.checkNotNull(regex); Preconditions.checkArgument(resId != 0); mOptions.add(new Pair<>(regex, resId)); return this; mOptions.add(new Option(regex, resId, contentDescription)); } /** * Creates a new {@link ImageTransformation} instance. */ Loading Loading @@ -178,15 +228,18 @@ public final class ImageTransformation extends InternalTransformation implements parcel.writeParcelable(mId, flags); final int size = mOptions.size(); final Pattern[] regexs = new Pattern[size]; final Pattern[] patterns = new Pattern[size]; final int[] resIds = new int[size]; final CharSequence[] contentDescriptions = new String[size]; for (int i = 0; i < size; i++) { Pair<Pattern, Integer> regex = mOptions.get(i); regexs[i] = regex.first; resIds[i] = regex.second; final Option option = mOptions.get(i); patterns[i] = option.pattern; resIds[i] = option.resId; contentDescriptions[i] = option.contentDescription; } parcel.writeSerializable(regexs); parcel.writeSerializable(patterns); parcel.writeIntArray(resIds); parcel.writeCharSequenceArray(contentDescriptions); } public static final Parcelable.Creator<ImageTransformation> CREATOR = Loading @@ -197,16 +250,23 @@ public final class ImageTransformation extends InternalTransformation implements final Pattern[] regexs = (Pattern[]) parcel.readSerializable(); final int[] resIds = parcel.createIntArray(); final CharSequence[] contentDescriptions = parcel.readCharSequenceArray(); // Always go through the builder to ensure the data ingested by the system obeys the // contract of the builder to avoid attacks using specially crafted parcels. final ImageTransformation.Builder builder = new ImageTransformation.Builder(id, regexs[0], resIds[0]); final CharSequence contentDescription = contentDescriptions[0]; final ImageTransformation.Builder builder = (contentDescription != null) ? new ImageTransformation.Builder(id, regexs[0], resIds[0], contentDescription) : new ImageTransformation.Builder(id, regexs[0], resIds[0]); final int size = regexs.length; for (int i = 1; i < size; i++) { if (contentDescriptions[i] != null) { builder.addOption(regexs[i], resIds[i], contentDescriptions[i]); } else { builder.addOption(regexs[i], resIds[i]); } } return builder.build(); } Loading @@ -216,4 +276,16 @@ public final class ImageTransformation extends InternalTransformation implements return new ImageTransformation[size]; } }; private static final class Option { public final Pattern pattern; public final int resId; public final CharSequence contentDescription; Option(Pattern pattern, int resId, CharSequence contentDescription) { this.pattern = pattern; this.resId = resId; this.contentDescription = TextUtils.trimNoCopySpans(contentDescription); } } }