Provide AutofillService to know how the dataset was shown to user

We introduce a filed for ui presentation in FillEventHistory.Event,
the type will be set for TYPE_DATASET_SHOWN and TYPE_DATASET_SELECTED.
The AutofillService can know which dataset is shown to user and which
type dataset user is clicked.

This change defines the definition and apply to TYPE_DATASET_SHOWN,
the TYPE_DATASET_SELECTED will be implemented on the follow up
change.

Bug: 223472350
Test: manual. build and boot pass. Test app and see dumpsys autofill
CTS-Coverage-Bug: 225310516

Change-Id: Ic221bd79e2ad512db5cd1ef8fd96c6bfae2ca616
This commit is contained in:
Joanne Chung
2022-03-17 17:48:46 +08:00
committed by skxu
parent faaf198328
commit f9fafbe617
4 changed files with 149 additions and 12 deletions

View File

@@ -38205,6 +38205,7 @@ package android.service.autofill {
method public int getNoSaveUiReason();
method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
method public int getType();
method public int getUiType();
field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6
field public static final int NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED = 5; // 0x5
field public static final int NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED = 3; // 0x3
@@ -38218,6 +38219,10 @@ package android.service.autofill {
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_SAVE_SHOWN = 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_MENU = 1; // 0x1
field public static final int UI_TYPE_UNKNOWN = 0; // 0x0
}
public final class FillRequest implements android.os.Parcelable {

View File

@@ -160,6 +160,7 @@ public final class FillEventHistory implements Parcelable {
event.mDetectedFieldClassifications);
}
parcel.writeInt(event.mSaveDialogNotShowReason);
parcel.writeInt(event.mUiType);
}
}
}
@@ -278,6 +279,29 @@ public final class FillEventHistory implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface NoSaveReason{}
/** The autofill suggestion presentation is unknown, this will be set for the event
* that is unrelated to fill Ui presentation */
public static final int UI_TYPE_UNKNOWN = 0;
/** The autofill suggestion is shown as a menu popup presentation. */
public static final int UI_TYPE_MENU = 1;
/** The autofill suggestion is shown as a keyboard inline presentation. */
public static final int UI_TYPE_INLINE = 2;
/** The autofill suggestion is shown as a dialog presentation. */
public static final int UI_TYPE_DIALOG = 3;
/** @hide */
@IntDef(prefix = { "UI_TYPE_" }, value = {
UI_TYPE_UNKNOWN,
UI_TYPE_MENU,
UI_TYPE_INLINE,
UI_TYPE_DIALOG
})
@Retention(RetentionPolicy.SOURCE)
public @interface UiType {}
@EventIds private final int mEventType;
@Nullable private final String mDatasetId;
@Nullable private final Bundle mClientState;
@@ -298,6 +322,10 @@ public final class FillEventHistory implements Parcelable {
@NoSaveReason private final int mSaveDialogNotShowReason;
@UiType
private final int mUiType;
/**
* Returns the type of the event.
*
@@ -497,6 +525,21 @@ public final class FillEventHistory implements Parcelable {
return mSaveDialogNotShowReason;
}
/**
* Returns fill suggestion ui presentation type which corresponds to types
* defined in {@link android.service.autofill.Presentations).
*
* <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN} and
* {@link #TYPE_DATASET_SELECTED}. For the other event types, the type is set to
* {@link #UI_TYPE_UNKNOWN }.
*
* @return The ui presentation type shown for user.
*/
@UiType
public int getUiType() {
return mUiType;
}
/**
* Creates a new event.
*
@@ -573,6 +616,49 @@ public final class FillEventHistory implements Parcelable {
@Nullable AutofillId[] detectedFieldIds,
@Nullable FieldClassification[] detectedFieldClassifications,
int saveDialogNotShowReason) {
this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds,
changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
saveDialogNotShowReason, UI_TYPE_UNKNOWN);
}
/**
* Creates a new event.
*
* @param eventType The type of the event
* @param datasetId The dataset the event was on, or {@code null} if the event was on the
* whole response.
* @param clientState The client state associated with the event.
* @param selectedDatasetIds The ids of datasets selected by the user.
* @param ignoredDatasetIds The ids of datasets NOT select by the user.
* @param changedFieldIds The ids of fields changed by the user.
* @param changedDatasetIds The ids of the datasets that havd values matching the
* respective entry on {@code changedFieldIds}.
* @param manuallyFilledFieldIds The ids of fields that were manually entered by the user
* and belonged to datasets.
* @param manuallyFilledDatasetIds The ids of datasets that had values matching the
* respective entry on {@code manuallyFilledFieldIds}.
* @param detectedFieldClassifications the field classification matches.
* @param saveDialogNotShowReason The reason why a save dialog was not shown.
* @param uiType The ui presentation type for fill suggestion.
*
* @throws IllegalArgumentException If the length of {@code changedFieldIds} and
* {@code changedDatasetIds} doesn't match.
* @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
* {@code manuallyFilledDatasetIds} doesn't match.
*
* @hide
*/
public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
@Nullable List<String> selectedDatasetIds,
@Nullable ArraySet<String> ignoredDatasetIds,
@Nullable ArrayList<AutofillId> changedFieldIds,
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
@Nullable AutofillId[] detectedFieldIds,
@Nullable FieldClassification[] detectedFieldClassifications,
int saveDialogNotShowReason, int uiType) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN,
"eventType");
mDatasetId = datasetId;
@@ -581,16 +667,16 @@ public final class FillEventHistory implements Parcelable {
mIgnoredDatasetIds = ignoredDatasetIds;
if (changedFieldIds != null) {
Preconditions.checkArgument(!ArrayUtils.isEmpty(changedFieldIds)
&& changedDatasetIds != null
&& changedFieldIds.size() == changedDatasetIds.size(),
&& changedDatasetIds != null
&& changedFieldIds.size() == changedDatasetIds.size(),
"changed ids must have same length and not be empty");
}
mChangedFieldIds = changedFieldIds;
mChangedDatasetIds = changedDatasetIds;
if (manuallyFilledFieldIds != null) {
Preconditions.checkArgument(!ArrayUtils.isEmpty(manuallyFilledFieldIds)
&& manuallyFilledDatasetIds != null
&& manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
&& manuallyFilledDatasetIds != null
&& manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
"manually filled ids must have same length and not be empty");
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
@@ -602,12 +688,14 @@ public final class FillEventHistory implements Parcelable {
mSaveDialogNotShowReason = Preconditions.checkArgumentInRange(saveDialogNotShowReason,
NO_SAVE_UI_REASON_NONE, NO_SAVE_UI_REASON_DATASET_MATCH,
"saveDialogNotShowReason");
mUiType = uiType;
}
@Override
public String toString() {
return "FillEvent [datasetId=" + mDatasetId
+ ", type=" + mEventType
+ ", type=" + eventToString(mEventType)
+ ", uiType=" + uiTypeToString(mUiType)
+ ", selectedDatasets=" + mSelectedDatasetIds
+ ", ignoredDatasetIds=" + mIgnoredDatasetIds
+ ", changedFieldIds=" + mChangedFieldIds
@@ -620,6 +708,38 @@ public final class FillEventHistory implements Parcelable {
+ ", saveDialogNotShowReason=" + mSaveDialogNotShowReason
+ "]";
}
private static String eventToString(int eventType) {
switch (eventType) {
case TYPE_DATASET_SELECTED:
return "TYPE_DATASET_SELECTED";
case TYPE_DATASET_AUTHENTICATION_SELECTED:
return "TYPE_DATASET_AUTHENTICATION_SELECTED";
case TYPE_AUTHENTICATION_SELECTED:
return "TYPE_AUTHENTICATION_SELECTED";
case TYPE_SAVE_SHOWN:
return "TYPE_SAVE_SHOWN";
case TYPE_CONTEXT_COMMITTED:
return "TYPE_CONTEXT_COMMITTED";
case TYPE_DATASETS_SHOWN:
return "TYPE_DATASETS_SHOWN";
default:
return "TYPE_UNKNOWN";
}
}
private static String uiTypeToString(int uiType) {
switch (uiType) {
case UI_TYPE_MENU:
return "UI_TYPE_MENU";
case UI_TYPE_INLINE:
return "UI_TYPE_INLINE";
case UI_TYPE_DIALOG:
return "UI_TYPE_FILL_DIALOG";
default:
return "UI_TYPE_UNKNOWN";
}
}
}
public static final @android.annotation.NonNull Parcelable.Creator<FillEventHistory> CREATOR =
@@ -660,13 +780,14 @@ public final class FillEventHistory implements Parcelable {
? FieldClassification.readArrayFromParcel(parcel)
: null;
final int saveDialogNotShowReason = parcel.readInt();
final int uiType = parcel.readInt();
selection.addEvent(new Event(eventType, datasetId, clientState,
selectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
detectedFieldIds, detectedFieldClassifications,
saveDialogNotShowReason));
saveDialogNotShowReason, uiType));
}
return selection;
}

