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

Commit 5311206f authored by Felipe Leme's avatar Felipe Leme
Browse files

Add custom presentation (RemoteViews) on Dataset values.

New tests on LoginActivityTest:

- testAutofillOneDatasetCustomPresentation()
- testAutofillMultipleDatasetsCustomPresentations()
- testAutofillMultipleDatasetsCustomPresentationSameFields()
- testAutofillMultipleDatasetsCustomPresentationFirstDatasetMissingSecondField()
- testAutofillMultipleDatasetsCustomPresentationSecondDatasetMissingFirstField()

Fixes: 36067706
Test: CtsAutoFillServiceTestCases pass

Change-Id: Iacb660bf5a5cf311dea4bfcbfe1b3722aab34715
parent 248278fc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -36838,9 +36838,11 @@ package android.service.autofill {
  public static final class Dataset.Builder {
    ctor public Dataset.Builder(android.widget.RemoteViews);
    ctor public Dataset.Builder();
    method public android.service.autofill.Dataset build();
    method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
  }
  public final class FillCallback {
+2 −0
Original line number Diff line number Diff line
@@ -39872,9 +39872,11 @@ package android.service.autofill {
  public static final class Dataset.Builder {
    ctor public Dataset.Builder(android.widget.RemoteViews);
    ctor public Dataset.Builder();
    method public android.service.autofill.Dataset build();
    method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
  }
  public final class FillCallback {
+2 −0
Original line number Diff line number Diff line
@@ -36984,9 +36984,11 @@ package android.service.autofill {
  public static final class Dataset.Builder {
    ctor public Dataset.Builder(android.widget.RemoteViews);
    ctor public Dataset.Builder();
    method public android.service.autofill.Dataset build();
    method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
  }
  public final class FillCallback {
+62 −4
Original line number Diff line number Diff line
@@ -49,12 +49,14 @@ public final class Dataset implements Parcelable {

    private final ArrayList<AutofillId> mFieldIds;
    private final ArrayList<AutofillValue> mFieldValues;
    private final ArrayList<RemoteViews> mFieldPresentations;
    private final RemoteViews mPresentation;
    private final IntentSender mAuthentication;

    private Dataset(Builder builder) {
        mFieldIds = builder.mFieldIds;
        mFieldValues = builder.mFieldValues;
        mFieldPresentations = builder.mFieldPresentations;
        mPresentation = builder.mPresentation;
        mAuthentication = builder.mAuthentication;
    }
@@ -69,6 +71,12 @@ public final class Dataset implements Parcelable {
        return mFieldValues;
    }

    /** @hide */
    public RemoteViews getFieldPresentation(int index) {
        final RemoteViews customPresentation = mFieldPresentations.get(index);
        return customPresentation != null ? customPresentation : mPresentation;
    }

    /** @hide */
    public @Nullable RemoteViews getPresentation() {
        return mPresentation;
@@ -91,6 +99,8 @@ public final class Dataset implements Parcelable {
        return new StringBuilder("Dataset [")
                .append(", fieldIds=").append(mFieldIds)
                .append(", fieldValues=").append(mFieldValues)
                .append(", fieldPresentations=")
                .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
                .append(", hasPresentation=").append(mPresentation != null)
                .append(", hasAuthentication=").append(mAuthentication != null)
                .append(']').toString();
@@ -103,6 +113,7 @@ public final class Dataset implements Parcelable {
    public static final class Builder {
        private ArrayList<AutofillId> mFieldIds;
        private ArrayList<AutofillValue> mFieldValues;
        private ArrayList<RemoteViews> mFieldPresentations;
        private RemoteViews mPresentation;
        private IntentSender mAuthentication;
        private boolean mDestroyed;
@@ -117,6 +128,15 @@ public final class Dataset implements Parcelable {
            mPresentation = presentation;
        }

        /**
         * Creates a new builder for a dataset where each field will be visualized independently.
         *
         * <p>When using this constructor, fields must be set through
         * {@link #setValue(AutofillId, AutofillValue, RemoteViews)}.
         */
        public Builder() {
        }

        /**
         * Requires a dataset authentication before autofilling the activity with this dataset.
         *
@@ -175,24 +195,54 @@ public final class Dataset implements Parcelable {
         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
         * @param value value to be auto filled.
         * @return This builder.
         * @throws IllegalStateException if the builder was constructed without a presentation
         * ({@link RemoteViews}).
         */
        public @NonNull Builder setValue(@NonNull AutofillId id, @NonNull AutofillValue value) {
            throwIfDestroyed();
            if (mPresentation == null) {
                throw new IllegalStateException("Dataset presentation not set on constructor");
            }
            setValueAndPresentation(id, value, null);
            return this;
        }

        /**
         * Sets the value of a field, usin a custom presentation to visualize it.
         *
         * @param id id returned by {@link
         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
         * @param value value to be auto filled.
         * @param presentation The presentation used to visualize this field.
         * @return This builder.
         */
        public @NonNull Builder setValue(@NonNull AutofillId id, @NonNull AutofillValue value,
                @NonNull RemoteViews presentation) {
            throwIfDestroyed();
            Preconditions.checkNotNull(presentation, "presentation cannot be null");
            setValueAndPresentation(id, value, presentation);
            return this;
        }

        private void setValueAndPresentation(AutofillId id, AutofillValue value,
                RemoteViews presentation) {
            Preconditions.checkNotNull(id, "id cannot be null");
            Preconditions.checkNotNull(value, "value cannot be null");
            if (mFieldIds != null) {
                final int existingIdx = mFieldIds.indexOf(id);
                if (existingIdx >= 0) {
                    mFieldValues.set(existingIdx, value);
                    return this;
                    mFieldPresentations.set(existingIdx, presentation);
                    return;
                }
            } else {
                mFieldIds = new ArrayList<>();
                mFieldValues = new ArrayList<>();
                mFieldPresentations = new ArrayList<>();
            }
            mFieldIds.add(id);
            mFieldValues.add(value);
            return this;
            mFieldPresentations.add(presentation);
        }

        /**
@@ -234,6 +284,7 @@ public final class Dataset implements Parcelable {
        parcel.writeParcelable(mPresentation, flags);
        parcel.writeTypedArrayList(mFieldIds, flags);
        parcel.writeTypedArrayList(mFieldValues, flags);
        parcel.writeParcelableList(mFieldPresentations, flags);
        parcel.writeParcelable(mAuthentication, flags);
    }

@@ -243,15 +294,22 @@ public final class Dataset implements Parcelable {
            // Always go through the builder to ensure the data ingested by
            // the system obeys the contract of the builder to avoid attacks
            // using specially crafted parcels.
            final Builder builder = new Builder(parcel.readParcelable(null));
            final RemoteViews presentation = parcel.readParcelable(null);
            final Builder builder = (presentation == null)
                    ? new Builder()
                    : new Builder(presentation);
            final ArrayList<AutofillId> ids = parcel.readTypedArrayList(null);
            final ArrayList<AutofillValue> values = parcel.readTypedArrayList(null);
            final ArrayList<RemoteViews> presentations = new ArrayList<>();
            parcel.readParcelableList(presentations, null);
            final int idCount = (ids != null) ? ids.size() : 0;
            final int valueCount = (values != null) ? values.size() : 0;
            for (int i = 0; i < idCount; i++) {
                final AutofillId id = ids.get(i);
                final AutofillValue value = (valueCount > i) ? values.get(i) : null;
                builder.setValue(id, value);
                final RemoteViews fieldPresentation = presentations.isEmpty() ? null
                        : presentations.get(i);
                builder.setValueAndPresentation(id, value, fieldPresentation);
            }
            builder.setAuthentication(parcel.readParcelable(null));
            return builder.build();
+5 −3
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RemoteViews;

import com.android.internal.R;
import libcore.util.Objects;

@@ -110,15 +112,15 @@ final class FillUi {
                final Dataset dataset = response.getDatasets().get(i);
                final int index = dataset.getFieldIds().indexOf(focusedViewId);
                if (index >= 0) {
                    final AutofillValue value = dataset.getFieldValues().get(index);
                    final RemoteViews presentation = dataset.getFieldPresentation(index);
                    final View view;
                    try {
                        view = dataset.getPresentation().apply(context, null);
                        view = presentation.apply(context, null);
                    } catch (RuntimeException e) {
                        Slog.e(TAG, "Error inflating remote views", e);
                        continue;
                    }

                    final AutofillValue value = dataset.getFieldValues().get(index);
                    String valueText = null;
                    if (value.isText()) {
                        valueText = value.getTextValue().toString().toLowerCase();