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

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

Merge "Refactored field detection mechanism to support multiple fields."

parents a18d3572 452886a5
Loading
Loading
Loading
Loading
+23 −9
Original line number Diff line number Diff line
@@ -457,19 +457,12 @@ package android.service.autofill {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }

  public final class FieldsDetection implements android.os.Parcelable {
    ctor public FieldsDetection(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FieldsDetection> CREATOR;
  }

  public static final class FillEventHistory.Event {
    method public java.util.Map<java.lang.String, java.lang.Integer> getDetectedFields();
    method public java.util.Map<java.lang.String, java.lang.Integer> getFieldsClassification();
  }

  public static final class FillResponse.Builder {
    method public android.service.autofill.FillResponse.Builder setFieldsDetection(android.service.autofill.FieldsDetection);
    method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(android.view.autofill.AutofillId...);
  }

  public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -501,6 +494,22 @@ package android.service.autofill {
    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(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);
  }
@@ -983,6 +992,11 @@ package android.view.autofill {
    ctor public AutofillId(int);
  }

  public final class AutofillManager {
    method public android.service.autofill.UserData getUserData();
    method public void setUserData(android.service.autofill.UserData);
  }

}

package android.widget {
+36 −0
Original line number Diff line number Diff line
@@ -5332,6 +5332,42 @@ public final class Settings {
        @TestApi
        public static final String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";

        /**
         * Experimental autofill feature.
         *
         * <p>TODO(b/67867469): document (or remove) once feature is finished
         * @hide
         */
        public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE =
                "autofill_user_data_max_user_data_size";

        /**
         * Experimental autofill feature.
         *
         * <p>TODO(b/67867469): document (or remove) once feature is finished
         * @hide
         */
        public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE =
                "autofill_user_data_max_field_classification_size";

        /**
         * Experimental autofill feature.
         *
         * <p>TODO(b/67867469): document (or remove) once feature is finished
         * @hide
         */
        public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH =
                "autofill_user_data_max_value_length";

        /**
         * Experimental autofill feature.
         *
         * <p>TODO(b/67867469): document (or remove) once feature is finished
         * @hide
         */
        public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH =
                "autofill_user_data_min_value_length";

        /**
         * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
         */
+7 −1
Original line number Diff line number Diff line
@@ -440,7 +440,6 @@ import com.android.internal.os.SomeArgs;
 *  save(username, password);
 * </pre>
 *
 *
 * <a name="Privacy"></a>
 * <h3>Privacy</h3>
 *
@@ -453,6 +452,13 @@ import com.android.internal.os.SomeArgs;
 * <p>Because this data could contain PII (Personally Identifiable Information, such as username or
 * 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
 *
 * <p>TODO(b/67867469): document it or remove this section; in particular, document the relationship
 * between set/getUserData(), FillResponse.setFieldClassificationIds(), and
 * FillEventHistory.getFieldsClassification.
 */
public abstract class AutofillService extends Service {
    private static final String TAG = "AutofillService";
+0 −127
Original line number Diff line number Diff line
/*
 * Copyright 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.service.autofill;

import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.autofill.AutofillId;

/**
 * Class 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):
 *  - proper javadoc
 *  - unhide / remove testApi
 *  - add FieldsDetection management so service can set it just once and reference it in further
 *    calls to improve performance (and also API to refresh it)
 *  - rename to FieldsDetectionInfo or FieldClassification? (same for CTS tests)
 *  - add FieldsDetectionUnitTest once API is well-defined
 * @hide
 */
@TestApi
public final class FieldsDetection implements Parcelable {

    private final AutofillId mFieldId;
    private final String mRemoteId;
    private final String mValue;

    /**
     * Creates a field detection for just one field / value pair.
     *
     * @param fieldId autofill id of the field in the screen.
     * @param remoteId id used by the service to identify the field later.
     * @param value field value known to the service.
     *
     * TODO(b/67867469):
     *  - proper javadoc
     *  - change signature to allow more fields / values / match methods
     *    - might also need to use a builder, where the constructor is the id for the fieldsdetector
     *    - might need id for values as well
     *  - add @NonNull / check it / add unit tests
     *  - make 'value' input more generic so it can accept distance-based match and other matches
     *  - throw exception if field value is less than X characters (somewhere between 7-10)
     *  - make sure to limit total number of fields to around 10 or so
     *  - use AutofillValue instead of String (so it can compare dates, for example)
     */
    public FieldsDetection(AutofillId fieldId, String remoteId, String value) {
        mFieldId = fieldId;
        mRemoteId = remoteId;
        mValue = value;
    }

    /** @hide */
    public AutofillId getFieldId() {
        return mFieldId;
    }

    /** @hide */
    public String getRemoteId() {
        return mRemoteId;
    }

    /** @hide */
    public String getValue() {
        return mValue;
    }

    /////////////////////////////////////
    // Object "contract" methods. //
    /////////////////////////////////////
    @Override
    public String toString() {
        // Cannot disclose remoteId or value because they could contain PII
        return new StringBuilder("FieldsDetection: [field=").append(mFieldId)
                .append(", remoteId_length=").append(mRemoteId.length())
                .append(", value_length=").append(mValue.length())
                .append("]").toString();
    }

    /////////////////////////////////////
    // Parcelable "contract" methods. //
    /////////////////////////////////////

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeParcelable(mFieldId, flags);
        parcel.writeString(mRemoteId);
        parcel.writeString(mValue);
    }

    public static final Parcelable.Creator<FieldsDetection> CREATOR =
            new Parcelable.Creator<FieldsDetection>() {
        @Override
        public FieldsDetection createFromParcel(Parcel parcel) {
            // TODO(b/67867469): remove comment below if it does not use a builder at the end
            // 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.
            return new FieldsDetection(parcel.readParcelable(null), parcel.readString(),
                    parcel.readString());
        }

        @Override
        public FieldsDetection[] newArray(int size) {
            return new FieldsDetection[size];
        }
    };
}
+10 −25
Original line number Diff line number Diff line
@@ -57,11 +57,6 @@ import java.util.Set;
 * the history will clear out after some pre-defined time).
 */
public final class FillEventHistory implements Parcelable {
    /**
     * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}.
     */
    private final int mServiceUid;

    /**
     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
     */
@@ -70,17 +65,6 @@ public final class FillEventHistory implements Parcelable {
    @Nullable private final Bundle mClientState;
    @Nullable List<Event> mEvents;

    /**
     * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}.
     *
     * @return The UID of the {@link AutofillService}
     *
     * @hide
     */
    public int getServiceUid() {
        return mServiceUid;
    }

    /** @hide */
    public int getSessionId() {
        return mSessionId;
@@ -123,9 +107,8 @@ public final class FillEventHistory implements Parcelable {
    /**
     * @hide
     */
    public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
    public FillEventHistory(int sessionId, @Nullable Bundle clientState) {
        mClientState = clientState;
        mServiceUid = serviceUid;
        mSessionId = sessionId;
    }

@@ -364,16 +347,17 @@ public final class FillEventHistory implements Parcelable {
        }

        /**
         * Gets the results of the last {@link FieldsDetection} request.
         * Gets the results of the last fields classification request.
         *
         * @return map of edit-distance match ({@code 0} means full match,
         * {@code 1} means 1 character different, etc...) by remote id (as set in the
         * {@link FieldsDetection} constructor), or {@code null} if none of the user-input values
         * {@code 1} means 1 character different, etc...) by remote id (as set on
         * {@link UserData.Builder#add(String, android.view.autofill.AutofillValue)}),
         * or {@code null} if none of the user-input values
         * matched the requested detection.
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the
         * service requested {@link FillResponse.Builder#setFieldsDetection(FieldsDetection) fields
         * detection}.
         * service requested {@link FillResponse.Builder#setFieldClassificationIds(AutofillId...)
         * fields detection}.
         *
         * TODO(b/67867469):
         *  - improve javadoc
@@ -382,11 +366,12 @@ public final class FillEventHistory implements Parcelable {
         *  - unhide
         *  - unhide / remove testApi
         *  - add @NonNull / check it / add unit tests
         *  - add link to AutofillService #FieldsClassification anchor
         *
         * @hide
         */
        @TestApi
        @NonNull public Map<String, Integer> getDetectedFields() {
        @NonNull public Map<String, Integer> getFieldsClassification() {
            if (mDetectedRemoteId == null || mDetectedFieldScore == -1) {
                return Collections.emptyMap();
            }
@@ -534,7 +519,7 @@ public final class FillEventHistory implements Parcelable {
            new Parcelable.Creator<FillEventHistory>() {
                @Override
                public FillEventHistory createFromParcel(Parcel parcel) {
                    FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
                    FillEventHistory selection = new FillEventHistory(0, parcel.readBundle());

                    final int numEvents = parcel.readInt();
                    for (int i = 0; i < numEvents; i++) {
Loading