View File

@@ -16,6 +16,8 @@
package com.android.server.autofill;
import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
@@ -816,12 +818,13 @@ final class AutofillManagerServiceImpl
/**
* Updates the last fill response when a dataset is shown.
*/
void logDatasetShown(int sessionId, @Nullable Bundle clientState) {
void logDatasetShown(int sessionId, @Nullable Bundle clientState, int presentationType) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetShown", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
null, null, null, null, null));
null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
presentationType));
}
}
}
@@ -858,9 +861,12 @@ final class AutofillManagerServiceImpl
|| mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
return;
}
// Augmented Autofill only logs for inline now, so set UI_TYPE_INLINE here.
// Ideally should not hardcode here and should also log for menu presentation.
mAugmentedAutofillEventHistory.addEvent(
new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
null, null, null, null, null));
null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
UI_TYPE_INLINE));
}
}

View File

@@ -18,6 +18,9 @@ package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
@@ -3290,7 +3293,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
synchronized (mLock) {
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
mService.logDatasetShown(id, mClientState);
mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
}
return;
}
@@ -3304,7 +3307,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
currentView.setState(ViewState.STATE_INLINE_SHOWN);
//TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
// rather than here where framework sends back the response.
mService.logDatasetShown(id, mClientState);
mService.logDatasetShown(id, mClientState, UI_TYPE_INLINE);
return;
}
}
@@ -3314,7 +3317,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.getServicePackageName(), mComponentName,
targetLabel, targetIcon, this, id, mCompatMode);
mService.logDatasetShown(id, mClientState);
synchronized (mLock) {
mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
}
synchronized (mLock) {
if (mUiShownTime == 0) {