Refactored the FieldsClassification score mechanism.

Before, FillEvent.getFieldsClassification() returned a map of remote ids and
scores. Now, it returns a Map of FieldClassication by AutofillId, which allows
multiple fields and scores for multiple user datas (although the initial
implementation supports only the top match for a field).

This is mostly a refactoring CL, as the implementation is still saving just one
user data entry and one field. But full support is coming next...

Test: atest CtsAutoFillServiceTestCases:FieldsClassificationTest
Test: atest CtsAutoFillServiceTestCases:UserDataTest
Test: atest CtsAutoFillServiceTestCases:FieldsClassificationScorerTest

Bug: 68045531

Change-Id: I08b29f24efbd527216f9bce2343e1bcd4b4554c0
diff --git a/api/test-current.txt b/api/test-current.txt
index 5cbefb2..52c1731 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -457,8 +457,27 @@
     method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
   }
 
+  public final class FieldClassification implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.service.autofill.FieldClassification.Match getTopMatch();
+    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 int getScore();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification.Match> CREATOR;
+  }
+
+  public final class FieldsClassificationScorer {
+    method public static int getScore(android.view.autofill.AutofillValue, java.lang.String);
+  }
+
   public static final class FillEventHistory.Event {
-    method public java.util.Map<java.lang.String, java.lang.Integer> getFieldsClassification();
+    method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification();
   }
 
   public static final class FillResponse.Builder {
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
new file mode 100644
index 0000000..5d0c81c
--- /dev/null
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 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 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;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Gets the <a href="#FieldsClassification">fields classification</a> results for a given field.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - unhide / remove testApi
+ *
+ * @hide
+ */
+@TestApi
+public final class FieldClassification implements Parcelable {
+
+    private final Match mMatch;
+
+    /** @hide */
+    public FieldClassification(@NonNull Match match) {
+        mMatch = Preconditions.checkNotNull(match);
+    }
+
+    /**
+     * Gets the {@link Match} with the highest {@link Match#getScore() score} for the field.
+     */
+    @NonNull
+    public Match getTopMatch() {
+        return mMatch;
+    }
+
+    @Override
+    public String toString() {
+        if (!sDebug) return super.toString();
+
+        return "FieldClassification: " + mMatch;
+    }
+
+    /////////////////////////////////////
+    // Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mMatch, flags);
+    }
+
+    public static final Parcelable.Creator<FieldClassification> CREATOR =
+            new Parcelable.Creator<FieldClassification>() {
+
+        @Override
+        public FieldClassification createFromParcel(Parcel parcel) {
+            return new FieldClassification(parcel.readParcelable(null));
+        }
+
+        @Override
+        public FieldClassification[] newArray(int size) {
+            return new FieldClassification[size];
+        }
+    };
+
+    /**
+     * Gets the score of a {@link UserData} entry for the field.
+     *
+     * TODO(b/67867469):
+     * - improve javadoc
+     * - unhide / remove testApi
+     *
+     * @hide
+     */
+    @TestApi
+    public static final class Match implements Parcelable {
+
+        private final String mRemoteId;
+        private final int mScore;
+
+        /** @hide */
+        public Match(String remoteId, int score) {
+            mRemoteId = Preconditions.checkNotNull(remoteId);
+            mScore = score;
+        }
+
+        /**
+         * Gets the remote id of the {@link UserData} entry.
+         */
+        @NonNull
+        public String getRemoteId() {
+            return mRemoteId;
+        }
+
+        /**
+         * Gets a score between the value of this field and 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}:
+         * <ul>
+         *   <li>{@code 1000000} represents a full match ({@code 100.0000%}).
+         *   <li>{@code 0} represents a full mismatch ({@code 0.0000%}).
+         *   <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 1000000} if the algorithm trims the values.
+         *   <li>{@code 0} if the algorithm compares the values sequentially.
+         *   <li>{@code 750000} if the algorithm consideres that 3/4 (75%) of the characters match.
+         * </ul>
+         *
+         * <p>Currently, the autofill service cannot configure the algorithm.
+         */
+        public int getScore() {
+            return mScore;
+        }
+
+        @Override
+        public String toString() {
+            if (!sDebug) return super.toString();
+
+            final StringBuilder string = new StringBuilder("Match: remoteId=");
+            Helper.appendRedacted(string, mRemoteId);
+            return string.append(", score=").append(mScore).toString();
+        }
+
+        /////////////////////////////////////
+        // Parcelable "contract" methods. //
+        /////////////////////////////////////
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeString(mRemoteId);
+            parcel.writeInt(mScore);
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<Match> CREATOR = new Parcelable.Creator<Match>() {
+
+            @Override
+            public Match createFromParcel(Parcel parcel) {
+                return new Match(parcel.readString(), parcel.readInt());
+            }
+
+            @Override
+            public Match[] newArray(int size) {
+                return new Match[size];
+            }
+        };
+    }
+}
diff --git a/core/java/android/service/autofill/FieldsClassificationScorer.java b/core/java/android/service/autofill/FieldsClassificationScorer.java
new file mode 100644
index 0000000..fea8ebf
--- /dev/null
+++ b/core/java/android/service/autofill/FieldsClassificationScorer.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 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.NonNull;
+import android.annotation.TestApi;
+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.
+ *
+ * @hide
+ */
+@TestApi
+public final class FieldsClassificationScorer {
+
+    private static final int MAX_VALUE = 100_0000; // 100.0000%
+
+    /**
+     * Returns the classification score between an actual {@link AutofillValue} filled
+     * by the user and the expected value predicted by an autofill service.
+     *
+     * <p>A full-match is {@code 1000000} (representing 100.0000%), a full mismatch is {@code 0} and
+     * partial mathces are something in between, typically using edit-distance algorithms.
+     */
+    public static int getScore(@NonNull AutofillValue actualValue, @NonNull String userData) {
+        // TODO(b/67867469): implement edit distance - currently it's returning either 0 or 100%
+        if (actualValue == null || !actualValue.isText() || userData == null) return 0;
+        return actualValue.getTextValue().toString().equalsIgnoreCase(userData) ? MAX_VALUE : 0;
+    }
+
+    private FieldsClassificationScorer() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index eedb972..cf6f296 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -38,6 +38,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 /**
@@ -123,34 +124,35 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBundle(mClientState);
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeBundle(mClientState);
         if (mEvents == null) {
-            dest.writeInt(0);
+            parcel.writeInt(0);
         } else {
-            dest.writeInt(mEvents.size());
+            parcel.writeInt(mEvents.size());
 
             int numEvents = mEvents.size();
             for (int i = 0; i < numEvents; i++) {
                 Event event = mEvents.get(i);
-                dest.writeInt(event.mEventType);
-                dest.writeString(event.mDatasetId);
-                dest.writeBundle(event.mClientState);
-                dest.writeStringList(event.mSelectedDatasetIds);
-                dest.writeArraySet(event.mIgnoredDatasetIds);
-                dest.writeTypedList(event.mChangedFieldIds);
-                dest.writeStringList(event.mChangedDatasetIds);
+                parcel.writeInt(event.mEventType);
+                parcel.writeString(event.mDatasetId);
+                parcel.writeBundle(event.mClientState);
+                parcel.writeStringList(event.mSelectedDatasetIds);
+                parcel.writeArraySet(event.mIgnoredDatasetIds);
+                parcel.writeTypedList(event.mChangedFieldIds);
+                parcel.writeStringList(event.mChangedDatasetIds);
 
-                dest.writeTypedList(event.mManuallyFilledFieldIds);
+                parcel.writeTypedList(event.mManuallyFilledFieldIds);
                 if (event.mManuallyFilledFieldIds != null) {
                     final int size = event.mManuallyFilledFieldIds.size();
                     for (int j = 0; j < size; j++) {
-                        dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
+                        parcel.writeStringList(event.mManuallyFilledDatasetIds.get(j));
                     }
                 }
-                dest.writeString(event.mDetectedRemoteId);
+                parcel.writeParcelable(event.mDetectedFieldId, flags);
                 if (event.mDetectedRemoteId != null) {
-                    dest.writeInt(event.mDetectedFieldScore);
+                    parcel.writeString(event.mDetectedRemoteId);
+                    parcel.writeInt(event.mDetectedFieldScore);
                 }
             }
         }
@@ -242,6 +244,8 @@
         @Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
         @Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;
 
+        // TODO(b/67867469): store list of fields instead of hardcoding just one
+        @Nullable private final AutofillId mDetectedFieldId;
         @Nullable private final String mDetectedRemoteId;
         private final int mDetectedFieldScore;
 
@@ -347,37 +351,29 @@
         }
 
         /**
-         * 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 on
-         * {@link UserData.Builder#add(String, android.view.autofill.AutofillValue)}),
-         * or {@code null} if none of the user-input values
-         * matched the requested detection.
+         * Gets the <a href="#FieldsClassification">fields 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 detection}.
+         * fields classification}.
          *
          * TODO(b/67867469):
          *  - improve javadoc
-         *  - refine score meaning (for example, should 1 be different of -1?)
-         *  - mention when it's set
-         *  - unhide
          *  - unhide / remove testApi
-         *  - add @NonNull / check it / add unit tests
-         *  - add link to AutofillService #FieldsClassification anchor
          *
          * @hide
          */
         @TestApi
-        @NonNull public Map<String, Integer> getFieldsClassification() {
-            if (mDetectedRemoteId == null || mDetectedFieldScore == -1) {
+        @NonNull public Map<AutofillId, FieldClassification> getFieldsClassification() {
+            if (mDetectedFieldId == null || mDetectedRemoteId == null
+                    || mDetectedFieldScore == -1) {
                 return Collections.emptyMap();
             }
 
-            final ArrayMap<String, Integer> map = new ArrayMap<>(1);
-            map.put(mDetectedRemoteId, mDetectedFieldScore);
+            final ArrayMap<AutofillId, FieldClassification> map = new ArrayMap<>(1);
+            map.put(mDetectedFieldId,
+                    new FieldClassification(new FieldClassification.Match(
+                            mDetectedRemoteId, mDetectedFieldScore)));
             return map;
         }
 
@@ -464,7 +460,7 @@
          *
          * @hide
          */
-        // TODO(b/67867469): document detection field parameters once stable
+        // 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,
@@ -472,7 +468,7 @@
                 @Nullable ArrayList<String> changedDatasetIds,
                 @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
                 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-                @Nullable String detectedRemoteId, int detectedFieldScore) {
+                @Nullable Map<AutofillId, FieldClassification> fieldsClassification) {
             mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
                     "eventType");
             mDatasetId = datasetId;
@@ -495,8 +491,21 @@
             }
             mManuallyFilledFieldIds = manuallyFilledFieldIds;
             mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
-            mDetectedRemoteId = detectedRemoteId;
-            mDetectedFieldScore = detectedFieldScore;
+
+            // TODO(b/67867469): store list of fields instead of hardcoding just one
+            if (fieldsClassification == null) {
+                mDetectedFieldId = null;
+                mDetectedRemoteId = null;
+                mDetectedFieldScore = 0;
+
+            } else {
+                final Entry<AutofillId, FieldClassification> tmpEntry = fieldsClassification
+                        .entrySet().iterator().next();
+                final FieldClassification.Match tmpMatch = tmpEntry.getValue().getTopMatch();
+                mDetectedFieldId = tmpEntry.getKey();
+                mDetectedRemoteId = tmpMatch.getRemoteId();
+                mDetectedFieldScore = tmpMatch.getScore();
+            }
         }
 
         @Override
