Merge "Add a new Autofill FillEvent - for when the user taps a field. Test: atest android.autofillservice.cts.inline.InlineFillEventHistoryTest" into udc-dev

This commit is contained in:
Tim Yu
2023-03-02 23:22:01 +00:00
committed by Android (Google) Code Review
4 changed files with 92 additions and 3 deletions

View File

@@ -39862,6 +39862,7 @@ package android.service.autofill {
field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1 field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6
field public static final int UI_TYPE_DIALOG = 3; // 0x3 field public static final int UI_TYPE_DIALOG = 3; // 0x3
field public static final int UI_TYPE_INLINE = 2; // 0x2 field public static final int UI_TYPE_INLINE = 2; // 0x2
field public static final int UI_TYPE_MENU = 1; // 0x1 field public static final int UI_TYPE_MENU = 1; // 0x1

View File

@@ -233,6 +233,22 @@ public final class FillEventHistory implements Parcelable {
*/ */
public static final int TYPE_DATASETS_SHOWN = 5; public static final int TYPE_DATASETS_SHOWN = 5;
/**
* The app/user requested for a field to be Autofilled.
*
* This event is fired when the view has been entered (by user or app) in order
* to differentiate from FillRequests that have been pretriggered for FillDialogs.
*
* For example, the user might navigate away from a screen without tapping any
* fields. In this case, a FillRequest/FillResponse has been generated, but was
* not used for Autofilling. The user did not intend to see an Autofill result,
* but a FillRequest was still generated. This is different from when the user
* did tap on a field after the pretriggered FillRequest, this event will appear
* in the FillEventHistory, signaling that the user did intend to Autofill
* something.
*/
public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6;
/** @hide */ /** @hide */
@IntDef(prefix = { "TYPE_" }, value = { @IntDef(prefix = { "TYPE_" }, value = {
TYPE_DATASET_SELECTED, TYPE_DATASET_SELECTED,
@@ -240,7 +256,8 @@ public final class FillEventHistory implements Parcelable {
TYPE_AUTHENTICATION_SELECTED, TYPE_AUTHENTICATION_SELECTED,
TYPE_SAVE_SHOWN, TYPE_SAVE_SHOWN,
TYPE_CONTEXT_COMMITTED, TYPE_CONTEXT_COMMITTED,
TYPE_DATASETS_SHOWN TYPE_DATASETS_SHOWN,
TYPE_VIEW_REQUESTED_AUTOFILL
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@interface EventIds{} @interface EventIds{}
@@ -659,8 +676,8 @@ public final class FillEventHistory implements Parcelable {
@Nullable AutofillId[] detectedFieldIds, @Nullable AutofillId[] detectedFieldIds,
@Nullable FieldClassification[] detectedFieldClassifications, @Nullable FieldClassification[] detectedFieldClassifications,
int saveDialogNotShowReason, int uiType) { int saveDialogNotShowReason, int uiType) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN, mEventType = Preconditions.checkArgumentInRange(eventType, 0,
"eventType"); TYPE_VIEW_REQUESTED_AUTOFILL, "eventType");
mDatasetId = datasetId; mDatasetId = datasetId;
mClientState = clientState; mClientState = clientState;
mSelectedDatasetIds = selectedDatasetIds; mSelectedDatasetIds = selectedDatasetIds;
@@ -723,6 +740,8 @@ public final class FillEventHistory implements Parcelable {
return "TYPE_CONTEXT_COMMITTED"; return "TYPE_CONTEXT_COMMITTED";
case TYPE_DATASETS_SHOWN: case TYPE_DATASETS_SHOWN:
return "TYPE_DATASETS_SHOWN"; return "TYPE_DATASETS_SHOWN";
case TYPE_VIEW_REQUESTED_AUTOFILL:
return "TYPE_VIEW_REQUESTED_AUTOFILL";
default: default:
return "TYPE_UNKNOWN"; return "TYPE_UNKNOWN";
} }

View File

@@ -849,6 +849,32 @@ final class AutofillManagerServiceImpl
} }
} }
/**
* Updates the last fill response when a view was entered.
*/
void logViewEntered(int sessionId, @Nullable Bundle clientState) {
synchronized (mLock) {
if (!isValidEventLocked("logViewEntered", sessionId)) {
return;
}
if (mEventHistory.getEvents() != null) {
// Do not log this event more than once
for (Event event : mEventHistory.getEvents()) {
if (event.getType() == Event.TYPE_VIEW_REQUESTED_AUTOFILL) {
Slog.v(TAG, "logViewEntered: already logged TYPE_VIEW_REQUESTED_AUTOFILL");
return;
}
}
}
mEventHistory.addEvent(
new Event(Event.TYPE_VIEW_REQUESTED_AUTOFILL, null, clientState, null,
null, null, null, null, null, null, null));
}
}
void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset, void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
@Nullable Bundle clientState) { @Nullable Bundle clientState) {
synchronized (mLock) { synchronized (mLock) {

View File

@@ -441,6 +441,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@GuardedBy("mLock") @GuardedBy("mLock")
private boolean mPreviouslyFillDialogPotentiallyStarted; private boolean mPreviouslyFillDialogPotentiallyStarted;
/**
* Keeps track of if the user entered view, this is used to
* distinguish Fill Request that did not have user interaction
* with ones that did.
*
* This is set to true when entering view - after FillDialog FillRequest
* or on plain user tap.
*/
@NonNull
@GuardedBy("mLock")
private boolean mLogViewEntered;
/** /**
* Keeps the fill dialog trigger ids of the last response. This invalidates * Keeps the fill dialog trigger ids of the last response. This invalidates
* the trigger ids of the previous response. * the trigger ids of the previous response.
@@ -1289,6 +1301,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags)); .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
mLogViewEntered = false;
} }
/** /**
@@ -1413,6 +1426,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.setLastResponse(id, response); mService.setLastResponse(id, response);
synchronized (mLock) {
if (mLogViewEntered) {
mLogViewEntered = false;
mService.logViewEntered(id, null);
}
}
final long disableDuration = response.getDisableDuration(); final long disableDuration = response.getDisableDuration();
final boolean autofillDisabled = disableDuration > 0; final boolean autofillDisabled = disableDuration > 0;
if (autofillDisabled) { if (autofillDisabled) {
@@ -3545,6 +3566,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return; return;
} }
synchronized (mLock) {
if (!mLogViewEntered) {
// If the current request is for FillDialog (preemptive)
// then this is the first time that the view is entered
// (mLogViewEntered == false) in this case, setLastResponse()
// has already been called, so just log here.
// If the current request is not and (mLogViewEntered == false)
// then the last session is being tracked (setLastResponse not called)
// so this calling logViewEntered will be a nop.
// Calling logViewEntered() twice will only log it once
// TODO(271181979): this is broken for multiple partitions
mService.logViewEntered(this.id, null);
}
// If this is the first time view is entered for inline, the last
// session is still being tracked, so logViewEntered() needs
// to be delayed until setLastResponse is called.
// For fill dialog requests case logViewEntered is already called above
// so this will do nothing. Assumption: only one fill dialog per session
mLogViewEntered = true;
}
// Previously, fill request will only start whenever a view is entered. // Previously, fill request will only start whenever a view is entered.
// With Fill Dialog, request starts prior to view getting entered. So, we can't end // With Fill Dialog, request starts prior to view getting entered. So, we can't end
// the event at this moment, otherwise we will be wrongly attributing fill dialog // the event at this moment, otherwise we will be wrongly attributing fill dialog