Merge "Provide AutofillService to know how the dataset was shown to user" into tm-dev
This commit is contained in:
@@ -38201,6 +38201,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
|
||||
@@ -38214,6 +38215,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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user