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

Commit 37f83722 authored by Felipe Leme's avatar Felipe Leme
Browse files

New Autofill Save UI API to switch visibility of views.

Test: atest \
      OnClickActionTest VisibilitySetterActionTest CustomDescriptionUnitTest

Fixes: 112709898

Change-Id: I05d59ecbdd21d68e9056adeb361e5a9bdd3d2a43
parent 93a2daf1
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -39005,6 +39005,7 @@ package android.service.autofill {
  public static class CustomDescription.Builder {
    ctor public CustomDescription.Builder(android.widget.RemoteViews);
    method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
    method public android.service.autofill.CustomDescription.Builder addOnClickAction(int, android.service.autofill.OnClickAction);
    method public android.service.autofill.CustomDescription.Builder batchUpdate(android.service.autofill.Validator, android.service.autofill.BatchUpdates);
    method public android.service.autofill.CustomDescription build();
  }
@@ -39143,6 +39144,9 @@ package android.service.autofill {
    field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
  }
  public abstract interface OnClickAction {
  }
  public final class RegexValidator implements android.os.Parcelable android.service.autofill.Validator {
    ctor public RegexValidator(android.view.autofill.AutofillId, java.util.regex.Pattern);
    method public int describeContents();
@@ -39238,6 +39242,18 @@ package android.service.autofill {
    method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
  }
  public final class VisibilitySetterAction implements android.service.autofill.OnClickAction android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.VisibilitySetterAction> CREATOR;
  }
  public static class VisibilitySetterAction.Builder {
    ctor public VisibilitySetterAction.Builder(int, int);
    method public android.service.autofill.VisibilitySetterAction build();
    method public android.service.autofill.VisibilitySetterAction.Builder setVisibility(int, int);
  }
}
package android.service.carrier {
+13 −0
Original line number Diff line number Diff line
@@ -998,6 +998,10 @@ package android.service.autofill {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }

  public final class CustomDescription implements android.os.Parcelable {
    method public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions();
  }

  public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }
@@ -1014,6 +1018,11 @@ package android.service.autofill {
    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
  }

  public abstract class InternalOnClickAction implements android.service.autofill.OnClickAction android.os.Parcelable {
    ctor public InternalOnClickAction();
    method public abstract void onClick(android.view.ViewGroup);
  }

  public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
    ctor public InternalSanitizer();
  }
@@ -1044,6 +1053,10 @@ package android.service.autofill {
    method public abstract android.view.autofill.AutofillValue findRawValueByAutofillId(android.view.autofill.AutofillId);
  }

  public final class VisibilitySetterAction extends android.service.autofill.InternalOnClickAction implements android.service.autofill.OnClickAction android.os.Parcelable {
    method public void onClick(android.view.ViewGroup);
  }

}

