diff options
| author | 2020-09-17 05:17:42 +0800 | |
|---|---|---|
| committer | 2020-10-14 02:35:10 +0800 | |
| commit | 5518d64780b4bee7c44c9f672c1e2dd6fe2f2dde (patch) | |
| tree | 6c060d7db1d5b1769c03d78a9a2727c3b9363e6b | |
| parent | f2afb166d4dfcc3e6430da1edc97d2442b0a77de (diff) | |
Add the reason why a save dialog was not shown to FillEventHistory.
In order to provide a better user experience, it would better know the
reason why a save dialog was not shown and improve the autofill experience.
So it is necessary to add the reason why a save dialog was not shown to
FillEventHistory.
Bug: 158328375
Test: atest FillEventHistoryTest
Test: atest InlineFillEventHistoryTest
Change-Id: I50c1e40334066d3f4844426c4b03294079a967b2
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/service/autofill/FillEventHistory.java | 100 | ||||
| -rw-r--r-- | non-updatable-api/current.txt | 8 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java | 23 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/Session.java | 194 |
5 files changed, 295 insertions, 38 deletions
diff --git a/api/current.txt b/api/current.txt index 9b9e258f23a2..11ca10c5c873 100644 --- a/api/current.txt +++ b/api/current.txt @@ -43168,8 +43168,16 @@ package android.service.autofill { method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification(); method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds(); method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField(); + method public int getNoSaveReason(); method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds(); method public int getType(); + field public static final int NO_SAVE_REASON_DATASET_MATCH = 6; // 0x6 + field public static final int NO_SAVE_REASON_FIELD_VALIDATION_FAILED = 5; // 0x5 + field public static final int NO_SAVE_REASON_HAS_EMPTY_REQUIRED = 3; // 0x3 + field public static final int NO_SAVE_REASON_NONE = 0; // 0x0 + field public static final int NO_SAVE_REASON_NO_SAVE_INFO = 1; // 0x1 + field public static final int NO_SAVE_REASON_NO_VALUE_CHANGED = 4; // 0x4 + field public static final int NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG = 2; // 0x2 field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4 field public static final int TYPE_DATASETS_SHOWN = 5; // 0x5 diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index 1cd2d62ce55f..f2265281b140 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -159,6 +159,7 @@ public final class FillEventHistory implements Parcelable { FieldClassification.writeArrayToParcel(parcel, event.mDetectedFieldClassifications); } + parcel.writeInt(event.mSaveDialogNotShowReason); } } } @@ -243,6 +244,40 @@ public final class FillEventHistory implements Parcelable { @Retention(RetentionPolicy.SOURCE) @interface EventIds{} + /** No reason for save dialog. */ + public static final int NO_SAVE_REASON_NONE = 0; + + /** The SaveInfo associated with the FillResponse is null. */ + public static final int NO_SAVE_REASON_NO_SAVE_INFO = 1; + + /** The service asked to delay save. */ + public static final int NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG = 2; + + /** There was empty value for required ids. */ + public static final int NO_SAVE_REASON_HAS_EMPTY_REQUIRED = 3; + + /** No value has been changed. */ + public static final int NO_SAVE_REASON_NO_VALUE_CHANGED = 4; + + /** Fields failed validation. */ + public static final int NO_SAVE_REASON_FIELD_VALIDATION_FAILED = 5; + + /** All fields matched contents of datasets. */ + public static final int NO_SAVE_REASON_DATASET_MATCH = 6; + + /** @hide */ + @IntDef(prefix = { "NO_SAVE_REASON_" }, value = { + NO_SAVE_REASON_NONE, + NO_SAVE_REASON_NO_SAVE_INFO, + NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG, + NO_SAVE_REASON_HAS_EMPTY_REQUIRED, + NO_SAVE_REASON_NO_VALUE_CHANGED, + NO_SAVE_REASON_FIELD_VALIDATION_FAILED, + NO_SAVE_REASON_DATASET_MATCH + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NoSaveReason{} + @EventIds private final int mEventType; @Nullable private final String mDatasetId; @Nullable private final Bundle mClientState; @@ -261,6 +296,8 @@ public final class FillEventHistory implements Parcelable { @Nullable private final AutofillId[] mDetectedFieldIds; @Nullable private final FieldClassification[] mDetectedFieldClassifications; + @NoSaveReason private final int mSaveDialogNotShowReason; + /** * Returns the type of the event. * @@ -448,6 +485,18 @@ public final class FillEventHistory implements Parcelable { } /** + * Returns the reason why a save dialog was not shown. + * + * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}. For the other + * event types, the reason is set to NO_SAVE_REASON_NONE. + * + * @return The reason why a save dialog was not shown. + */ + public int getNoSaveReason() { + return mSaveDialogNotShowReason; + } + + /** * Creates a new event. * * @param eventType The type of the event @@ -481,6 +530,48 @@ public final class FillEventHistory implements Parcelable { @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @Nullable AutofillId[] detectedFieldIds, @Nullable FieldClassification[] detectedFieldClassifications) { + this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds, + changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, + manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications, + NO_SAVE_REASON_NONE); + } + + /** + * 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. + * + * @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) { mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN, "eventType"); mDatasetId = datasetId; @@ -506,6 +597,10 @@ public final class FillEventHistory implements Parcelable { mDetectedFieldIds = detectedFieldIds; mDetectedFieldClassifications = detectedFieldClassifications; + + mSaveDialogNotShowReason = Preconditions.checkArgumentInRange(saveDialogNotShowReason, + NO_SAVE_REASON_NONE, NO_SAVE_REASON_DATASET_MATCH, + "saveDialogNotShowReason"); } @Override @@ -521,6 +616,7 @@ public final class FillEventHistory implements Parcelable { + ", detectedFieldIds=" + Arrays.toString(mDetectedFieldIds) + ", detectedFieldClassifications =" + Arrays.toString(mDetectedFieldClassifications) + + ", saveDialogNotShowReason=" + mSaveDialogNotShowReason + "]"; } } @@ -562,12 +658,14 @@ public final class FillEventHistory implements Parcelable { (detectedFieldIds != null) ? FieldClassification.readArrayFromParcel(parcel) : null; + final int saveDialogNotShowReason = parcel.readInt(); selection.addEvent(new Event(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds, - detectedFieldIds, detectedFieldClassifications)); + detectedFieldIds, detectedFieldClassifications, + saveDialogNotShowReason)); } return selection; } diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index d62e132b5745..ff301b61e0c3 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -41311,8 +41311,16 @@ package android.service.autofill { method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification(); method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds(); method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField(); + method public int getNoSaveReason(); method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds(); method public int getType(); + field public static final int NO_SAVE_REASON_DATASET_MATCH = 6; // 0x6 + field public static final int NO_SAVE_REASON_FIELD_VALIDATION_FAILED = 5; // 0x5 + field public static final int NO_SAVE_REASON_HAS_EMPTY_REQUIRED = 3; // 0x3 + field public static final int NO_SAVE_REASON_NONE = 0; // 0x0 + field public static final int NO_SAVE_REASON_NO_SAVE_INFO = 1; // 0x1 + field public static final int NO_SAVE_REASON_NO_VALUE_CHANGED = 4; // 0x4 + field public static final int NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG = 2; // 0x2 field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4 field public static final int TYPE_DATASETS_SHOWN = 5; // 0x5 diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 57ffe0498a88..a6b82f41c124 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -55,6 +55,7 @@ import android.service.autofill.FieldClassification; import android.service.autofill.FieldClassification.Match; import android.service.autofill.FillEventHistory; import android.service.autofill.FillEventHistory.Event; +import android.service.autofill.FillEventHistory.Event.NoSaveReason; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.service.autofill.InlineSuggestionRenderService; @@ -429,9 +430,15 @@ final class AutofillManagerServiceImpl return; } - session.logContextCommitted(); + final Session.SaveResult saveResult = session.showSaveLocked(); - final boolean finished = session.showSaveLocked(); + session.logContextCommitted(saveResult.getNoSaveReason()); + + if (saveResult.isLogSaveShown()) { + session.logSaveUiShown(); + } + + final boolean finished = saveResult.isRemoveSession(); if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished); if (finished) { @@ -868,7 +875,9 @@ final class AutofillManagerServiceImpl @NonNull ComponentName appComponentName, boolean compatMode) { logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, - manuallyFilledDatasetIds, null, null, appComponentName, compatMode); + manuallyFilledDatasetIds, /* detectedFieldIdsList= */ null, + /* detectedFieldClassificationsList= */ null, appComponentName, compatMode, + Event.NO_SAVE_REASON_NONE); } @GuardedBy("mLock") @@ -881,7 +890,8 @@ final class AutofillManagerServiceImpl @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @Nullable ArrayList<AutofillId> detectedFieldIdsList, @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList, - @NonNull ComponentName appComponentName, boolean compatMode) { + @NonNull ComponentName appComponentName, boolean compatMode, + @NoSaveReason int saveDialogNotShowReason) { if (isValidEventLocked("logDatasetNotSelected()", sessionId)) { if (sVerbose) { Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId @@ -893,7 +903,8 @@ final class AutofillManagerServiceImpl + ", detectedFieldIds=" + detectedFieldIdsList + ", detectedFieldClassifications=" + detectedFieldClassificationsList + ", appComponentName=" + appComponentName.toShortString() - + ", compatMode=" + compatMode); + + ", compatMode=" + compatMode + + ", saveDialogNotShowReason=" + saveDialogNotShowReason); } AutofillId[] detectedFieldsIds = null; FieldClassification[] detectedFieldClassifications = null; @@ -929,7 +940,7 @@ final class AutofillManagerServiceImpl clientState, selectedDatasets, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds, - detectedFieldsIds, detectedFieldClassifications)); + detectedFieldsIds, detectedFieldClassifications, saveDialogNotShowReason)); } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 1970b5774bbb..0e2eef894d2a 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -71,6 +71,8 @@ import android.service.autofill.FieldClassification; import android.service.autofill.FieldClassification.Match; import android.service.autofill.FieldClassificationUserData; import android.service.autofill.FillContext; +import android.service.autofill.FillEventHistory.Event; +import android.service.autofill.FillEventHistory.Event.NoSaveReason; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.service.autofill.InlinePresentation; @@ -1596,10 +1598,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * when necessary. */ public void logContextCommitted() { - mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this)); + mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this, + Event.NO_SAVE_REASON_NONE)); } - private void handleLogContextCommitted() { + /** + * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED} + * when necessary. + * + * @param saveDialogNotShowReason The reason why a save dialog was not shown. + */ + public void logContextCommitted(@NoSaveReason int saveDialogNotShowReason) { + mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this, + saveDialogNotShowReason)); + } + + private void handleLogContextCommitted(@NoSaveReason int saveDialogNotShowReason) { final FillResponse lastResponse; synchronized (mLock) { lastResponse = getLastResponseLocked("logContextCommited(%s)"); @@ -1629,22 +1643,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Sets field classification scores if (userData != null && fcStrategy != null) { - logFieldClassificationScore(fcStrategy, userData); + logFieldClassificationScore(fcStrategy, userData, saveDialogNotShowReason); } else { - logContextCommitted(null, null); + logContextCommitted(null, null, saveDialogNotShowReason); } } private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds, - @Nullable ArrayList<FieldClassification> detectedFieldClassifications) { + @Nullable ArrayList<FieldClassification> detectedFieldClassifications, + @NoSaveReason int saveDialogNotShowReason) { synchronized (mLock) { - logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications); + logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications, + saveDialogNotShowReason); } } @GuardedBy("mLock") private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds, - @Nullable ArrayList<FieldClassification> detectedFieldClassifications) { + @Nullable ArrayList<FieldClassification> detectedFieldClassifications, + @NoSaveReason int saveDialogNotShowReason) { final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)"); if (lastResponse == null) return; @@ -1822,10 +1839,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds, - ignoredDatasets, changedFieldIds, changedDatasetIds, - manuallyFilledFieldIds, manuallyFilledDatasetIds, detectedFieldIds, - detectedFieldClassifications, mComponentName, mCompatMode); + mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds, ignoredDatasets, + changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, + manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications, + mComponentName, mCompatMode, saveDialogNotShowReason); } /** @@ -1833,7 +1850,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * {@code fieldId} based on its {@code currentValue} and {@code userData}. */ private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy, - @NonNull FieldClassificationUserData userData) { + @NonNull FieldClassificationUserData userData, + @NoSaveReason int saveDialogNotShowReason) { final String[] userValues = userData.getValues(); final String[] categoryIds = userData.getCategoryIds(); @@ -1879,7 +1897,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final RemoteCallback callback = new RemoteCallback((result) -> { if (result == null) { if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results"); - logContextCommitted(null, null); + logContextCommitted(null, null, saveDialogNotShowReason); return; } final Scores scores = result.getParcelable(EXTRA_SCORES); @@ -1940,7 +1958,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - logContextCommitted(detectedFieldIds, detectedFieldClassifications); + logContextCommitted(detectedFieldIds, detectedFieldClassifications, + saveDialogNotShowReason); }); fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds, @@ -1948,17 +1967,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } /** + * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN} + * when necessary. + * + * <p>Note: It is necessary to call logContextCommitted() first before calling this method. + */ + public void logSaveUiShown() { + mHandler.sendMessage(obtainMessage(Session::logSaveShown, this)); + } + + /** * Shows the save UI, when session can be saved. * - * @return {@code true} if session is done and could be removed, or {@code false} if it's - * pending user action or the service asked to keep it alive (for multi-screens workflow). + * @return {@link SaveResult} that contains the save ui display status information. */ @GuardedBy("mLock") - public boolean showSaveLocked() { + @NonNull + public SaveResult showSaveLocked() { if (mDestroyed) { Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: " + id + " destroyed"); - return false; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false, + Event.NO_SAVE_REASON_NONE); } final FillResponse response = getLastResponseLocked("showSaveLocked(%s)"); final SaveInfo saveInfo = response == null ? null : response.getSaveInfo(); @@ -1975,13 +2005,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ if (saveInfo == null) { if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service"); - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + Event.NO_SAVE_REASON_NO_SAVE_INFO); } if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) { // TODO(b/113281366): log metrics if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save"); - return false; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false, + Event.NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG); } final ArrayMap<AutofillId, InternalSanitizer> sanitizers = createSanitizers(saveInfo); @@ -2073,7 +2105,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.v(TAG, "allRequiredAreNotEmpty: " + allRequiredAreNotEmpty + " hasOptional: " + (optionalIds != null)); } - if (allRequiredAreNotEmpty) { + int saveDialogNotShowReason; + if (!allRequiredAreNotEmpty) { + saveDialogNotShowReason = Event.NO_SAVE_REASON_HAS_EMPTY_REQUIRED; + } else { // Must look up all optional ids in 2 scenarios: // - if no required id changed but an optional id did, it should trigger save / update // - if at least one required id changed but it was not part of a filled dataset, we @@ -2124,7 +2159,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } } - if (atLeastOneChanged) { + if (!atLeastOneChanged) { + saveDialogNotShowReason = Event.NO_SAVE_REASON_NO_VALUE_CHANGED; + } else { if (sDebug) { Slog.d(TAG, "at least one field changed, validate fields for save UI"); } @@ -2142,13 +2179,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.e(TAG, "Not showing save UI because validation failed:", e); log.setType(MetricsEvent.TYPE_FAILURE); mMetricsLogger.write(log); - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + Event.NO_SAVE_REASON_FIELD_VALIDATION_FAILED); } mMetricsLogger.write(log); if (!isValid) { Slog.i(TAG, "not showing save UI because fields failed validation"); - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + Event.NO_SAVE_REASON_FIELD_VALIDATION_FAILED); } } @@ -2187,7 +2226,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.d(TAG, "ignoring Save UI because all fields match contents of " + "dataset #" + i + ": " + dataset); } - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + Event.NO_SAVE_REASON_DATASET_MATCH); } } @@ -2196,9 +2236,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + id + "!"); } - // Use handler so logContextCommitted() is logged first - mHandler.sendMessage(obtainMessage(Session::logSaveShown, this)); - final IAutoFillManagerClient client = getClient(); mPendingSaveUi = new PendingUi(new Binder(), id, client); @@ -2210,8 +2247,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if (serviceLabel == null || serviceIcon == null) { wtf(null, "showSaveLocked(): no service label or icon"); - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + Event.NO_SAVE_REASON_NONE); } + getUiForShowing().showSaveUi(serviceLabel, serviceIcon, mService.getServicePackageName(), saveInfo, this, mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode); @@ -2223,7 +2262,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } mIsSaving = true; - return false; + return new SaveResult(/* logSaveShown= */ true, /* removeSession= */ false, + Event.NO_SAVE_REASON_NONE); } } // Nothing changed... @@ -2232,7 +2272,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + "allRequiredAreNotNull=" + allRequiredAreNotEmpty + ", atLeastOneChanged=" + atLeastOneChanged); } - return true; + return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true, + saveDialogNotShowReason); } private void logSaveShown() { @@ -3586,6 +3627,97 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + /** + * The result of checking whether to show the save dialog, when session can be saved. + * + * @hide + */ + static final class SaveResult { + /** + * Whether to record the save dialog has been shown. + */ + private boolean mLogSaveShown; + + /** + * Whether to remove the session. + */ + private boolean mRemoveSession; + + /** + * The reason why a save dialog was not shown. + */ + @NoSaveReason private int mSaveDialogNotShowReason; + + SaveResult(boolean logSaveShown, boolean removeSession, + @NoSaveReason int saveDialogNotShowReason) { + mLogSaveShown = logSaveShown; + mRemoveSession = removeSession; + mSaveDialogNotShowReason = saveDialogNotShowReason; + } + + /** + * Returns whether to record the save dialog has been shown. + * + * @return Whether to record the save dialog has been shown. + */ + public boolean isLogSaveShown() { + return mLogSaveShown; + } + + /** + * Sets whether to record the save dialog has been shown. + * + * @param logSaveShown Whether to record the save dialog has been shown. + */ + public void setLogSaveShown(boolean logSaveShown) { + mLogSaveShown = logSaveShown; + } + + /** + * Returns whether to remove the session. + * + * @return Whether to remove the session. + */ + public boolean isRemoveSession() { + return mRemoveSession; + } + + /** + * Sets whether to remove the session. + * + * @param removeSession Whether to remove the session. + */ + public void setRemoveSession(boolean removeSession) { + mRemoveSession = removeSession; + } + + /** + * Returns the reason why a save dialog was not shown. + * + * @return The reason why a save dialog was not shown. + */ + @NoSaveReason + public int getNoSaveReason() { + return mSaveDialogNotShowReason; + } + + /** + * Sets the reason why a save dialog was not shown. + * + * @param saveDialogNotShowReason The reason why a save dialog was not shown. + */ + public void setSaveDialogNotShowReason(@NoSaveReason int saveDialogNotShowReason) { + mSaveDialogNotShowReason = saveDialogNotShowReason; + } + + @Override + public String toString() { + return "SaveResult: [logSaveShown=" + mLogSaveShown + + ", removeSession=" + mRemoveSession + + ", saveDialogNotShowReason=" + mSaveDialogNotShowReason + "]"; + } + } + @Override public String toString() { return "Session: [id=" + id + ", component=" + mComponentName + "]"; |