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
|
// Then use the results, asynchronously
|
||||||
final RemoteCallback callback = new RemoteCallback((result) -> {
|
final RemoteCallback callback = new RemoteCallback(
|
||||||
if (result == null) {
|
new LogFieldClassificationScoreOnResultListener(
|
||||||
if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
|
this,
|
||||||
logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
|
saveDialogNotShowReason,
|
||||||
return;
|
commitReason,
|
||||||
}
|
viewsSize,
|
||||||
final Scores scores = result.getParcelable(EXTRA_SCORES, android.service.autofill.AutofillFieldClassificationService.Scores.class);
|
autofillIds,
|
||||||
if (scores == null) {
|
userValues,
|
||||||
Slog.w(TAG, "No field classification score on " + result);
|
categoryIds,
|
||||||
return;
|
detectedFieldIds,
|
||||||
}
|
detectedFieldClassifications));
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
|
fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
|
||||||
defaultAlgorithm, defaultArgs, algorithms, args);
|
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}
|
* Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN}
|
||||||
* when necessary.
|
* when necessary.
|
||||||
|
|||||||
Reference in New Issue
Block a user