Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9f32596 authored by Felipe Leme's avatar Felipe Leme
Browse files

Changed Autofill Save UI to show UPDATE instead of SAVE when necessary.

Also introduced new metric: FIELD_AUTOFILL_UPDATE on AUTOFILL_SAVE_UI.

Test: atest CtsAutoFillServiceTestCases # with a bunch of changes
Test: atest OptionalSaveActivityTest#testShowUpdateWhenUserChangedOptionalValueFromDatasetAndRequiredNotFromDataset

Bug: 112192360
Fixes: 80100983

Change-Id: Ifab0d43de44fd473a3f8b232d77d5dc62344b0ae
parent bc0a1737
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -4936,10 +4936,29 @@
         by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
         data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
    <string name="autofill_save_title_with_3types">Save <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>

    <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
         by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
    <string name="autofill_update_title">Update to &lt;b><xliff:g id="label" example="MyPass">%1$s</xliff:g>&lt;/b>?</string>
    <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
         by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
    <string name="autofill_update_title_with_type">Update <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%2$s</xliff:g>&lt;/b>?</string>
    <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
         by an autofill service, and the service does knows what the activity represents, and it represents 2 types of
         data (for example, password and credit card info) [CHAR LIMIT=NONE] -->
    <string name="autofill_update_title_with_2types">Update <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%3$s</xliff:g>&lt;/b>?</string>
    <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
         by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
         data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
    <string name="autofill_update_title_with_3types">Update <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>


    <!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
    <string name="autofill_save_yes">Save</string>
    <!-- Label for the autofill cancel button [CHAR LIMIT=NONE] -->
    <string name="autofill_save_no">No thanks</string>
    <!-- Label for the autofill update button [CHAR LIMIT=NONE] -->
    <string name="autofill_update_yes">Update</string>

    <!-- Label for the type of data being saved for autofill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
    <string name="autofill_save_type_password">password</string>
+5 −0
Original line number Diff line number Diff line
@@ -3108,6 +3108,11 @@
  <java-symbol type="plurals" name="autofill_picker_some_suggestions" />
  <java-symbol type="string" name="autofill" />
  <java-symbol type="string" name="autofill_picker_accessibility_title " />
  <java-symbol type="string" name="autofill_update_title" />
  <java-symbol type="string" name="autofill_update_title_with_type" />
  <java-symbol type="string" name="autofill_update_title_with_2types" />
  <java-symbol type="string" name="autofill_update_title_with_3types" />
  <java-symbol type="string" name="autofill_update_yes" />
  <java-symbol type="string" name="autofill_save_accessibility_title " />
  <java-symbol type="string" name="autofill_save_title" />
  <java-symbol type="string" name="autofill_save_title_with_type" />
