Merge "Rewrite field classification remote callback" into udc-dev
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 com.android.server.autofill;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.service.autofill.FieldClassification;
|
||||
import android.service.autofill.FillEventHistory.Event.NoSaveReason;
|
||||
import android.util.Slog;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.AutofillManager.AutofillCommitReason;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class LogFieldClassificationScoreOnResultListener implements
|
||||
RemoteCallback.OnResultListener {
|
||||
|
||||
private static final String TAG = "LogFieldClassificationScoreOnResultListener";
|
||||
|
||||
private Session mSession;
|
||||
private final @NoSaveReason int mSaveDialogNotShowReason;
|
||||
private final @AutofillCommitReason int mCommitReason;
|
||||
private final int mViewsSize;
|
||||
private final AutofillId[] mAutofillIds;
|
||||
private final String[] mUserValues;
|
||||
private final String[] mCategoryIds;
|
||||
private final ArrayList<AutofillId> mDetectedFieldIds;
|
||||
private final ArrayList<FieldClassification> mDetectedFieldClassifications;
|
||||
LogFieldClassificationScoreOnResultListener(Session session,
|
||||
int saveDialogNotShowReason,
|
||||
int commitReason, int viewsSize, AutofillId[] autofillIds, String[] userValues,
|
||||
String[] categoryIds, ArrayList<AutofillId> detectedFieldIds,
|
||||
ArrayList<FieldClassification> detectedFieldClassifications) {
|
||||
this.mSession = session;
|
||||
this.mSaveDialogNotShowReason = saveDialogNotShowReason;
|
||||
this.mCommitReason = commitReason;
|
||||
this.mViewsSize = viewsSize;
|
||||
this.mAutofillIds = autofillIds;
|
||||
this.mUserValues = userValues;
|
||||
this.mCategoryIds = categoryIds;
|
||||
this.mDetectedFieldIds = detectedFieldIds;
|
||||
this.mDetectedFieldClassifications = detectedFieldClassifications;
|
||||
}
|
||||
|
||||
public void onResult(@Nullable Bundle result) {
|
||||
// Create a local copy to safe guard race condition
|
||||
Session session = mSession;
|
||||
if (session == null) {
|
||||
Slog.wtf(TAG, "session is null when calling onResult()");
|
||||
return;
|
||||
}
|
||||
session.handleLogFieldClassificationScore(
|
||||
result,
|
||||
mSaveDialogNotShowReason,
|
||||
mCommitReason,
|
||||
mViewsSize,
|
||||
mAutofillIds,
|
||||
mUserValues,
|
||||
mCategoryIds,
|
||||
mDetectedFieldIds,
|
||||
mDetectedFieldClassifications);
|
||||
mSession = null;
|
||||
}
|
||||
}
|
||||
@@ -3063,78 +3063,93 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
|
||||
// Then use the results, asynchronously
|
||||
final RemoteCallback callback = new RemoteCallback((result) -> {
|
||||
if (result == null) {
|
||||
if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
|
||||
logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
|
||||
return;
|
||||
}
|
||||
final Scores scores = result.getParcelable(EXTRA_SCORES, android.service.autofill.AutofillFieldClassificationService.Scores.class);
|
||||
if (scores == null) {
|
||||
Slog.w(TAG, "No field classification score on " + result);
|
||||
return;
|
||||
}
|
||||
int i = 0, j = 0;
|
||||
try {
|
||||
// Iteract over all autofill fields first
|
||||
for (i = 0; i < viewsSize; i++) {
|
||||
final AutofillId autofillId = autofillIds[i];
|
||||
|
||||
// Search the best scores for each category (as some categories could have
|
||||
// multiple user values
|
||||
ArrayMap<String, Float> scoresByField = null;
|
||||
for (j = 0; j < userValues.length; j++) {
|
||||
final String categoryId = categoryIds[j];
|
||||
final float score = scores.scores[i][j];
|
||||
if (score > 0) {
|
||||
if (scoresByField == null) {
|
||||
scoresByField = new ArrayMap<>(userValues.length);
|
||||
}
|
||||
final Float currentScore = scoresByField.get(categoryId);
|
||||
if (currentScore != null && currentScore > score) {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "skipping score " + score
|
||||
+ " because it's less than " + currentScore);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
|
||||
+ autofillId);
|
||||
}
|
||||
scoresByField.put(categoryId, score);
|
||||
} else if (sVerbose) {
|
||||
Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
|
||||
}
|
||||
}
|
||||
if (scoresByField == null) {
|
||||
if (sVerbose) Slog.v(TAG, "no score for autofillId=" + autofillId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Then create the matches for that autofill id
|
||||
final ArrayList<Match> matches = new ArrayList<>(scoresByField.size());
|
||||
for (j = 0; j < scoresByField.size(); j++) {
|
||||
final String fieldId = scoresByField.keyAt(j);
|
||||
final float score = scoresByField.valueAt(j);
|
||||
matches.add(new Match(fieldId, score));
|
||||
}
|
||||
detectedFieldIds.add(autofillId);
|
||||
detectedFieldClassifications.add(new FieldClassification(matches));
|
||||
} // for i
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
|
||||
return;
|
||||
}
|
||||
|
||||
logContextCommitted(detectedFieldIds, detectedFieldClassifications,
|
||||
saveDialogNotShowReason, commitReason);
|
||||
});
|
||||
final RemoteCallback callback = new RemoteCallback(
|
||||
new LogFieldClassificationScoreOnResultListener(
|
||||
this,
|
||||
saveDialogNotShowReason,
|
||||
commitReason,
|
||||
viewsSize,
|
||||
autofillIds,
|
||||
userValues,
|
||||
categoryIds,
|
||||
detectedFieldIds,
|
||||
detectedFieldClassifications));
|
||||
|
||||
fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
|
||||
defaultAlgorithm, defaultArgs, algorithms, args);
|
||||
}
|
||||
|
||||
void handleLogFieldClassificationScore(@Nullable Bundle result, int saveDialogNotShowReason,
|
||||
int commitReason, int viewsSize, AutofillId[] autofillIds, String[] userValues,
|
||||
String[] categoryIds, ArrayList<AutofillId> detectedFieldIds,
|
||||
ArrayList<FieldClassification> detectedFieldClassifications) {
|
||||
if (result == null) {
|
||||
if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
|
||||
logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
|
||||
return;
|
||||
}
|
||||
final Scores scores = result.getParcelable(EXTRA_SCORES,
|
||||
android.service.autofill.AutofillFieldClassificationService.Scores.class);
|
||||
if (scores == null) {
|
||||
Slog.w(TAG, "No field classification score on " + result);
|
||||
return;
|
||||
}
|
||||
int i = 0, j = 0;
|
||||
try {
|
||||
// Iteract over all autofill fields first
|
||||
for (i = 0; i < viewsSize; i++) {
|
||||
final AutofillId autofillId = autofillIds[i];
|
||||
|
||||
// Search the best scores for each category (as some categories could have
|
||||
// multiple user values
|
||||
ArrayMap<String, Float> scoresByField = null;
|
||||
for (j = 0; j < userValues.length; j++) {
|
||||
final String categoryId = categoryIds[j];
|
||||
final float score = scores.scores[i][j];
|
||||
if (score > 0) {
|
||||
if (scoresByField == null) {
|
||||
scoresByField = new ArrayMap<>(userValues.length);
|
||||
}
|
||||
final Float currentScore = scoresByField.get(categoryId);
|
||||
if (currentScore != null && currentScore > score) {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "skipping score " + score
|
||||
+ " because it's less than " + currentScore);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
|
||||
+ autofillId);
|
||||
}
|
||||
scoresByField.put(categoryId, score);
|
||||
} else if (sVerbose) {
|
||||
Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
|
||||
}
|
||||
}
|
||||
if (scoresByField == null) {
|
||||
if (sVerbose) Slog.v(TAG, "no score for autofillId=" + autofillId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Then create the matches for that autofill id
|
||||
final ArrayList<Match> matches = new ArrayList<>(scoresByField.size());
|
||||
for (j = 0; j < scoresByField.size(); j++) {
|
||||
final String fieldId = scoresByField.keyAt(j);
|
||||
final float score = scoresByField.valueAt(j);
|
||||
matches.add(new Match(fieldId, score));
|
||||
}
|
||||
detectedFieldIds.add(autofillId);
|
||||
detectedFieldClassifications.add(new FieldClassification(matches));
|
||||
} // for i
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
|
||||
return;
|
||||
}
|
||||
logContextCommitted(detectedFieldIds, detectedFieldClassifications,
|
||||
saveDialogNotShowReason, commitReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN}
|
||||
* when necessary.
|
||||
|
||||
Reference in New Issue
Block a user