package android.service.notification {
+97 −4
Original line number Diff line number Diff line
@@ -20,11 +20,13 @@ import static android.view.autofill.Helper.sDebug;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import android.util.SparseArray;
import android.widget.RemoteViews;

import com.android.internal.util.Preconditions;
@@ -90,11 +92,13 @@ public final class CustomDescription implements Parcelable {
    private final RemoteViews mPresentation;
    private final ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
    private final ArrayList<Pair<InternalValidator, BatchUpdates>> mUpdates;
    private final SparseArray<InternalOnClickAction> mActions;

    private CustomDescription(Builder builder) {
        mPresentation = builder.mPresentation;
        mTransformations = builder.mTransformations;
        mUpdates = builder.mUpdates;
        mActions = builder.mActions;
    }

    /** @hide */
@@ -115,6 +119,13 @@ public final class CustomDescription implements Parcelable {
        return mUpdates;
    }

    /** @hide */
    @Nullable
    @TestApi
    public SparseArray<InternalOnClickAction> getActions() {
        return mActions;
    }

    /**
     * Builder for {@link CustomDescription} objects.
     */
@@ -124,6 +135,7 @@ public final class CustomDescription implements Parcelable {
        private boolean mDestroyed;
        private ArrayList<Pair<Integer, InternalTransformation>> mTransformations;
        private ArrayList<Pair<InternalValidator, BatchUpdates>> mUpdates;
        private SparseArray<InternalOnClickAction> mActions;

        /**
         * Default constructor.
@@ -157,9 +169,12 @@ public final class CustomDescription implements Parcelable {
         *
         * @param id view id of the children view.
         * @param transformation an implementation provided by the Android System.
         *
         * @return this builder.
         *
         * @throws IllegalArgumentException if {@code transformation} is not a class provided
         * by the Android System.
         * @throws IllegalStateException if {@link #build()} was already called.
         */
        public Builder addChild(int id, @NonNull Transformation transformation) {
            throwIfDestroyed();
@@ -250,8 +265,10 @@ public final class CustomDescription implements Parcelable {
         * is satisfied.
         *
         * @return this builder
         *
         * @throws IllegalArgumentException if {@code condition} is not a class provided
         * by the Android System.
         * @throws IllegalStateException if {@link #build()} was already called.
         */
        public Builder batchUpdate(@NonNull Validator condition, @NonNull BatchUpdates updates) {
            throwIfDestroyed();
@@ -265,6 +282,58 @@ public final class CustomDescription implements Parcelable {
            return this;
        }

        /**
         * Sets an action to be applied to the {@link RemoteViews presentation template} when the
         * child view with the given {@code id} is clicked.
         *
         * <p>Typically used when the presentation uses a masked field (like {@code ****}) for
         * sensitive fields like passwords or credit cards numbers, but offers a an icon that the
         * user can tap to show the value for that field.
         *
         * <p>Example:
         *
         * <pre class="prettyprint">
         * customDescriptionBuilder
         *   .addChild(R.id.password_plain, new CharSequenceTransformation
         *      .Builder(passwordId, Pattern.compile("^(.*)$"), "$1").build())
         *   .addOnClickAction(R.id.showIcon, new VisibilitySetterAction
         *     .Builder(R.id.hideIcon, View.VISIBLE)
         *     .setVisibility(R.id.showIcon, View.GONE)
         *     .setVisibility(R.id.password_plain, View.VISIBLE)
         *     .setVisibility(R.id.password_masked, View.GONE)
         *     .build())
         *   .addOnClickAction(R.id.hideIcon, new VisibilitySetterAction
         *     .Builder(R.id.showIcon, View.VISIBLE)
         *     .setVisibility(R.id.hideIcon, View.GONE)
         *     .setVisibility(R.id.password_masked, View.VISIBLE)
         *     .setVisibility(R.id.password_plain, View.GONE)
         *     .build());
         * </pre>
         *
         * <p><b>Note:</b> Currently only one action can be applied to a child; if this method
         * is called multiple times passing the same {@code id}, only the last call will be used.
         *
         * @param id resource id of the child view.
         * @param action action to be performed.
         *
         * @return this builder
         *
         * @throws IllegalArgumentException if {@code action} is not a class provided
         * by the Android System.
         * @throws IllegalStateException if {@link #build()} was already called.
         */
        public Builder addOnClickAction(int id, @NonNull OnClickAction action) {
            throwIfDestroyed();
            Preconditions.checkArgument((action instanceof InternalOnClickAction),
                    "not provided by Android System: " + action);
            if (mActions == null) {
                mActions = new SparseArray<InternalOnClickAction>();
            }
            mActions.put(id, (InternalOnClickAction) action);

            return this;
        }

        /**
         * Creates a new {@link CustomDescription} instance.
         */
@@ -294,6 +363,8 @@ public final class CustomDescription implements Parcelable {
                    .append(mTransformations == null ? "N/A" : mTransformations.size())
                .append(", updates=")
                    .append(mUpdates == null ? "N/A" : mUpdates.size())
                .append(", actions=")
                    .append(mActions == null ? "N/A" : mActions.size())
                .append("]").toString();
    }

@@ -339,6 +410,19 @@ public final class CustomDescription implements Parcelable {
            dest.writeParcelableArray(conditions, flags);
            dest.writeParcelableArray(updates, flags);
        }
        if (mActions == null) {
            dest.writeIntArray(null);
        } else {
            final int size = mActions.size();
            final int[] ids = new int[size];
            final InternalOnClickAction[] values = new InternalOnClickAction[size];
            for (int i = 0; i < size; i++) {
                ids[i] = mActions.keyAt(i);
                values[i] = mActions.valueAt(i);
            }
            dest.writeIntArray(ids);
            dest.writeParcelableArray(values, flags);
        }
    }
    public static final Parcelable.Creator<CustomDescription> CREATOR =
            new Parcelable.Creator<CustomDescription>() {
@@ -351,13 +435,13 @@ public final class CustomDescription implements Parcelable {
            if (parentPresentation == null) return null;

            final Builder builder = new Builder(parentPresentation);
            final int[] ids = parcel.createIntArray();
            if (ids != null) {
            final int[] transformationIds = parcel.createIntArray();
            if (transformationIds != null) {
                final InternalTransformation[] values =
                    parcel.readParcelableArray(null, InternalTransformation.class);
                final int size = ids.length;
                final int size = transformationIds.length;
                for (int i = 0; i < size; i++) {
                    builder.addChild(ids[i], values[i]);
                    builder.addChild(transformationIds[i], values[i]);
                }
            }
            final InternalValidator[] conditions =
@@ -369,6 +453,15 @@ public final class CustomDescription implements Parcelable {
                    builder.batchUpdate(conditions[i], updates[i]);
                }
            }
            final int[] actionIds = parcel.createIntArray();
            if (actionIds != null) {
                final InternalOnClickAction[] values =
                    parcel.readParcelableArray(null, InternalOnClickAction.class);
                final int size = actionIds.length;
                for (int i = 0; i < size; i++) {
                    builder.addOnClickAction(actionIds[i], values[i]);
                }
            }
            return builder.build();
        }

+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.service.autofill;

import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcelable;
import android.view.ViewGroup;

/**
 * Superclass of all {@link OnClickAction} the system understands. As this is not public, all public
 * subclasses have to implement {@link OnClickAction} again.
 *
 * @hide
 */
@TestApi
public abstract class InternalOnClickAction implements OnClickAction, Parcelable {

    /**
     * Applies the action to the children of the {@rootView} when clicked.
     */
    public abstract void onClick(@NonNull ViewGroup rootView);
}
+0 −2
Original line number Diff line number Diff line
@@ -35,8 +35,6 @@ public abstract class InternalSanitizer implements Sanitizer, Parcelable {
     *
     * @return sanitized value or {@code null} if value could not be sanitized (for example: didn't
     * match regex, it's an invalid type, regex failed, etc).
     *
     * @hide
     */
    @Nullable
    public abstract AutofillValue sanitize(@NonNull AutofillValue value);
Loading