@@ -509,6 +518,7 @@
                     + ", changedDatasetsIds=" + mChangedDatasetIds
                     + ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
                     + ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
+                    + ", detectedFieldId=" + mDetectedFieldId
                     + ", detectedRemoteId=" + mDetectedRemoteId
                     + ", detectedFieldScore=" + mDetectedFieldScore
                     + "]";
@@ -546,15 +556,23 @@
                         } else {
                             manuallyFilledDatasetIds = null;
                         }
-                        final String detectedRemoteId = parcel.readString();
-                        final int detectedFieldScore = detectedRemoteId == null ? -1
-                                : parcel.readInt();
+                        // TODO(b/67867469): store list of fields instead of hardcoding just one
+                        ArrayMap<AutofillId, FieldClassification> fieldsClassification = null;
+                        final AutofillId detectedFieldId = parcel.readParcelable(null);
+                        if (detectedFieldId == null) {
+                            fieldsClassification = null;
+                        } else {
+                            fieldsClassification = new ArrayMap<AutofillId, FieldClassification>(1);
+                            fieldsClassification.put(detectedFieldId,
+                                    new FieldClassification(new FieldClassification.Match(
+                                            parcel.readString(), parcel.readInt())));
+                        }
 
                         selection.addEvent(new Event(eventType, datasetId, clientState,
                                 selectedDatasetIds, ignoredDatasets,
                                 changedFieldIds, changedDatasetIds,
                                 manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                                detectedRemoteId, detectedFieldScore));
