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

Commit db6b0fec authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Moved Field Classification score logic to ExtServices."

parents 9e1afde8 bc055b0e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -242,6 +242,7 @@ java_library {
        "core/java/android/security/IKeystoreService.aidl",
        "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
        "core/java/android/service/autofill/IAutoFillService.aidl",
        "core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
        "core/java/android/service/autofill/IFillCallback.aidl",
        "core/java/android/service/autofill/ISaveCallback.aidl",
        "core/java/android/service/carrier/ICarrierService.aidl",
+22 −0
Original line number Diff line number Diff line
@@ -3856,6 +3856,28 @@ 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);
    method public java.util.List<java.lang.String> onGetAvailableAlgorithms();
    method public java.lang.String onGetDefaultAlgorithm();
    method public android.service.autofill.AutofillFieldClassificationService.Scores 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 SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
  }

  public static final class AutofillFieldClassificationService.Scores implements android.os.Parcelable {
    ctor public AutofillFieldClassificationService.Scores(java.lang.String, int, int);
    ctor public AutofillFieldClassificationService.Scores(android.os.Parcel);
    method public int describeContents();
    method public java.lang.String getAlgorithm();
    method public float[][] getScores();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.AutofillFieldClassificationService.Scores> CREATOR;
  }

}

package android.service.notification {

  public final class Adjustment implements android.os.Parcelable {
+0 −5
Original line number Diff line number Diff line
@@ -563,11 +563,6 @@ package android.service.autofill {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }

  public final class EditDistanceScorer {
    method public static android.service.autofill.EditDistanceScorer getInstance();
    method public float getScore(android.view.autofill.AutofillValue, java.lang.String);
  }

  public final class FillResponse implements android.os.Parcelable {
    method public int getFlags();
  }
+284 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 static android.view.autofill.AutofillManager.EXTRA_AVAILABLE_ALGORITHMS;
import static android.view.autofill.AutofillManager.EXTRA_DEFAULT_ALGORITHM;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.view.autofill.AutofillValue;

import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;

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

/**
 * A service that calculates field classification scores.
 *
 * <p>A field classification score is a {@code float} representing how well an
 * {@link AutofillValue} filled 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 specifiied by the caller
 * when calculating the scores).
 *
 * {@hide}
 */
@SystemApi
public abstract class AutofillFieldClassificationService extends Service {

    private static final String TAG = "AutofillFieldClassificationService";

    private static final int MSG_GET_AVAILABLE_ALGORITHMS = 1;
    private static final int MSG_GET_DEFAULT_ALGORITHM = 2;
    private static final int MSG_GET_SCORES = 3;

    /**
     * The {@link Intent} action that must be declared as handled by a service
     * in its manifest for the system to recognize it as a quota providing service.
     */
    public static final String SERVICE_INTERFACE =
            "android.service.autofill.AutofillFieldClassificationService";

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

    private AutofillFieldClassificationServiceWrapper mWrapper;

    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
        final int action = msg.what;
        final Bundle data = new Bundle();
        final RemoteCallback callback;
        switch (action) {
            case MSG_GET_AVAILABLE_ALGORITHMS:
                callback = (RemoteCallback) msg.obj;
                final List<String> availableAlgorithms = onGetAvailableAlgorithms();
                String[] asArray = null;
                if (availableAlgorithms != null) {
                    asArray = new String[availableAlgorithms.size()];
                    availableAlgorithms.toArray(asArray);
                }
                data.putStringArray(EXTRA_AVAILABLE_ALGORITHMS, asArray);
                break;
            case MSG_GET_DEFAULT_ALGORITHM:
                callback = (RemoteCallback) msg.obj;
                final String defaultAlgorithm = onGetDefaultAlgorithm();
                data.putString(EXTRA_DEFAULT_ALGORITHM, defaultAlgorithm);
                break;
            case MSG_GET_SCORES:
                final SomeArgs args = (SomeArgs) msg.obj;
                callback = (RemoteCallback) args.arg1;
                final String algorithmName = (String) args.arg2;
                final Bundle algorithmArgs = (Bundle) args.arg3;
                @SuppressWarnings("unchecked")
                final List<AutofillValue> actualValues = ((List<AutofillValue>) args.arg4);
                @SuppressWarnings("unchecked")
                final String[] userDataValues = (String[]) args.arg5;
                final Scores scores = onGetScores(algorithmName, algorithmArgs, actualValues,
                        Arrays.asList(userDataValues));
                data.putParcelable(EXTRA_SCORES, scores);
                break;
            default:
                Log.w(TAG, "Handling unknown message: " + action);
                return;
        }
        callback.sendResult(data);
    };

    private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(),
            mHandlerCallback, true);

    /** @hide */
    public AutofillFieldClassificationService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        mWrapper = new AutofillFieldClassificationServiceWrapper();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mWrapper;
    }

    /**
     * Gets the name of all available algorithms.
     *
     * @throws UnsupportedOperationException if not implemented by service.
     */
    // TODO(b/70939974): rename to onGetAvailableAlgorithms if not removed
    @NonNull
    public List<String> onGetAvailableAlgorithms() {
        throw new UnsupportedOperationException("Must be implemented by external service");
    }

    /**
     * Gets the default algorithm that's used when an algorithm is not specified or is invalid.
     *
     * @throws UnsupportedOperationException if not implemented by service.
     */
    @NonNull
    public String onGetDefaultAlgorithm() {
        throw new UnsupportedOperationException("Must be implemented by external service");
    }

    /**
     * Calculates field classification scores in a batch.
     *
     * <p>See {@link AutofillFieldClassificationService} for more info about field classification
     * scores.
     *
     * @param algorithm name of the algorithm to be used to calculate the scores. If invalid, the
     * default algorithm will be used instead.
     * @param args optional arguments to be passed to the algorithm.
     * @param actualValues values entered by the user.
     * @param userDataValues values predicted from the user data.
     * @return the calculated scores and the algorithm used.
     *
     * {@hide}
     */
    @Nullable
    @SystemApi
    public Scores onGetScores(@Nullable String algorithm,
            @Nullable Bundle args, @NonNull List<AutofillValue> actualValues,
            @NonNull List<String> userDataValues) {
        throw new UnsupportedOperationException("Must be implemented by external service");
    }

    private final class AutofillFieldClassificationServiceWrapper
            extends IAutofillFieldClassificationService.Stub {

        @Override
        public void getAvailableAlgorithms(RemoteCallback callback) throws RemoteException {
            mHandlerCaller.obtainMessageO(MSG_GET_AVAILABLE_ALGORITHMS, callback).sendToTarget();
        }

        @Override
        public void getDefaultAlgorithm(RemoteCallback callback) throws RemoteException {
            mHandlerCaller.obtainMessageO(MSG_GET_DEFAULT_ALGORITHM, callback).sendToTarget();
        }

        @Override
        public void getScores(RemoteCallback callback, String algorithmName, Bundle algorithmArgs,
                List<AutofillValue> actualValues, String[] userDataValues)
                        throws RemoteException {
            // TODO(b/70939974): refactor to use PooledLambda
            mHandlerCaller.obtainMessageOOOOO(MSG_GET_SCORES, callback, algorithmName,
                    algorithmArgs, actualValues, userDataValues).sendToTarget();
        }
    }


    // TODO(b/70939974): it might be simpler to remove this class and return the float[][] directly,
    // ignoring the request if the algorithm name is invalid.
    /**
     * Represents field classification scores used in a batch calculation.
     *
     * {@hide}
     */
    @SystemApi
    public static final class Scores implements Parcelable {
        private final String mAlgorithmName;
        private final float[][] mScores;

        /* @hide */
        public Scores(String algorithmName, int size1, int size2) {
            mAlgorithmName = algorithmName;
            mScores = new float[size1][size2];
        }

        public Scores(Parcel parcel) {
            mAlgorithmName = parcel.readString();
            final int size1 = parcel.readInt();
            final int size2 = parcel.readInt();
            mScores = new float[size1][size2];
            for (int i = 0; i < size1; i++) {
                for (int j = 0; j < size2; j++) {
                    mScores[i][j] = parcel.readFloat();
                }
            }
        }

        /**
         * Gets the name of algorithm used to calculate the score.
         */
        @NonNull
        public String getAlgorithm() {
            return mAlgorithmName;
        }

        /**
         * Gets the resulting scores, with the 1st dimension representing actual values and the 2nd
         * dimension values from {@link UserData}.
         */
        @NonNull
        public float[][] getScores() {
            return mScores;
        }

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

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(mAlgorithmName);
            int size1 = mScores.length;
            int size2 = mScores[0].length;
            parcel.writeInt(size1);
            parcel.writeInt(size2);
            for (int i = 0; i < size1; i++) {
                for (int j = 0; j < size2; j++) {
                    parcel.writeFloat(mScores[i][j]);
                }
            }
        }

        public static final Creator<Scores> CREATOR = new Creator<Scores>() {

            @Override
            public Scores createFromParcel(Parcel parcel) {
                return new Scores(parcel);
            }

            @Override
            public Scores[] newArray(int size) {
                return new Scores[size];
            }

        };
    }
}
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.os.Bundle;
import android.os.RemoteCallback;
import android.view.autofill.AutofillValue;
import java.util.List;

/**
 * Service used to calculate match scores for Autofill Field Classification.
 *
 * @hide
 */
oneway interface IAutofillFieldClassificationService {
    void getAvailableAlgorithms(in RemoteCallback callback);
    void getDefaultAlgorithm(in RemoteCallback callback);
    void getScores(in RemoteCallback callback, String algorithmName, in Bundle algorithmArgs,
                  in List<AutofillValue> actualValues, in String[] userDataValues);
}
Loading