Merge "Optimize Autofill Sanitizer to work as a Validator."
diff --git a/core/java/android/service/autofill/InternalSanitizer.java b/core/java/android/service/autofill/InternalSanitizer.java
index 95d2f66..d77e41e 100644
--- a/core/java/android/service/autofill/InternalSanitizer.java
+++ b/core/java/android/service/autofill/InternalSanitizer.java
@@ -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 @@
/**
* 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);
}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 9a1dcbb..bc4b3fc 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -613,6 +613,11 @@
* 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.
diff --git a/core/java/android/service/autofill/TextValueSanitizer.java b/core/java/android/service/autofill/TextValueSanitizer.java
index 12e85b1..a3a98d8 100644
--- a/core/java/android/service/autofill/TextValueSanitizer.java
+++ b/core/java/android/service/autofill/TextValueSanitizer.java
@@ -19,6 +19,7 @@
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 @@
/** @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;
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index af4668a..9741486 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1167,7 +1167,16 @@
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 @@
return sanitizers;
}
- @NonNull
+ @Nullable
private AutofillValue getSanitizedValue(
@Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
@NonNull AutofillId id,
@@ -1431,10 +1440,10 @@
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 @@
}
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.
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 832a66b..0dbdc13 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -76,6 +76,7 @@
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 @@
}
@Nullable
+ AutofillValue getSanitizedValue() {
+ return mSanitizedValue;
+ }
+
+ void setSanitizedValue(@Nullable AutofillValue value) {
+ mSanitizedValue = value;
+ }
+
+ @Nullable
FillResponse getResponse() {
return mResponse;
}
@@ -218,6 +228,7 @@
}
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