OSDN Git Service

Verify regex on ImageTransformation
authorPhilip P. Moltmann <moltmann@google.com>
Mon, 10 Jul 2017 23:34:05 +0000 (16:34 -0700)
committerPhilip P. Moltmann <moltmann@google.com>
Mon, 10 Jul 2017 23:54:52 +0000 (16:54 -0700)
Also change the constructor of the Builder of this class

Bug: 62534917
Test: cts-tradefed run cts-dev -m CtsAutoFillServiceTestCases
Change-Id: Ie54f3a1d4b3a0ecd25945d3deafb4858423f926e

api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/service/autofill/ImageTransformation.java
core/java/android/service/autofill/ValueFinder.java
core/java/android/view/autofill/AutofillId.java

index 0d422c5..71724de 100644 (file)
@@ -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();
   }
index 4cae69c..e6c7555 100644 (file)
@@ -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();
   }
index 5d2c557..0d2e0bb 100644 (file)
@@ -37221,13 +37221,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();
   }
@@ -37296,6 +37297,10 @@ package android.service.autofill {
     method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
   }
 
+  public abstract interface ValueFinder {
+    method public abstract java.lang.String findByAutofillId(android.view.autofill.AutofillId);
+  }
+
 }
 
 package android.service.carrier {
@@ -48263,6 +48268,7 @@ package android.view.animation {
 package android.view.autofill {
 
   public final class AutofillId implements android.os.Parcelable {
+    ctor public AutofillId(int);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.autofill.AutofillId> CREATOR;
index 9f6eedc..67efe13 100644 (file)
@@ -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();
-                final int size = regexs.length;
-                for (int i = 0; i < size; i++) {
-                    builder.addOption(regexs[i], resIds[i]);
-                }
+            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 = 1; i < size; i++) {
+                builder.addOption(regexs[i], resIds[i]);
             }
+
             return builder.build();
         }
 
index d02a358..1705b7d 100644 (file)
@@ -17,6 +17,7 @@ package android.service.autofill;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.view.autofill.AutofillId;
 
 /**
@@ -24,6 +25,7 @@ import android.view.autofill.AutofillId;
  *
  * @hide
  */
+@TestApi
 public interface ValueFinder {
 
     /**
index 1cee529..5ce2421 100644 (file)
@@ -15,6 +15,7 @@
  */
 package android.view.autofill;
 
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.View;
@@ -29,6 +30,7 @@ public final class AutofillId implements Parcelable {
     private final int mVirtualId;
 
     /** @hide */
+    @TestApi
     public AutofillId(int id) {
         mVirtual = false;
         mViewId = id;