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

Commit 71d53e0c authored by Adam He's avatar Adam He
Browse files

Added new API to set field classification algorithms per category.

Originally one field classification algorithm was used to classify every
field. The change allows different category of fields to be classified
by different field classification algorithms.

Change-Id: I27205a4096774d6e0c0d56da5e0fd38dda995d8f
Fixes: 118681526
Test: atest CtsAutoFillServiceTestCases
Test: atest android.autofillservice.cts.FieldsClassificationTest
parent e02414c2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -40506,6 +40506,7 @@ package android.service.autofill {
  public final class UserData implements android.os.Parcelable {
    method public int describeContents();
    method public java.lang.String getFieldClassificationAlgorithm();
    method public java.lang.String getFieldClassificationAlgorithmForCategory(java.lang.String);
    method public java.lang.String getId();
    method public static int getMaxCategoryCount();
    method public static int getMaxFieldClassificationIdsSize();
@@ -40521,6 +40522,7 @@ package android.service.autofill {
    method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String);
    method public android.service.autofill.UserData build();
    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithm(java.lang.String, android.os.Bundle);
    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithmForCategory(java.lang.String, java.lang.String, android.os.Bundle);
  }
  public abstract interface Validator {
+4 −1
Original line number Diff line number Diff line
@@ -4871,7 +4871,10 @@ package android.service.autofill {

  public abstract class AutofillFieldClassificationService extends android.app.Service {
    method public android.os.IBinder onBind(android.content.Intent);
    method public float[][] onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>);
    method public float[][] onCalculateScores(java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>, java.util.List<java.lang.String>, java.lang.String, android.os.Bundle, java.util.Map, java.util.Map);
    method public deprecated float[][] onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>);
    field public static final java.lang.String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
    field public static final java.lang.String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
    field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
    field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
+13 −0
Original line number Diff line number Diff line
@@ -1066,6 +1066,15 @@ package android.security.keystore {

package android.service.autofill {

  public abstract class AutofillFieldClassificationService extends android.app.Service {
    method public android.os.IBinder onBind(android.content.Intent);
    field public static final java.lang.String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
    field public static final java.lang.String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
    field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
    field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
  }

  public final class CharSequenceTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }
@@ -1122,6 +1131,10 @@ 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 android.util.ArrayMap<java.lang.String, java.lang.String> getFieldClassificationAlgorithms();
  }

  public abstract interface ValueFinder {
    method public default java.lang.String findByAutofillId(android.view.autofill.AutofillId);
    method public abstract android.view.autofill.AutofillValue findRawValueByAutofillId(android.view.autofill.AutofillId);
+112 −9
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
@@ -35,6 +36,7 @@ import android.view.autofill.AutofillValue;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * A service that calculates field classification scores.
@@ -51,6 +53,7 @@ import java.util.List;
 * {@hide}
 */
@SystemApi
@TestApi
public abstract class AutofillFieldClassificationService extends Service {

    private static final String TAG = "AutofillFieldClassificationService";
@@ -75,17 +78,32 @@ public abstract class AutofillFieldClassificationService extends Service {
    public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
            "android.autofill.field_classification.available_algorithms";

    /**
     * Field classification algorithm that computes the edit distance between two Strings.
     *
     * <p>Service implementation must provide this algorithm.</p>
     */
    public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";

    /**
     * Field classification algorithm that computes whether the last four digits between two
     * Strings match exactly.
     *
     * <p>Service implementation must provide this algorithm.</p>
     */
    public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";

    /** {@hide} **/
    public static final String EXTRA_SCORES = "scores";

    private AutofillFieldClassificationServiceWrapper mWrapper;

    private void getScores(RemoteCallback callback, String algorithmName, Bundle algorithmArgs,
            List<AutofillValue> actualValues, String[] userDataValues) {
    private void calculateScores(RemoteCallback callback, List<AutofillValue> actualValues,
            String[] userDataValues, String[] categoryIds, String defaultAlgorithm,
            Bundle defaultArgs, Map algorithms, Map args) {
        final Bundle data = new Bundle();
        final float[][] scores = onGetScores(algorithmName, algorithmArgs, actualValues,
                Arrays.asList(userDataValues));
        final float[][] scores = onCalculateScores(actualValues, Arrays.asList(userDataValues),
                Arrays.asList(categoryIds), defaultAlgorithm, defaultArgs, algorithms, args);
        if (scores != null) {
            data.putParcelable(EXTRA_SCORES, new Scores(scores));
        }
@@ -169,9 +187,12 @@ public abstract class AutofillFieldClassificationService extends Service {
     * @return the calculated scores of {@code actualValues} x {@code userDataValues}.
     *
     * {@hide}
     *
     * @deprecated Use {@link AutofillFieldClassificationService#onCalculateScores} instead.
     */
    @Nullable
    @SystemApi
    @Deprecated
    public float[][] onGetScores(@Nullable String algorithm,
            @Nullable Bundle algorithmOptions, @NonNull List<AutofillValue> actualValues,
            @NonNull List<String> userDataValues) {
@@ -179,16 +200,98 @@ public abstract class AutofillFieldClassificationService extends Service {
        return null;
    }

    /**
     * Calculates field classification scores in a batch.
     *
     * <p>A field classification score is a {@code float} representing how well an
     * {@link AutofillValue} matches a expected value predicted by an autofill service
     * &mdash;a full match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
     *
     * <p>The exact score depends on the algorithm used to calculate it&mdash;the service must
     * provide at least one default algorithm (which is used when the algorithm is not specified
     * or is invalid), but it could provide more (in which case the algorithm name should be
     * specified by the caller when calculating the scores).
     *
     * <p>For example, if the service provides an algorithm named {@code EXACT_MATCH} that
     * returns {@code 1.0} if all characters match or {@code 0.0} otherwise, a call to:
     *
     * <pre>
     * HashMap algorithms = new HashMap<>();
     * algorithms.put("email", "EXACT_MATCH");
     * algorithms.put("phone", "EXACT_MATCH");
     *
     * HashMap args = new HashMap<>();
     * args.put("email", null);
     * args.put("phone", null);
     *
     * service.onCalculateScores(Arrays.asList(AutofillValue.forText("email1"),
     * AutofillValue.forText("PHONE1")), Arrays.asList("email1", "phone1"),
     * Array.asList("email", "phone"), algorithms, args);
     * </pre>
     *
     * <p>Returns:
     *
     * <pre>
     * [
     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
     *   [0.0, 0.0]  // "PHONE1" compared against ["email1", "phone1"]
     * ];
     * </pre>
     *
     * <p>If the same algorithm allows the caller to specify whether the comparisons should be
     * case sensitive by passing a boolean option named {@code "case_sensitive"}, then a call to:
     *
     * <pre>
     * Bundle algorithmOptions = new Bundle();
     * algorithmOptions.putBoolean("case_sensitive", false);
     * args.put("phone", algorithmOptions);
     *
     * service.onCalculateScores(Arrays.asList(AutofillValue.forText("email1"),
     * AutofillValue.forText("PHONE1")), Arrays.asList("email1", "phone1"),
     * Array.asList("email", "phone"), algorithms, args);
     * </pre>
     *
     * <p>Returns:
     *
     * <pre>
     * [
     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
     *   [0.0, 1.0]  // "PHONE1" compared against ["email1", "phone1"]
     * ];
     * </pre>
     *
     * @param actualValues values entered by the user.
     * @param userDataValues values predicted from the user data.
     * @param categoryIds category Ids correspoinding to userDataValues
     * @param defaultAlgorithm default field classification algorithm
     * @param algorithms array of field classification algorithms
     * @return the calculated scores of {@code actualValues} x {@code userDataValues}.
     *
     * {@hide}
     */
    @Nullable
    @SystemApi
    public float[][] onCalculateScores(@NonNull List<AutofillValue> actualValues,
            @NonNull List<String> userDataValues, @NonNull List<String> categoryIds,
            @Nullable String defaultAlgorithm, @Nullable Bundle defaultArgs,
            @Nullable Map algorithms, @Nullable Map args) {
        Log.e(TAG, "service implementation (" + getClass()
                + " does not implement onCalculateScore()");
        return null;
    }

    private final class AutofillFieldClassificationServiceWrapper
            extends IAutofillFieldClassificationService.Stub {
        @Override
        public void getScores(RemoteCallback callback, String algorithmName, Bundle algorithmArgs,
                List<AutofillValue> actualValues, String[] userDataValues)
        public void calculateScores(RemoteCallback callback, List<AutofillValue> actualValues,
                String[] userDataValues, String[] categoryIds, String defaultAlgorithm,
                Bundle defaultArgs, Map algorithms, Map args)
                throws RemoteException {
            mHandler.sendMessage(obtainMessage(
                    AutofillFieldClassificationService::getScores,
                    AutofillFieldClassificationService::calculateScores,
                    AutofillFieldClassificationService.this,
                    callback, algorithmName, algorithmArgs, actualValues, userDataValues));
                    callback, actualValues, userDataValues, categoryIds, defaultAlgorithm,
                    defaultArgs, algorithms, args));
        }
    }

+5 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.os.RemoteCallback;
import android.view.autofill.AutofillValue;
import java.util.List;
import java.util.Map;

/**
 * Service used to calculate match scores for Autofill Field Classification.
@@ -27,6 +28,8 @@ import java.util.List;
 * @hide
 */
oneway interface IAutofillFieldClassificationService {
    void getScores(in RemoteCallback callback, String algorithmName, in Bundle algorithmArgs,
                   in List<AutofillValue> actualValues, in String[] userDataValues);
    void calculateScores(in RemoteCallback callback, in List<AutofillValue> actualValues,
                         in String[] userDataValues, in String[] categoryIds,
                         in String defaultAlgorithm, in Bundle defaultArgs,
                         in Map algorithms, in Map args);
}
Loading