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

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

Merge "Implemented multiple matches on FieldClassification.getMatches()"

parents e1055125 51f6cd70
Loading
Loading
Loading
Loading
+29 −10
Original line number Diff line number Diff line
@@ -25,8 +25,9 @@ import android.view.autofill.Helper;

import com.android.internal.util.Preconditions;

import com.google.android.collect.Lists;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
@@ -36,15 +37,24 @@ import java.util.List;
// TODO(b/70291841): let caller handle Parcelable...
public final class FieldClassification implements Parcelable {

    private final Match mMatch;
    private final ArrayList<Match> mMatches;

    /** @hide */
    public FieldClassification(@NonNull Match match) {
        mMatch = Preconditions.checkNotNull(match);
    public FieldClassification(@NonNull ArrayList<Match> matches) {
        mMatches = Preconditions.checkNotNull(matches);
        Collections.sort(mMatches, new Comparator<Match>() {
            @Override
            public int compare(Match o1, Match o2) {
                if (o1.mScore > o2.mScore) return -1;
                if (o1.mScore < o2.mScore) return 1;
                return 0;
            }}
        );
    }

    /**
     * Gets the {@link Match matches} with the highest {@link Match#getScore() scores}.
     * Gets the {@link Match matches} with the highest {@link Match#getScore() scores} (sorted in
     * descending order).
     *
     * <p><b>Note:</b> There's no guarantee of how many matches will be returned. In fact,
     * the Android System might return just the top match to minimize the impact of field
@@ -52,14 +62,14 @@ public final class FieldClassification implements Parcelable {
     */
    @NonNull
    public List<Match> getMatches() {
        return Lists.newArrayList(mMatch);
        return mMatches;
    }

    @Override
    public String toString() {
        if (!sDebug) return super.toString();

        return "FieldClassification: " + mMatch;
        return "FieldClassification: " + mMatches;
    }

    /////////////////////////////////////
@@ -73,7 +83,10 @@ public final class FieldClassification implements Parcelable {

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        mMatch.writeToParcel(parcel);
        parcel.writeInt(mMatches.size());
        for (int i = 0; i < mMatches.size(); i++) {
            mMatches.get(i).writeToParcel(parcel);
        }
    }

    public static final Parcelable.Creator<FieldClassification> CREATOR =
@@ -81,7 +94,13 @@ public final class FieldClassification implements Parcelable {

        @Override
        public FieldClassification createFromParcel(Parcel parcel) {
            return new FieldClassification(Match.readFromParcel(parcel));
            final int size = parcel.readInt();
            final ArrayList<Match> matches = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                matches.add(i, Match.readFromParcel(parcel));
            }

            return new FieldClassification(matches);
        }

        @Override
+15 −13
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.autofill.FieldClassification.Match;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -157,7 +156,7 @@ public final class FillEventHistory implements Parcelable {
                final AutofillId[] detectedFields = event.mDetectedFieldIds;
                parcel.writeParcelableArray(detectedFields, flags);
                if (detectedFields != null) {
                    Match.writeArrayToParcel(parcel, event.mDetectedMatches);
                    parcel.writeParcelableArray(event.mDetectedFieldClassifications, flags);
                }
            }
        }
@@ -251,7 +250,7 @@ public final class FillEventHistory implements Parcelable {
        @Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;

        @Nullable private final AutofillId[] mDetectedFieldIds;
        @Nullable private final Match[] mDetectedMatches;
        @Nullable private final FieldClassification[] mDetectedFieldClassifications;

        /**
         * Returns the type of the event.
@@ -370,11 +369,11 @@ public final class FillEventHistory implements Parcelable {
            final ArrayMap<AutofillId, FieldClassification> map = new ArrayMap<>(size);
            for (int i = 0; i < size; i++) {
                final AutofillId id = mDetectedFieldIds[i];
                final Match match = mDetectedMatches[i];
                final FieldClassification fc = mDetectedFieldClassifications[i];
                if (sVerbose) {
                    Log.v(TAG, "getFieldsClassification[" + i + "]: id=" + id + ", match=" + match);
                    Log.v(TAG, "getFieldsClassification[" + i + "]: id=" + id + ", fc=" + fc);
                }
                map.put(id, new FieldClassification(match));
                map.put(id, fc);
            }
            return map;
        }
@@ -455,7 +454,7 @@ 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.
         * @param detectedFieldClassifications the field classification matches.
         *
         * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
         * {@code changedDatasetIds} doesn't match.
@@ -471,7 +470,8 @@ public final class FillEventHistory implements Parcelable {
                @Nullable ArrayList<String> changedDatasetIds,
                @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
                @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                @Nullable AutofillId[] detectedFieldIds, @Nullable Match[] detectedMatches) {
                @Nullable AutofillId[] detectedFieldIds,
                @Nullable FieldClassification[] detectedFieldClassifications) {
            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
                    "eventType");
            mDatasetId = datasetId;
@@ -496,7 +496,7 @@ public final class FillEventHistory implements Parcelable {
            mManuallyFilledDatasetIds = manuallyFilledDatasetIds;

            mDetectedFieldIds = detectedFieldIds;
            mDetectedMatches = detectedMatches;
            mDetectedFieldClassifications = detectedFieldClassifications;
        }

        @Override
@@ -510,7 +510,8 @@ public final class FillEventHistory implements Parcelable {
                    + ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
                    + ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
                    + ", detectedFieldIds=" + Arrays.toString(mDetectedFieldIds)
                    + ", detectedMaches =" + Arrays.toString(mDetectedMatches)
                    + ", detectedFieldClassifications ="
                        + Arrays.toString(mDetectedFieldClassifications)
                    + "]";
        }
    }
@@ -548,15 +549,16 @@ public final class FillEventHistory implements Parcelable {
                        }
                        final AutofillId[] detectedFieldIds = parcel.readParcelableArray(null,
                                AutofillId.class);
                        final Match[] detectedMatches = (detectedFieldIds != null)
                                ? Match.readArrayFromParcel(parcel)
                        final FieldClassification[] detectedFieldClassifications =
                                (detectedFieldIds != null)
                                ? parcel.readParcelableArray(null, FieldClassification.class)
                                : null;

                        selection.addEvent(new Event(eventType, datasetId, clientState,
                                selectedDatasetIds, ignoredDatasets,
                                changedFieldIds, changedDatasetIds,
                                manuallyFilledFieldIds, manuallyFilledDatasetIds,
                                detectedFieldIds, detectedMatches));
                                detectedFieldIds, detectedFieldClassifications));
                    }
                    return selection;
                }
+25 −15
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
import android.service.autofill.FieldClassification;
import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillEventHistory;
import android.service.autofill.FillEventHistory.Event;
@@ -81,6 +82,7 @@ import com.android.server.autofill.ui.AutoFillUI;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
@@ -720,37 +722,45 @@ final class AutofillManagerServiceImpl {
            @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
            @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
            @Nullable ArrayList<AutofillId> detectedFieldIdsList,
            @Nullable ArrayList<Match> detectedMatchesList,
            @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
            @NonNull String appPackageName) {

        synchronized (mLock) {
            if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
                AutofillId[] detectedFieldsIds = null;
                Match[] detectedMatches = null;
                FieldClassification[] detectedFieldClassifications = null;
                if (detectedFieldIdsList != null) {
                    detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
                    detectedFieldIdsList.toArray(detectedFieldsIds);
                    detectedMatches = new Match[detectedMatchesList.size()];
                    detectedMatchesList.toArray(detectedMatches);
                    detectedFieldClassifications =
                            new FieldClassification[detectedFieldClassificationsList.size()];
                    detectedFieldClassificationsList.toArray(detectedFieldClassifications);

                    final int size = detectedMatchesList.size();
                    final int numberFields = detectedFieldsIds.length;
                    int totalSize = 0;
                    float totalScore = 0;
                    for (int i = 0; i < size; i++) {
                        totalScore += detectedMatches[i].getScore();
                    for (int i = 0; i < numberFields; i++) {
                        final FieldClassification fc = detectedFieldClassifications[i];
                        final List<Match> matches = fc.getMatches();
                        final int size = matches.size();
                        totalSize += size;
                        for (int j = 0; j < size; j++) {
                            totalScore += matches.get(j).getScore();
                        }
                    }
                    final int averageScore = (int) ((totalScore * 100) / size);
                    mMetricsLogger.write(
                            Helper.newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
                                    appPackageName, getServicePackageName())
                            .setCounterValue(size)
                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE, averageScore));

                    final int averageScore = (int) ((totalScore * 100) / totalSize);
                    mMetricsLogger.write(Helper
                            .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
                                    appPackageName, getServicePackageName())
                            .setCounterValue(numberFields)
                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
                                    averageScore));
                }
                mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
                        clientState, selectedDatasets, ignoredDatasets,
                        changedFieldIds, changedDatasetIds,
                        manuallyFilledFieldIds, manuallyFilledDatasetIds,
                        detectedFieldsIds, detectedMatches));
                        detectedFieldsIds, detectedFieldClassifications));
            }
        }
    }
+26 −21
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ import android.service.autofill.SaveRequest;
import android.service.autofill.UserData;
import android.service.autofill.ValueFinder;
import android.service.autofill.EditDistanceScorer;
import android.service.autofill.FieldClassification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
@@ -961,15 +962,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        final UserData userData = mService.getUserData();

        final ArrayList<AutofillId> detectedFieldIds;
        final ArrayList<Match> detectedMatches;
        final ArrayList<FieldClassification> detectedFieldClassifications;

        if (userData != null) {
            final int maxFieldsSize = UserData.getMaxFieldClassificationIdsSize();
            detectedFieldIds = new ArrayList<>(maxFieldsSize);
            detectedMatches = new ArrayList<>(maxFieldsSize);
            detectedFieldClassifications = new ArrayList<>(maxFieldsSize);
        } else {
            detectedFieldIds = null;
            detectedMatches = null;
            detectedFieldClassifications = null;
        }

        for (int i = 0; i < mViewStates.size(); i++) {
@@ -1078,8 +1079,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState

                    // Sets field classification score for field
                    if (userData!= null) {
                        setScore(detectedFieldIds, detectedMatches, userData, viewState.id,
                                currentValue);
                        setScore(detectedFieldIds, detectedFieldClassifications, userData,
                                viewState.id, currentValue);
                    }
                } // else
            } // else
@@ -1093,7 +1094,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    + ", changedDatasetIds=" + changedDatasetIds
                    + ", manuallyFilledIds=" + manuallyFilledIds
                    + ", detectedFieldIds=" + detectedFieldIds
                    + ", detectedMatches=" + detectedMatches
                    + ", detectedFieldClassifications=" + detectedFieldClassifications
                    );
        }

@@ -1116,16 +1117,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
                changedFieldIds, changedDatasetIds,
                manuallyFilledFieldIds, manuallyFilledDatasetIds,
                detectedFieldIds, detectedMatches, mComponentName.getPackageName());
                detectedFieldIds, detectedFieldClassifications, mComponentName.getPackageName());
    }

    /**
     * Adds the top score match to {@code detectedFieldsIds} and {@code detectedMatches} for
     * Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
     * {@code fieldId} based on its {@code currentValue} and {@code userData}.
     */
    private static void setScore(@NonNull ArrayList<AutofillId> detectedFieldIds,
            @NonNull ArrayList<Match> detectedMatches, @NonNull UserData userData,
            @NonNull AutofillId fieldId, @NonNull AutofillValue currentValue) {
            @NonNull ArrayList<FieldClassification> detectedFieldClassifications,
            @NonNull UserData userData, @NonNull AutofillId fieldId,
            @NonNull AutofillValue currentValue) {

        final String[] userValues = userData.getValues();
        final String[] remoteIds = userData.getRemoteIds();
@@ -1138,23 +1140,26 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    + valuesLength + ", ids.length = " + idsLength);
            return;
        }
        String remoteId = null;
        float topScore = 0;

        ArrayList<Match> matches = null;
        for (int i = 0; i < userValues.length; i++) {
            String remoteId = remoteIds[i];
            final String value = userValues[i];
            final float score = userData.getScorer().getScore(currentValue, value);
            if (score > topScore) {
                topScore = score;
                remoteId = remoteIds[i];
            if (score > 0) {
                if (sVerbose) {
                    Slog.v(TAG, "adding score " + score + " at index " + i + " and id " + fieldId);
                }
                if (matches == null) {
                    matches = new ArrayList<>(userValues.length);
                }

        if (remoteId != null && topScore > 0) {
            if (sVerbose) Slog.v(TAG, "setScores(): top score for #" + fieldId + " is " + topScore);
                matches.add(new Match(remoteId, score));
            }
            else if (sVerbose) Slog.v(TAG, "skipping score 0 at index " + i + " and id " + fieldId);
        }
        if (matches != null) {
            detectedFieldIds.add(fieldId);
            detectedMatches.add(new Match(remoteId, topScore));
        } else if (sVerbose) {
            Slog.v(TAG, "setScores(): no top score for #" + fieldId + ": " + topScore);
            detectedFieldClassifications.add(new FieldClassification(matches));
        }
    }