Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99f0e0ef authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Verify regex on ImageTransformation"

parents 544ae85c de78fabb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -37054,7 +37054,7 @@ package android.service.autofill {
  }
  public static class ImageTransformation.Builder {
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.lang.String, int);
    method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
    method public android.service.autofill.ImageTransformation build();
  }
+1 −1
Original line number Diff line number Diff line
@@ -40135,7 +40135,7 @@ package android.service.autofill {
  }
  public static class ImageTransformation.Builder {
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.lang.String, int);
    method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
    method public android.service.autofill.ImageTransformation build();
  }
+2 −1
Original line number Diff line number Diff line
@@ -37222,13 +37222,14 @@ package android.service.autofill {
  }
  public final class ImageTransformation implements android.os.Parcelable {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int);
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
  }
  public static class ImageTransformation.Builder {
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.lang.String, int);
    method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
    method public android.service.autofill.ImageTransformation build();
  }
+41 −39
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package android.service.autofill;

import static android.view.autofill.Helper.sDebug;

import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
@@ -29,6 +31,8 @@ import android.widget.RemoteViews;

import com.android.internal.util.Preconditions;

import java.util.regex.Pattern;

/**
 * Replaces the content of a child {@link ImageView} of a
 * {@link RemoteViews presentation template} with the first image that matches a regular expression
@@ -37,26 +41,20 @@ import com.android.internal.util.Preconditions;
 * <p>Typically used to display credit card logos. Example:
 *
 * <pre class="prettyprint">
 *   new ImageTransformation.Builder(ccNumberId)
 *     .addOption("^4815.*$", R.drawable.ic_credit_card_logo1)
 *   new ImageTransformation.Builder(ccNumberId, "^4815.*$", R.drawable.ic_credit_card_logo1)
 *     .addOption("^1623.*$", R.drawable.ic_credit_card_logo2)
 *     .addOption("^42.*$", R.drawable.ic_credit_card_logo3)
 *     .build();
 * </pre>
 *
 * <p>There is no imposed limit in the number of options, but keep in mind that regexs are
 * expensive to evaluate, so try to:
 * <ul>
 *   <li>Use the minimum number of regex per image.
 *   <li>Add the most common images first.
 * </ul>
 * expensive to evaluate, so use the minimum number of regexs.
 */
//TODO(b/62534917): add unit tests
public final class ImageTransformation extends InternalTransformation implements Parcelable {
    private static final String TAG = "ImageTransformation";

    private final AutofillId mId;
    private final ArrayMap<String, Integer> mOptions;
    private final ArrayMap<Pattern, Integer> mOptions;

    private ImageTransformation(Builder builder) {
        mId = builder.mId;
@@ -64,6 +62,7 @@ public final class ImageTransformation extends InternalTransformation implements
    }

    /** @hide */
    @TestApi
    @Override
    public void apply(@NonNull ValueFinder finder, @NonNull RemoteViews parentTemplate,
            int childViewId) {
@@ -79,8 +78,8 @@ public final class ImageTransformation extends InternalTransformation implements
        }

        for (int i = 0; i < size; i++) {
            final String regex = mOptions.keyAt(i);
            if (value.matches(regex)) {
            final Pattern regex = mOptions.keyAt(i);
            if (regex.matcher(value).matches()) {
                Log.d(TAG, "Found match at " + i + ": " + regex);
                parentTemplate.setImageViewResource(childViewId, mOptions.valueAt(i));
                return;
@@ -94,19 +93,22 @@ public final class ImageTransformation extends InternalTransformation implements
     */
    public static class Builder {
        private final AutofillId mId;
        private ArrayMap<String, Integer> mOptions;
        private final ArrayMap<Pattern, Integer> mOptions = new ArrayMap<>();
        private boolean mDestroyed;

        /**
         * Default constructor.
         * Create 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.
         */
        //TODO(b/62534917): add a regex/resid so we force it to have at least one
        // (and then remove the check for empty from build())
        public Builder(@NonNull AutofillId id) {
        public Builder(@NonNull AutofillId id, @NonNull String regex, @DrawableRes int resId) {
            mId = Preconditions.checkNotNull(id);

            addOption(regex, resId);
        }

        /**
@@ -118,13 +120,15 @@ public final class ImageTransformation extends InternalTransformation implements
         *
         * @return this build
         */
        public Builder addOption(String regex, int resId) {
            //TODO(b/62534917): throw exception if regex / resId are invalid
        public Builder addOption(@NonNull String regex, @DrawableRes int resId) {
            throwIfDestroyed();
            if (mOptions == null) {
                mOptions = new ArrayMap<>();
            }
            mOptions.put(regex, resId);

            Preconditions.checkArgument(resId != 0);

            // Check regex
            Pattern pattern = Pattern.compile(regex);

            mOptions.put(pattern, resId);
            return this;
        }

@@ -163,19 +167,15 @@ public final class ImageTransformation extends InternalTransformation implements
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeParcelable(mId, flags);
        if (mOptions == null) {
            parcel.writeStringArray(null);
            return;
        }

        final int size = mOptions.size();
        final String[] regexs = new String[size];
        final int[] resIds = new int[size];
        for (int i = 0; i < size; i++) {
            regexs[i] = mOptions.keyAt(i);
            regexs[i] = mOptions.keyAt(i).pattern();
            resIds[i] = mOptions.valueAt(i);
        }
        parcel.writeStringArray(regexs);
@@ -186,19 +186,21 @@ public final class ImageTransformation extends InternalTransformation implements
            new Parcelable.Creator<ImageTransformation>() {
        @Override
        public ImageTransformation createFromParcel(Parcel parcel) {
            // 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(parcel.readParcelable(null));
            final AutofillId id = parcel.readParcelable(null);

            final String[] regexs = parcel.createStringArray();
            if (regexs != null) {
            final int[] resIds = parcel.createIntArray();

            // 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 int size = regexs.length;
                for (int i = 0; i < size; i++) {
            for (int i = 1; i < size; i++) {
                builder.addOption(regexs[i], resIds[i]);
            }
            }

            return builder.build();
        }