+                                fieldsClassification));
                     }
                     return selection;
                 }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8b6dc20..77e8907 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -47,6 +47,7 @@
 import android.provider.Settings;
 import android.service.autofill.AutofillService;
 import android.service.autofill.AutofillServiceInfo;
+import android.service.autofill.FieldClassification;
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillEventHistory.Event;
 import android.service.autofill.FillResponse;
@@ -74,6 +75,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Map;
 import java.util.Random;
 
 /**
@@ -626,7 +628,7 @@
             if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
-                                null, null, null, null, null, -1));
+                                null, null, null, null, null));
             }
         }
     }
@@ -640,7 +642,7 @@
             if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
-                                clientState, null, null, null, null, null, null, null, -1));
+                                clientState, null, null, null, null, null, null, null));
             }
         }
     }
@@ -652,7 +654,7 @@
         synchronized (mLock) {
             if (isValidEventLocked("logSaveShown()", sessionId)) {
                 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
-                        null, null, null, null, null, null, -1));
+                        null, null, null, null, null, null));
             }
         }
     }
@@ -666,7 +668,7 @@
             if (isValidEventLocked("logDatasetSelected()", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
-                                null, null, null, null, null, null, -1));
+                                null, null, null, null, null, null));
             }
         }
     }
@@ -681,14 +683,15 @@
             @Nullable ArrayList<String> changedDatasetIds,
             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @Nullable String detectedRemoteId, int detectedFieldScore) {
+            @Nullable Map<AutofillId, FieldClassification> fieldsClassification) {
+
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
                 mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
                         clientState, selectedDatasets, ignoredDatasets,
                         changedFieldIds, changedDatasetIds,
                         manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                        detectedRemoteId, detectedFieldScore));
+                        fieldsClassification));
             }
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3615bca..106ac8f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -55,6 +55,7 @@
 import android.os.SystemClock;
 import android.service.autofill.AutofillService;
 import android.service.autofill.Dataset;
+import android.service.autofill.FieldClassification;
 import android.service.autofill.FillContext;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
@@ -64,6 +65,7 @@
 import android.service.autofill.SaveRequest;
 import android.service.autofill.UserData;
 import android.service.autofill.ValueFinder;
+import android.service.autofill.FieldsClassificationScorer;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
@@ -942,9 +944,12 @@
         }
 
         final UserData userData = mService.getUserData();
+        // TODO(b/67867469): support multiple fields / merge redundant variables below
         final AutofillId detectableFieldId;
         final String detectableRemoteId;
         String detectedRemoteId = null;
+        Map<AutofillId, FieldClassification> fieldsClassification = null;
+
         if (userData == null) {
             detectableFieldId = null;
             detectableRemoteId = null;
@@ -1063,17 +1068,19 @@
                     // Check if detectable field changed.
                     if (detectableFieldId != null && detectableFieldId.equals(viewState.id)
                             && currentValue.isText() && currentValue.getTextValue() != null) {
-                        final String actualValue = currentValue.getTextValue().toString();
                         // TODO(b/67867469): hardcoded to just first entry on initial refactoring.
-                        final String expectedValue = userData.getValues()[0];
-                        if (actualValue.equalsIgnoreCase(expectedValue)) {
+                        detectedFieldScore = FieldsClassificationScorer.getScore(currentValue,
+                                userData.getValues()[0]);
+                        if (detectedFieldScore > 0) {
                             detectedRemoteId = detectableRemoteId;
-                            detectedFieldScore = 0;
+                            fieldsClassification = new ArrayMap<AutofillId, FieldClassification>(1);
+                            fieldsClassification.put(detectableFieldId,
+                                    new FieldClassification(new FieldClassification.Match(
+                                            detectedRemoteId, detectedFieldScore)));
                         } else if (sVerbose) {
                             Slog.v(TAG, "Detection mismatch for field " + detectableFieldId);
                         }
-                        // TODO(b/67867469): set score on partial hits
-                    }
+                    } // if
                 } // else
             } // else
         }
@@ -1087,6 +1094,7 @@
                     + ", manuallyFilledIds=" + manuallyFilledIds
                     + ", detectableFieldId=" + detectableFieldId
                     + ", detectedFieldScore=" + detectedFieldScore
+                    + ", fieldsClassification=" + fieldsClassification
                     );
         }
 
@@ -1108,8 +1116,7 @@
 
         mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
                 changedFieldIds, changedDatasetIds,
-                manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                detectedRemoteId, detectedFieldScore);
+                manuallyFilledFieldIds, manuallyFilledDatasetIds, fieldsClassification);
     }
 
     /**