+5 −0
Original line number Diff line number Diff line
@@ -4084,6 +4084,8 @@ message MetricsEvent {
    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
    // NOTE: starting on OS Q, it also added the following fields:
    // FIELD_AUTOFILL_UPDATE: Whether the UI displayed "UPDATE" instead of "SAVE"
    AUTOFILL_SAVE_UI = 916;

    // Tag of a field for the number of saveable ids
@@ -6430,6 +6432,9 @@ message MetricsEvent {
    // OS: Q
    FACE_ENROLL_PREVIEW = 1554;

    // Field used to indicate whether a save request was used to update existing user data.
    FIELD_AUTOFILL_UPDATE = 1555;

    // ---- End Q Constants, all Q constants go above this line ----

    // Add new aosp constants above this line.
+37 −11
Original line number Diff line number Diff line
@@ -1479,6 +1479,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        final AutofillId[] requiredIds = saveInfo.getRequiredIds();
        boolean allRequiredAreNotEmpty = true;
        boolean atLeastOneChanged = false;
        // If an autofilled field is changed, we need to change isUpdate to true so the proper UI is
        // shown.
        boolean isUpdate = false;
        if (requiredIds != null) {
            for (int i = 0; i < requiredIds.length; i++) {
                final AutofillId id = requiredIds[i];
@@ -1536,6 +1539,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                            }
                            changed = false;
                        }
                    } else {
                        isUpdate = true;
                    }
                    if (changed) {
                        if (sDebug) {
@@ -1549,8 +1554,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        }

        final AutofillId[] optionalIds = saveInfo.getOptionalIds();
        if (sVerbose) {
            Slog.v(TAG, "allRequiredAreNotEmpty: " + allRequiredAreNotEmpty + " hasOptional: "
                    + (optionalIds != null));
        }
        if (allRequiredAreNotEmpty) {
            if (!atLeastOneChanged && optionalIds != null) {
            // 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
            //   need to check if an optional id is part of a filled datased (in which case we show
            //   Update instead of Save)
            if (optionalIds!= null && (!atLeastOneChanged || !isUpdate)) {
                // No change on required ids yet, look for changes on optional ids.
                for (int i = 0; i < optionalIds.length; i++) {
                    final AutofillId id = optionalIds[i];
@@ -1562,15 +1576,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    }
                    if ((viewState.getState() & ViewState.STATE_CHANGED) != 0) {
                        final AutofillValue currentValue = viewState.getCurrentValue();
                        currentValues.put(id, currentValue);
                        final AutofillValue value = getSanitizedValue(sanitizers, id, currentValue);
                        if (value == null) {
                            if (sDebug) {
                                Slog.d(TAG, "value of opt. field " + id + " failed sanitization");
                            }
                            continue;
                        }

                        currentValues.put(id, value);
                        final AutofillValue filledValue = viewState.getAutofilledValue();
                        if (currentValue != null && !currentValue.equals(filledValue)) {
                        if (value != null && !value.equals(filledValue)) {
                            if (sDebug) {
                                Slog.d(TAG, "found a change on optional " + id + ": " + filledValue
                                        + " => " + currentValue);
                                        + " => " + value);
                            }
                            if (filledValue != null) {
                                isUpdate = true;
                            }
                            atLeastOneChanged = true;
                            break;
                        }
                    } else  {
                        // Update current values cache based on initial value
@@ -1623,7 +1647,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                                Helper.getFields(dataset);
                        if (sVerbose) {
                            Slog.v(TAG, "Checking if saved fields match contents of dataset #" + i
                                    + ": " + dataset + "; allSavableIds=" + savableIds);
                                    + ": " + dataset + "; savableIds=" + savableIds);
                        }
                        savable_ids_loop: for (int j = 0; j < savableIds.size(); j++) {
                            final AutofillId id = savableIds.valueAt(j);
@@ -1664,7 +1688,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                mPendingSaveUi = new PendingUi(mActivityToken, id, client);
                getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
                        mService.getServicePackageName(), saveInfo, this,
                        mComponentName, this, mPendingSaveUi, mCompatMode);
                        mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode);
                if (client != null) {
                    try {
                        client.setSaveUiState(id, true);
@@ -1714,12 +1738,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        return sanitizers;
    }

    // TODO: this method is called a few times in the save process, we should cache its results into
    // ViewState.
    @Nullable
    private AutofillValue getSanitizedValue(
            @Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
            @NonNull AutofillId id,
            @NonNull AutofillValue value) {
        if (sanitizers == null) return value;
            @Nullable AutofillValue value) {
        if (sanitizers == null || value == null) return value;

        final InternalSanitizer sanitizer = sanitizers.get(id);
        if (sanitizer == null) {
+7 −3
Original line number Diff line number Diff line
@@ -268,9 +268,10 @@ public final class AutoFillUI {
            @Nullable String servicePackageName, @NonNull SaveInfo info,
            @NonNull ValueFinder valueFinder, @NonNull ComponentName componentName,
            @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi,
            boolean compatMode) {
            boolean isUpdate, boolean compatMode) {
        if (sVerbose) {
            Slog.v(TAG, "showSaveUi() for " + componentName.toShortString() + ": " + info);
            Slog.v(TAG, "showSaveUi(update=" + isUpdate + ") for " + componentName.toShortString()
                    + ": " + info);
        }
        int numIds = 0;
        numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
@@ -280,6 +281,9 @@ public final class AutoFillUI {
                .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, componentName, servicePackageName,
                        pendingSaveUi.sessionId, compatMode)
                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
        if (isUpdate) {
            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_UPDATE, 1);
        }

        mHandler.post(() -> {
            if (callback != mCallback) {
@@ -328,7 +332,7 @@ public final class AutoFillUI {
                    }
                    mMetricsLogger.write(log);
                }
            }, compatMode);
            }, isUpdate, compatMode);
        });
    }

Loading