diff options
| -rw-r--r-- | api/current.txt | 43 | ||||
| -rw-r--r-- | api/system-current.txt | 5 | ||||
| -rw-r--r-- | api/test-current.txt | 52 | ||||
| -rw-r--r-- | core/java/android/provider/Settings.java | 23 | ||||
| -rw-r--r-- | core/java/android/service/autofill/AutofillService.java | 43 | ||||
| -rw-r--r-- | core/java/android/service/autofill/EditDistanceScorer.java | 12 | ||||
| -rw-r--r-- | core/java/android/service/autofill/FieldClassification.java | 89 | ||||
| -rw-r--r-- | core/java/android/service/autofill/FillEventHistory.java | 26 | ||||
| -rw-r--r-- | core/java/android/service/autofill/FillResponse.java | 24 | ||||
| -rw-r--r-- | core/java/android/service/autofill/Scorer.java | 15 | ||||
| -rw-r--r-- | core/java/android/service/autofill/UserData.java | 24 | ||||
| -rw-r--r-- | core/java/android/view/autofill/AutofillManager.java | 39 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/provider/SettingsBackupTest.java | 12 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/Session.java | 3 |
14 files changed, 190 insertions, 220 deletions
diff --git a/api/current.txt b/api/current.txt index 6e4f63bdcde2..1bc38d402cbc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37622,6 +37622,25 @@ package android.service.autofill { method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews); } + public final class EditDistanceScorer implements android.os.Parcelable android.service.autofill.Scorer { + method public int describeContents(); + method public static android.service.autofill.EditDistanceScorer getInstance(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.EditDistanceScorer> CREATOR; + } + + public final class FieldClassification implements android.os.Parcelable { + method public int describeContents(); + method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification> CREATOR; + } + + public static final class FieldClassification.Match { + method public java.lang.String getRemoteId(); + method public float getScore(); + } + public final class FillCallback { method public void onFailure(java.lang.CharSequence); method public void onSuccess(android.service.autofill.FillResponse); @@ -37647,6 +37666,7 @@ package android.service.autofill { method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields(); method public android.os.Bundle getClientState(); method public java.lang.String getDatasetId(); + method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification(); method public java.util.Set<java.lang.String> getIgnoredDatasetIds(); method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField(); method public java.util.Set<java.lang.String> getSelectedDatasetIds(); @@ -37684,6 +37704,7 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder disableAutofill(long); method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle); + method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(android.view.autofill.AutofillId...); method public android.service.autofill.FillResponse.Builder setFlags(int); method public android.service.autofill.FillResponse.Builder setFooter(android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setHeader(android.widget.RemoteViews); @@ -37767,6 +37788,9 @@ package android.service.autofill { field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR; } + public abstract interface Scorer { + } + public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer { ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String); method public int describeContents(); @@ -37777,6 +37801,22 @@ package android.service.autofill { public abstract interface Transformation { } + public final class UserData implements android.os.Parcelable { + method public int describeContents(); + method public static int getMaxFieldClassificationIdsSize(); + method public static int getMaxUserDataSize(); + method public static int getMaxValueLength(); + method public static int getMinValueLength(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.UserData> CREATOR; + } + + public static final class UserData.Builder { + ctor public UserData.Builder(android.service.autofill.Scorer, java.lang.String, java.lang.String); + method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String); + method public android.service.autofill.UserData build(); + } + public abstract interface Validator { } @@ -48586,9 +48626,11 @@ package android.view.autofill { method public void cancel(); method public void commit(); method public void disableAutofillServices(); + method public android.service.autofill.UserData getUserData(); method public boolean hasEnabledAutofillServices(); method public boolean isAutofillSupported(); method public boolean isEnabled(); + method public boolean isFieldClassificationEnabled(); method public void notifyValueChanged(android.view.View); method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue); method public void notifyViewEntered(android.view.View); @@ -48600,6 +48642,7 @@ package android.view.autofill { method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(android.view.View); method public void requestAutofill(android.view.View, int, android.graphics.Rect); + method public void setUserData(android.service.autofill.UserData); method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback); field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE"; field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT"; diff --git a/api/system-current.txt b/api/system-current.txt index 30e4cbce78e5..227b4833cf76 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3531,6 +3531,11 @@ package android.provider { public static final class Settings.Secure extends android.provider.Settings.NameValueTable { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean); method public static void resetToDefaults(android.content.ContentResolver, java.lang.String); + field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; + field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size"; + field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size"; + field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length"; + field public static final java.lang.String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length"; field public static final java.lang.String INSTANT_APPS_ENABLED = "instant_apps_enabled"; } diff --git a/api/test-current.txt b/api/test-current.txt index 3fc5cd6efc76..5635b5653a77 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -463,34 +463,11 @@ package android.service.autofill { } public final class EditDistanceScorer extends android.service.autofill.InternalScorer implements android.os.Parcelable android.service.autofill.Scorer { - method public int describeContents(); - method public static android.service.autofill.EditDistanceScorer getInstance(); method public float getScore(android.view.autofill.AutofillValue, java.lang.String); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.service.autofill.EditDistanceScorer> CREATOR; - } - - public final class FieldClassification implements android.os.Parcelable { - method public int describeContents(); - method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification> CREATOR; - } - - public static final class FieldClassification.Match implements android.os.Parcelable { - method public int describeContents(); - method public java.lang.String getRemoteId(); - method public float getScore(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification.Match> CREATOR; - } - - public static final class FillEventHistory.Event { - method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification(); } - public static final class FillResponse.Builder { - method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(android.view.autofill.AutofillId...); + public final class FillResponse implements android.os.Parcelable { + method public int getFlags(); } public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { @@ -523,29 +500,10 @@ package android.service.autofill { method public boolean isValid(android.service.autofill.ValueFinder); } - public abstract interface Scorer { - } - public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer { method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue); } - public final class UserData implements android.os.Parcelable { - method public int describeContents(); - method public static int getMaxFieldClassificationIdsSize(); - method public static int getMaxUserDataSize(); - method public static int getMaxValueLength(); - method public static int getMinValueLength(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.service.autofill.UserData> CREATOR; - } - - public static final class UserData.Builder { - ctor public UserData.Builder(android.service.autofill.Scorer, java.lang.String, java.lang.String); - method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String); - method public android.service.autofill.UserData build(); - } - public abstract interface ValueFinder { method public abstract java.lang.String findByAutofillId(android.view.autofill.AutofillId); } @@ -993,12 +951,6 @@ package android.view.autofill { ctor public AutofillId(int); } - public final class AutofillManager { - method public android.service.autofill.UserData getUserData(); - method public boolean isFieldClassificationEnabled(); - method public void setUserData(android.service.autofill.UserData); - } - } package android.widget { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index abc16cec269d..d0c1003e3034 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5328,48 +5328,51 @@ public final class Settings { public static final String AUTOFILL_SERVICE = "autofill_service"; /** - * Experimental autofill feature. + * Boolean indicating if Autofill supports field classification. + * + * @see android.service.autofill.AutofillService * - * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ + @SystemApi @TestApi public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; /** - * Experimental autofill feature. + * Defines value returned by {@link android.service.autofill.UserData#getMaxUserDataSize()}. * - * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ + @SystemApi public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size"; /** - * Experimental autofill feature. + * Defines value returned by + * {@link android.service.autofill.UserData#getMaxFieldClassificationIdsSize()}. * - * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ + @SystemApi public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size"; /** - * Experimental autofill feature. + * Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}. * - * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ + @SystemApi public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length"; /** - * Experimental autofill feature. + * Defines value returned by {@link android.service.autofill.UserData#getMinValueLength()}. * - * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ + @SystemApi public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length"; diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 97fdcefc9d56..2600f8ab4d69 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -453,13 +453,46 @@ import com.android.internal.os.SomeArgs; * email address), the service should only use it locally (i.e., in the app's process) for * heuristics purposes, but it should not be sent to external servers. * - * <a name="FieldsClassification"></a> - * <h3>Metrics and fields classification</h3 + * <a name="FieldClassification"></a> + * <h3>Metrics and field classification</h3 * - * <p>TODO(b/67867469): document it or remove this section; in particular, document the relationship - * between set/getUserData(), FillResponse.setFieldClassificationIds(), and - * FillEventHistory.getFieldsClassification. + * <p>The service can call {@link #getFillEventHistory()} to get metrics representing the user + * actions, and then use these metrics to improve its heuristics. + * + * <p>Prior to Android {@link android.os.Build.VERSION_CODES#P}, the metrics covered just the + * scenarios where the service knew how to autofill an activity, but Android + * {@link android.os.Build.VERSION_CODES#P} introduced a new mechanism called field classification, + * which allows the service to dinamically classify the meaning of fields based on the existing user + * data known by the service. + * + * <p>Typically, field classification can be used to detect fields that can be autofilled with + * user data that is not associated with a specific app—such as email and physical + * address. Once the service identifies that a such field was manually filled by the user, the + * service could use this signal to improve its heuristics, either locally (i.e., in the same + * device) or globally (i.e., by crowdsourcing the results back to the service's server so it can + * be used by other users). + * + * <p>The field classification workflow involves 4 steps: + * + * <ol> + * <li>Set the user data through {@link AutofillManager#setUserData(UserData)}. This data is + * cached until the system restarts (or the service is disabled), so it doesn't need to be set for + * all requests. + * <li>Identify which fields should be analysed by calling + * {@link FillResponse.Builder#setFieldClassificationIds(AutofillId...)}. + * <li>Verify the results through {@link FillEventHistory.Event#getFieldsClassification()}. + * <li>Use the results to dynamically create {@link Dataset} or {@link SaveInfo} objects in future + * requests. + * </ol> + * + * <p>The field classification is an expensive operation and should be used carefully, otherwise it + * can reach its rate limit and get blocked by the Android System. Ideally, it should be used just + * in cases where the service could not determine how an activity can be autofilled, but it has a + * strong suspicious that it could. For example, if an activity has four or more fields and one of + * them is a list, chances are that these are address fields (like address, city, state, and + * zip code). */ +// TODO(b/70407264): add code snippets above??? public abstract class AutofillService extends Service { private static final String TAG = "AutofillService"; diff --git a/core/java/android/service/autofill/EditDistanceScorer.java b/core/java/android/service/autofill/EditDistanceScorer.java index e25cd0467cc8..0706b377bbe8 100644 --- a/core/java/android/service/autofill/EditDistanceScorer.java +++ b/core/java/android/service/autofill/EditDistanceScorer.java @@ -16,7 +16,6 @@ package android.service.autofill; import android.annotation.NonNull; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.view.autofill.AutofillValue; @@ -24,14 +23,8 @@ import android.view.autofill.AutofillValue; /** * Helper used to calculate the classification score between an actual {@link AutofillValue} filled * by the user and the expected value predicted by an autofill service. - * - * TODO(b/67867469): - * - improve javadoc - * - document algorithm / copy from InternalScorer - * - unhide / remove testApi - * @hide */ -@TestApi +// TODO(b/70291841): explain algorithm once it's fully implemented public final class EditDistanceScorer extends InternalScorer implements Scorer, Parcelable { private static final EditDistanceScorer sInstance = new EditDistanceScorer(); @@ -46,10 +39,11 @@ public final class EditDistanceScorer extends InternalScorer implements Scorer, private EditDistanceScorer() { } + /** @hide */ @Override public float getScore(@NonNull AutofillValue actualValue, @NonNull String userData) { if (actualValue == null || !actualValue.isText() || userData == null) return 0; - // TODO(b/67867469): implement edit distance - currently it's returning either 0, 100%, or + // TODO(b/70291841): implement edit distance - currently it's returning either 0, 100%, or // partial match when number of chars match final String textValue = actualValue.getTextValue().toString(); final int total = textValue.length(); diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java index 0a60208c45a7..b28c6f81e782 100644 --- a/core/java/android/service/autofill/FieldClassification.java +++ b/core/java/android/service/autofill/FieldClassification.java @@ -19,7 +19,6 @@ package android.service.autofill; import static android.view.autofill.Helper.sDebug; import android.annotation.NonNull; -import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.view.autofill.Helper; @@ -31,15 +30,10 @@ import com.google.android.collect.Lists; import java.util.List; /** - * Gets the <a href="#FieldsClassification">fields classification</a> results for a given field. - * - * TODO(b/67867469): - * - improve javadoc - * - unhide / remove testApi - * - * @hide + * Represents the <a href="AutofillService.html#FieldClassification">field classification</a> + * results for a given field. */ -@TestApi +// TODO(b/70291841): let caller handle Parcelable... public final class FieldClassification implements Parcelable { private final Match mMatch; @@ -79,7 +73,7 @@ public final class FieldClassification implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { - parcel.writeParcelable(mMatch, flags); + mMatch.writeToParcel(parcel); } public static final Parcelable.Creator<FieldClassification> CREATOR = @@ -87,7 +81,7 @@ public final class FieldClassification implements Parcelable { @Override public FieldClassification createFromParcel(Parcel parcel) { - return new FieldClassification(parcel.readParcelable(null)); + return new FieldClassification(Match.readFromParcel(parcel)); } @Override @@ -97,16 +91,12 @@ public final class FieldClassification implements Parcelable { }; /** - * Gets the score of a {@link UserData} entry for the field. + * Represents the score of a {@link UserData} entry for the field. * - * TODO(b/67867469): - * - improve javadoc - * - unhide / remove testApi - * - * @hide + * <p>The score is defined by {@link #getScore()} and the entry is identified by + * {@link #getRemoteId()}. */ - @TestApi - public static final class Match implements Parcelable { + public static final class Match { private final String mRemoteId; private final float mScore; @@ -126,26 +116,19 @@ public final class FieldClassification implements Parcelable { } /** - * Gets a score between the value of this field and the value of the {@link UserData} entry. + * Gets a classification score for the value of this field compared to the value of the + * {@link UserData} entry. * - * <p>The score is based in a case-insensitive comparisson of all characters from both the - * field value and the user data entry, and it ranges from {@code 0} to {@code 1000000}: + * <p>The score is based in a comparison of the field value and the user data entry, and it + * ranges from {@code 0.0F} to {@code 1.0F}: * <ul> - * <li>{@code 1.0} represents a full match ({@code 100%}). - * <li>{@code 0.0} represents a full mismatch ({@code 0%}). + * <li>{@code 1.0F} represents a full match ({@code 100%}). + * <li>{@code 0.0F} represents a full mismatch ({@code 0%}). * <li>Any other value is a partial match. * </ul> * - * <p>How the score is calculated depends on the algorithm used by the Android System. - * For example, if the user data is {@code "abc"} and the field value us {@code " abc"}, - * the result could be: - * <ul> - * <li>{@code 1.0} if the algorithm trims the values. - * <li>{@code 0.0} if the algorithm compares the values sequentially. - * <li>{@code 0.75} if the algorithm consideres that 3/4 (75%) of the characters match. - * </ul> - * - * <p>Currently, the autofill service cannot configure the algorithm. + * <p>How the score is calculated depends on the algorithm used by the {@link Scorer} + * implementation. */ public float getScore() { return mScore; @@ -160,33 +143,31 @@ public final class FieldClassification implements Parcelable { return string.append(", score=").append(mScore).toString(); } - ///////////////////////////////////// - // Parcelable "contract" methods. // - ///////////////////////////////////// - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { + private void writeToParcel(@NonNull Parcel parcel) { parcel.writeString(mRemoteId); parcel.writeFloat(mScore); } - @SuppressWarnings("hiding") - public static final Parcelable.Creator<Match> CREATOR = new Parcelable.Creator<Match>() { + private static Match readFromParcel(@NonNull Parcel parcel) { + return new Match(parcel.readString(), parcel.readFloat()); + } - @Override - public Match createFromParcel(Parcel parcel) { - return new Match(parcel.readString(), parcel.readFloat()); + /** @hide */ + public static Match[] readArrayFromParcel(@NonNull Parcel parcel) { + final int length = parcel.readInt(); + final Match[] matches = new Match[length]; + for (int i = 0; i < length; i++) { + matches[i] = readFromParcel(parcel); } + return matches; + } - @Override - public Match[] newArray(int size) { - return new Match[size]; + /** @hide */ + public static void writeArrayToParcel(@NonNull Parcel parcel, @NonNull Match[] matches) { + parcel.writeInt(matches.length); + for (int i = 0; i < matches.length; i++) { + matches[i].writeToParcel(parcel); } - }; + } } } diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index a527f16105b9..07fab611e6be 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -21,7 +21,6 @@ import static android.view.autofill.Helper.sVerbose; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; @@ -158,7 +157,7 @@ public final class FillEventHistory implements Parcelable { final AutofillId[] detectedFields = event.mDetectedFieldIds; parcel.writeParcelableArray(detectedFields, flags); if (detectedFields != null) { - parcel.writeParcelableArray(event.mDetectedMatches, flags); + Match.writeArrayToParcel(parcel, event.mDetectedMatches); } } } @@ -208,6 +207,7 @@ public final class FillEventHistory implements Parcelable { * ({@link #getIgnoredDatasetIds()}). * <li>Which fields in the selected datasets were changed by the user after the dataset * was selected ({@link #getChangedFields()}. + * <li>Which fields match the {@link UserData} set by the service. * </ul> * * <p><b>Note: </b>This event is only generated when: @@ -222,7 +222,6 @@ public final class FillEventHistory implements Parcelable { * <p>See {@link android.view.autofill.AutofillManager} for more information about autofill * contexts. */ - // TODO(b/67867469): update with field detection behavior public static final int TYPE_CONTEXT_COMMITTED = 4; /** @hide */ @@ -356,19 +355,13 @@ public final class FillEventHistory implements Parcelable { } /** - * Gets the <a href="#FieldsClassification">fields classification</a> results. + * Gets the <a href="AutofillService.html#FieldClassification">field classification</a> + * results. * * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the * service requested {@link FillResponse.Builder#setFieldClassificationIds(AutofillId...) - * fields classification}. - * - * TODO(b/67867469): - * - improve javadoc - * - unhide / remove testApi - * - * @hide + * field classification}. */ - @TestApi @NonNull public Map<AutofillId, FieldClassification> getFieldsClassification() { if (mDetectedFieldIds == null) { return Collections.emptyMap(); @@ -462,6 +455,8 @@ public final class FillEventHistory implements Parcelable { * and belonged to datasets. * @param manuallyFilledDatasetIds The ids of datasets that had values matching the * respective entry on {@code manuallyFilledFieldIds}. + * @param detectedMatches the field classification matches. + * * @throws IllegalArgumentException If the length of {@code changedFieldIds} and * {@code changedDatasetIds} doesn't match. * @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and @@ -469,7 +464,6 @@ public final class FillEventHistory implements Parcelable { * * @hide */ - // TODO(b/67867469): document field classification parameters once stable public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState, @Nullable List<String> selectedDatasetIds, @Nullable ArraySet<String> ignoredDatasetIds, @@ -477,7 +471,7 @@ public final class FillEventHistory implements Parcelable { @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, - @Nullable AutofillId[] detectedFieldIds, @Nullable Match[] detectedMaches) { + @Nullable AutofillId[] detectedFieldIds, @Nullable Match[] detectedMatches) { mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED, "eventType"); mDatasetId = datasetId; @@ -502,7 +496,7 @@ public final class FillEventHistory implements Parcelable { mManuallyFilledDatasetIds = manuallyFilledDatasetIds; mDetectedFieldIds = detectedFieldIds; - mDetectedMatches = detectedMaches; + mDetectedMatches = detectedMatches; } @Override @@ -555,7 +549,7 @@ public final class FillEventHistory implements Parcelable { final AutofillId[] detectedFieldIds = parcel.readParcelableArray(null, AutofillId.class); final Match[] detectedMatches = (detectedFieldIds != null) - ? parcel.readParcelableArray(null, Match.class) + ? Match.readArrayFromParcel(parcel) : null; selection.addEvent(new Event(eventType, datasetId, clientState, diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 014d3e8c42c9..3a4b6bb8037e 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -41,7 +41,7 @@ import java.util.Arrays; import java.util.List; /** - * Response for a {@link + * Response for an {@link * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}. * * <p>See the main {@link AutofillService} documentation for more details and examples. @@ -156,6 +156,7 @@ public final class FillResponse implements Parcelable { } /** @hide */ + @TestApi public int getFlags() { return mFlags; } @@ -352,22 +353,18 @@ public final class FillResponse implements Parcelable { } /** - * Sets which fields are used for <a href="#FieldsClassification">fields classification</a> + * Sets which fields are used for + * <a href="AutofillService.html#FieldClassification">field classification</a> * + * <p><b>Note:</b> This method automatically adds the + * {@link FillResponse#FLAG_TRACK_CONTEXT_COMMITED} to the {@link #setFlags(int) flags}. + * @throws IllegalArgumentException is length of {@code ids} args is more than * {@link UserData#getMaxFieldClassificationIdsSize()}. * @throws IllegalStateException if {@link #build()} or {@link #disableAutofill(long)} was * already called. * @throws NullPointerException if {@code ids} or any element on it is {@code null}. - * - * TODO(b/67867469): - * - improve javadoc: explain relationship with UserData and how to check results - * - unhide / remove testApi - * - implement multiple ids - * - * @hide */ - @TestApi public Builder setFieldClassificationIds(@NonNull AutofillId... ids) { throwIfDestroyed(); throwIfDisableAutofillCalled(); @@ -375,6 +372,7 @@ public final class FillResponse implements Parcelable { Preconditions.checkArgumentInRange(ids.length, 1, UserData.getMaxFieldClassificationIdsSize(), "ids length"); mFieldClassificationIds = ids; + mFlags |= FLAG_TRACK_CONTEXT_COMMITED; return this; } @@ -423,9 +421,8 @@ public final class FillResponse implements Parcelable { * @throws IllegalStateException if either {@link #addDataset(Dataset)}, * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)}, * {@link #setSaveInfo(SaveInfo)}, {@link #setClientState(Bundle)}, or - * {link #setFieldClassificationIds(AutofillId...)} was already called. + * {@link #setFieldClassificationIds(AutofillId...)} was already called. */ - // TODO(b/67867469): add @ to {link setFieldClassificationIds} once it's public public Builder disableAutofill(long duration) { throwIfDestroyed(); if (duration <= 0) { @@ -506,14 +503,13 @@ public final class FillResponse implements Parcelable { * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)}, * {@link #setSaveInfo(SaveInfo)}, {@link #disableAutofill(long)}, * {@link #setClientState(Bundle)}, - * or {link #setFieldClassificationIds(AutofillId...)}. + * or {@link #setFieldClassificationIds(AutofillId...)}. * <li>{@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} is called * without any previous calls to {@link #addDataset(Dataset)}. * </ol> * * @return A built response. */ - // TODO(b/67867469): add @ to {link setFieldClassificationIds} once it's public public FillResponse build() { throwIfDestroyed(); if (mAuthentication == null && mDatasets == null && mSaveInfo == null diff --git a/core/java/android/service/autofill/Scorer.java b/core/java/android/service/autofill/Scorer.java index f6a802a33e14..c4018558b3ed 100644 --- a/core/java/android/service/autofill/Scorer.java +++ b/core/java/android/service/autofill/Scorer.java @@ -15,21 +15,14 @@ */ package android.service.autofill; -import android.annotation.TestApi; - /** * Helper class used to calculate a score. * - * <p>Typically used to calculate the field classification score between an actual - * {@link android.view.autofill.AutofillValue} filled by the user and the expected value predicted - * by an autofill service. - * - * TODO(b/67867469): - * - improve javadoc - * - unhide / remove testApi - * @hide + * <p>Typically used to calculate the + * <a href="AutofillService.html#FieldClassification">field classification</a> score between an + * actual {@link android.view.autofill.AutofillValue} filled by the user and the expected value + * predicted by an autofill service. */ -@TestApi public interface Scorer { } diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java index 0d378153aa0d..f0cc360fe075 100644 --- a/core/java/android/service/autofill/UserData.java +++ b/core/java/android/service/autofill/UserData.java @@ -23,7 +23,6 @@ import static android.view.autofill.Helper.sDebug; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.app.ActivityThread; import android.content.ContentResolver; import android.os.Parcel; @@ -38,15 +37,9 @@ import java.io.PrintWriter; import java.util.ArrayList; /** - * Class used by service to improve autofillable fields detection by tracking the meaning of fields - * manually edited by the user (when they match values provided by the service). - * - * TODO(b/67867469): - * - improve javadoc / add link to section on AutofillService - * - unhide / remove testApi - * @hide + * Defines the user data used for + * <a href="AutofillService.html#FieldClassification">field classification</a>. */ -@TestApi public final class UserData implements Parcelable { private static final String TAG = "UserData"; @@ -110,12 +103,7 @@ public final class UserData implements Parcelable { /** * A builder for {@link UserData} objects. - * - * TODO(b/67867469): unhide / remove testApi - * - * @hide */ - @TestApi public static final class Builder { private final InternalScorer mScorer; private final ArrayList<String> mRemoteIds; @@ -123,7 +111,7 @@ public final class UserData implements Parcelable { private boolean mDestroyed; /** - * Creates a new builder for the user data used for <a href="#FieldsClassification">fields + * Creates a new builder for the user data used for <a href="#FieldClassification">field * classification</a>. * * @throws IllegalArgumentException if any of the following occurs: @@ -288,14 +276,16 @@ public final class UserData implements Parcelable { } /** - * Gets the minimum length of values passed to {@link Builder#Builder(Scorer, String, String)}. + * Gets the minimum length of values passed to the builder's constructor or + * or {@link Builder#add(String, String)}. */ public static int getMinValueLength() { return getInt(AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, DEFAULT_MIN_VALUE_LENGTH); } /** - * Gets the maximum length of values passed to {@link Builder#Builder(Scorer, String, String)}. + * Gets the maximum length of values passed to the builder's constructor or + * or {@link Builder#add(String, String)}. */ public static int getMaxValueLength() { return getInt(AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, DEFAULT_MAX_VALUE_LENGTH); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 6d84aa009c75..d0dbff0e23f3 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -24,7 +24,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.TestApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -1010,20 +1009,14 @@ public final class AutofillManager { } /** - * Gets the user data used for <a href="#FieldsClassification">fields classification</a>. + * Gets the user data used for + * <a href="AutofillService.html#FieldClassification">field classification</a>. * * <p><b>Note:</b> This method should only be called by an app providing an autofill service. * - * TODO(b/67867469): - * - proper javadoc - * - unhide / remove testApi - * * @return value previously set by {@link #setUserData(UserData)} or {@code null} if it was * reset or if the caller currently does not have an enabled autofill service for the user. - * - * @hide */ - @TestApi @Nullable public UserData getUserData() { try { return mService.getUserData(); @@ -1034,21 +1027,13 @@ public final class AutofillManager { } /** - * Sets the user data used for <a href="#FieldsClassification">fields classification</a>. + * Sets the user data used for + * <a href="AutofillService.html#FieldClassification">field classification</a> * * <p><b>Note:</b> This method should only be called by an app providing an autofill service, * and it's ignored if the caller currently doesn't have an enabled autofill service for * the user. - * - * TODO(b/67867469): - * - proper javadoc - * - unhide / remove testApi - * - add unit tests: - * - call set / get / verify - * - * @hide */ - @TestApi public void setUserData(@Nullable UserData userData) { try { mService.setUserData(userData); @@ -1058,13 +1043,17 @@ public final class AutofillManager { } /** - * TODO(b/67867469): - * - proper javadoc - * - mention this method in other places - * - unhide / remove testApi - * @hide + * Checks if <a href="AutofillService.html#FieldClassification">field classification</a> is + * enabled. + * + * <p>As field classification is an expensive operation, it could be disabled, either + * temporarily (for example, because the service exceeded a rate-limit threshold) or + * permanently (for example, because the device is a low-level device). + * + * <p><b>Note:</b> This method should only be called by an app providing an autofill service, + * and it's ignored if the caller currently doesn't have an enabled autofill service for + * the user. */ - @TestApi public boolean isFieldClassificationEnabled() { try { return mService.isFieldClassificationEnabled(); diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 907a1b843c0c..10024535067b 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -421,13 +421,6 @@ public class SettingsBackupTest { private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, - // TODO(b/67867469): Move autofill settings below to - // BACKUP_BLACKLISTED_SYSTEM_SETTINGS once feature is moved out of experimental - Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, - Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, - Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, - Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, - Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS, Settings.Secure.ALWAYS_ON_VPN_APP, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, @@ -437,6 +430,11 @@ public class SettingsBackupTest { Settings.Secure.ASSIST_DISCLOSURE_ENABLED, Settings.Secure.ASSIST_SCREENSHOT_ENABLED, Settings.Secure.ASSIST_STRUCTURE_ENABLED, + Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, + Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, + Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, + Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, + Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED, Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 56f5f64c090a..ceae93cefe95 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -512,7 +512,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final AutofillId[] fieldClassificationIds = response.getFieldClassificationIds(); - // TODO(b/67867469): remove once feature is finished (or use method from AFM to check) if (fieldClassificationIds != null && !mService.isFieldClassificationEnabled()) { Slog.w(TAG, "Ignoring " + response + " because field detection is disabled"); processNullResponseLocked(requestFlags); @@ -1662,7 +1661,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL); mViewStates.put(id, viewState); - // TODO(b/67867469): for optimization purposes, should also ignore if change is + // TODO(b/70407264): for optimization purposes, should also ignore if change is // detectable, and batch-send them when the session is finished (but that will // require tracking detectable fields on AutofillManager) if (isIgnored) { |