Merge "Don't show Save UI when values filled by user belong to a dataset." into oc-mr1-dev
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user