OSDN Git Service

Optimize Autofill Sanitizer to work as a Validator.
authorFelipe Leme <felipeal@google.com>
Fri, 17 Nov 2017 21:54:55 +0000 (13:54 -0800)
committerFelipe Leme <felipeal@google.com>
Sat, 18 Nov 2017 19:28:14 +0000 (11:28 -0800)
Test: cts-tradefed run commandAndExit cts-dev -m CtsAutoFillServiceTestCases

Fixes: 69465320

Change-Id: I0eec8c6373ae3129314eda3f1f531592b85a4118

core/java/android/service/autofill/InternalSanitizer.java
core/java/android/service/autofill/SaveInfo.java
core/java/android/service/autofill/TextValueSanitizer.java
services/autofill/java/com/android/server/autofill/Session.java
services/autofill/java/com/android/server/autofill/ViewState.java

index 95d2f66..d77e41e 100644 (file)
@@ -16,6 +16,7 @@
 package android.service.autofill;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcelable;
 import android.view.autofill.AutofillValue;
@@ -32,7 +33,11 @@ public abstract class InternalSanitizer implements Sanitizer, Parcelable {
     /**
      * Sanitizes an {@link AutofillValue}.
      *
+     * @return sanitized value or {@code null} if value could not be sanitized (for example: didn't
+     * match regex, it's an invalid type, regex failed, etc).
+     *
      * @hide
      */
+    @Nullable
     public abstract AutofillValue sanitize(@NonNull AutofillValue value);
 }
index 9a1dcbb..bc4b3fc 100644 (file)
@@ -613,6 +613,11 @@ public final class SaveInfo implements Parcelable {
          *         usernameId, passwordId);
          * </pre>
          *
+         * <p>The sanitizer can also be used as an alternative for a
+         * {@link #setValidator(Validator) validator}&mdashif any of the {@code ids} is a
+         * {@link #SaveInfo.Builder(int, AutofillId[]) required id} and the {@code sanitizer} fail
+         * for it, then the save UI is not shown.
+         *
          * @param sanitizer an implementation provided by the Android System.
          * @param ids id of fields whose value will be sanitized.
          * @return this builder.
index 12e85b1..a3a98d8 100644 (file)
@@ -19,6 +19,7 @@ package android.service.autofill;
 import static android.view.autofill.Helper.sDebug;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -62,24 +63,31 @@ public final class TextValueSanitizer extends InternalSanitizer implements
     /** @hide */
     @Override
     @TestApi
+    @Nullable
     public AutofillValue sanitize(@NonNull AutofillValue value) {
         if (value == null) {
             Slog.w(TAG, "sanitize() called with null value");
             return null;
         }
-        if (!value.isText()) return value;
+        if (!value.isText()) {
+            if (sDebug) Slog.d(TAG, "sanitize() called with non-text value: " + value);
+            return null;
+        }
 
         final CharSequence text = value.getTextValue();
 
         try {
             final Matcher matcher = mRegex.matcher(text);
-            if (!matcher.matches()) return value;
+            if (!matcher.matches()) {
+                if (sDebug) Slog.d(TAG, "sanitize(): " + mRegex + " failed for " + value);
+                return null;
+            }
 
             final CharSequence sanitized = matcher.replaceAll(mSubst);
             return AutofillValue.forText(sanitized);
         } catch (Exception e) {
             Slog.w(TAG, "Exception evaluating " + mRegex + "/" + mSubst + ": " + e);
-            return value;
+            return null;
         }
     }
 
index af4668a..9741486 100644 (file)
@@ -1167,7 +1167,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                         break;
                     }
                 }
+
                 value = getSanitizedValue(sanitizers, id, value);
+                if (value == null) {
+                    if (sDebug) {
+                        Slog.d(TAG, "value of required field " + id + " failed sanitization");
+                    }
+                    allRequiredAreNotEmpty = false;
+                    break;
+                }
+                viewState.setSanitizedValue(value);
                 currentValues.put(id, value);
                 final AutofillValue filledValue = viewState.getAutofilledValue();
 
@@ -1337,7 +1346,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
         return sanitizers;
     }
 
-    @NonNull
+    @Nullable
     private AutofillValue getSanitizedValue(
             @Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
             @NonNull AutofillId id,
@@ -1431,10 +1440,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
             if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + context);
 
             for (int viewStateNum = 0; viewStateNum < mViewStates.size(); viewStateNum++) {
-                final ViewState state = mViewStates.valueAt(viewStateNum);
+                final ViewState viewState = mViewStates.valueAt(viewStateNum);
 
-                final AutofillId id = state.id;
-                final AutofillValue value = state.getCurrentValue();
+                final AutofillId id = viewState.id;
+                final AutofillValue value = viewState.getCurrentValue();
                 if (value == null) {
                     if (sVerbose) Slog.v(TAG, "callSaveLocked(): skipping " + id);
                     continue;
@@ -1446,9 +1455,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                 }
                 if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + id + " to " + value);
 
-                final AutofillValue sanitizedValue = getSanitizedValue(sanitizers, id, value);
+                AutofillValue sanitizedValue = viewState.getSanitizedValue();
 
-                node.updateAutofillValue(sanitizedValue);
+                if (sanitizedValue == null) {
+                    // Field is optional and haven't been sanitized yet.
+                    sanitizedValue = getSanitizedValue(sanitizers, id, value);
+                }
+                if (sanitizedValue != null) {
+                    node.updateAutofillValue(sanitizedValue);
+                } else if (sDebug) {
+                    Slog.d(TAG, "Not updating field " + id + " because it failed sanitization");
+                }
             }
 
             // Sanitize structure before it's sent to service.
index 832a66b..0dbdc13 100644 (file)
@@ -76,6 +76,7 @@ final class ViewState {
     private FillResponse mResponse;
     private AutofillValue mCurrentValue;
     private AutofillValue mAutofilledValue;
+    private AutofillValue mSanitizedValue;
     private Rect mVirtualBounds;
     private int mState;
     private String mDatasetId;
@@ -117,6 +118,15 @@ final class ViewState {
     }
 
     @Nullable
+    AutofillValue getSanitizedValue() {
+        return mSanitizedValue;
+    }
+
+    void setSanitizedValue(@Nullable AutofillValue value) {
+        mSanitizedValue = value;
+    }
+
+    @Nullable
     FillResponse getResponse() {
         return mResponse;
     }
@@ -218,6 +228,7 @@ final class ViewState {
         }
         pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
         pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
+        pw.print(prefix); pw.print("sanitizedValue:" ); pw.println(mSanitizedValue);
         pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
     }
 }
\ No newline at end of file