Merge "Don't show Save UI when values filled by user belong to a dataset." into oc-mr1-dev

This commit is contained in:
Felipe Leme
2017-07-27 15:11:22 +00:00
committed by Android (Google) Code Review
4 changed files with 85 additions and 9 deletions

View File

@@ -26,6 +26,7 @@ import android.os.Parcelable;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.widget.RemoteViews;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;

View File

@@ -118,6 +118,9 @@ import java.util.Arrays;
* <li>The {@link AutofillValue} of at least one view (be it required or optional) has changed
* (i.e., it's neither the same value passed in a {@link Dataset}, nor the initial value
* presented in the view).
* <li>There is no {@link Dataset} in the last {@link FillResponse} that completely matches the
* screen state (i.e., all required and optional fields in the dataset have the same value as
* the fields in the screen).
* <li>The user explicitly tapped the UI affordance asking to save data for autofill.
* </ul>
*

View File

@@ -16,11 +16,16 @@
package com.android.server.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
@@ -82,4 +87,16 @@ public final class Helper {
}
return array;
}
@NonNull
static ArrayMap<AutofillId, AutofillValue> getFields(@NonNull Dataset dataset) {
final ArrayList<AutofillId> ids = dataset.getFieldIds();
final ArrayList<AutofillValue> values = dataset.getFieldValues();
final int size = ids == null ? 0 : ids.size();
final ArrayMap<AutofillId, AutofillValue> fields = new ArrayMap<>(size);
for (int i = 0; i < size; i++) {
fields.put(ids.get(i), values.get(i));
}
return fields;
}
}

View File

@@ -804,15 +804,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
/*
* The Save dialog is only shown if all conditions below are met:
*
* - saveInfo is not null
* - autofillValue of all required ids is not null
* - saveInfo is not null.
* - autofillValue of all required ids is not null.
* - autofillValue of at least one id (required or optional) has changed.
* - there is no Dataset in the last FillResponse whose values of all dataset fields matches
* the current values of all fields in the screen.
*/
if (saveInfo == null) {
return true;
}
// Cache used to make sure changed fields do not belong to a dataset.
final ArrayMap<AutofillId, AutofillValue> currentValues = new ArrayMap<>();
final ArraySet<AutofillId> allIds = new ArraySet<>();
final AutofillId[] requiredIds = saveInfo.getRequiredIds();
boolean allRequiredAreNotEmpty = true;
boolean atLeastOneChanged = false;
@@ -823,6 +828,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.w(TAG, "null autofill id on " + Arrays.toString(requiredIds));
continue;
}
allIds.add(id);
final ViewState viewState = mViewStates.get(id);
if (viewState == null) {
Slog.w(TAG, "showSaveLocked(): no ViewState for required " + id);
@@ -841,18 +847,19 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
value = initialValue;
} else {
if (sDebug) {
Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
Slog.d(TAG, "empty value for required " + id );
}
allRequiredAreNotEmpty = false;
break;
}
}
currentValues.put(id, value);
final AutofillValue filledValue = viewState.getAutofilledValue();
if (!value.equals(filledValue)) {
if (sDebug) {
Slog.d(TAG, "showSaveLocked(): found a change on required " + id + ": "
+ filledValue + " => " + value);
Slog.d(TAG, "found a change on required " + id + ": " + filledValue
+ " => " + value);
}
atLeastOneChanged = true;
}
@@ -865,22 +872,34 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// 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];
allIds.add(id);
final ViewState viewState = mViewStates.get(id);
if (viewState == null) {
Slog.w(TAG, "showSaveLocked(): no ViewState for optional " + id);
Slog.w(TAG, "no ViewState for optional " + id);
continue;
}
if ((viewState.getState() & ViewState.STATE_CHANGED) != 0) {
final AutofillValue currentValue = viewState.getCurrentValue();
currentValues.put(id, currentValue);
final AutofillValue filledValue = viewState.getAutofilledValue();
if (currentValue != null && !currentValue.equals(filledValue)) {
if (sDebug) {
Slog.d(TAG, "finishSessionLocked(): found a change on optional "
+ id + ": " + filledValue + " => " + currentValue);
Slog.d(TAG, "found a change on optional " + id + ": " + filledValue
+ " => " + currentValue);
}
atLeastOneChanged = true;
break;
}
} else {
// Update current values cache based on initial value
final AutofillValue initialValue = getValueFromContexts(id);
if (sDebug) {
Slog.d(TAG, "no current value for " + id + "; initial value is "
+ initialValue);
}
if (initialValue != null) {
currentValues.put(id, initialValue);
}
}
}
}
@@ -907,6 +926,42 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
// Make sure the service doesn't have the fields already by checking the datasets
// content.
final ArrayList<Dataset> datasets = response.getDatasets();
if (datasets != null) {
datasets_loop: for (int i = 0; i < datasets.size(); i++) {
final Dataset dataset = datasets.get(i);
final ArrayMap<AutofillId, AutofillValue> datasetValues =
Helper.getFields(dataset);
if (sVerbose) {
Slog.v(TAG, "Checking if saved fields match contents of dataset #" + i
+ ": " + dataset + "; allIds=" + allIds);
}
for (int j = 0; j < allIds.size(); j++) {
final AutofillId id = allIds.valueAt(j);
final AutofillValue currentValue = currentValues.get(id);
if (currentValue == null) {
if (sDebug) {
Slog.d(TAG, "dataset has value for field that is null: " + id);
}
continue datasets_loop;
}
final AutofillValue datasetValue = datasetValues.get(id);
if (!currentValue.equals(datasetValue)) {
if (sDebug) Slog.d(TAG, "found a change on id " + id);
continue datasets_loop;
}
if (sVerbose) Slog.v(TAG, "no changes for id " + id);
}
if (sDebug) {
Slog.d(TAG, "ignoring Save UI because all fields match contents of "
+ "dataset #" + i + ": " + dataset);
}
return true;
}
}
if (sDebug) Slog.d(TAG, "Good news, everyone! All checks passed, show save UI!");
mService.setSaveShown(id);
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo,