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

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

New Autofill APIs for UserData id.

Test: atest CtsAutoFillServiceTestCases:FieldsClassificationTest CtsAutoFillServiceTestCases:UserDataTest

Bug: 70407264

Change-Id: Id49efc88e1ccbfa2634bcb6ccaa3371f6fd2ed4e
parent 6fa646ab
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -11576,15 +11576,15 @@ package android.content.res {
  public final class AssetManager implements java.lang.AutoCloseable {
    method public void close();
    method public java.lang.String[] getLocales();
    method public java.lang.String[] list(java.lang.String) throws java.io.IOException;
    method public java.io.InputStream open(java.lang.String) throws java.io.IOException;
    method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
    method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
    method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
    method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
    method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
    method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
    method public final java.lang.String[] getLocales();
    method public final java.lang.String[] list(java.lang.String) throws java.io.IOException;
    method public final java.io.InputStream open(java.lang.String) throws java.io.IOException;
    method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
    method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
    method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
    method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
    method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
    method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
    field public static final int ACCESS_BUFFER = 3; // 0x3
    field public static final int ACCESS_RANDOM = 1; // 0x1
    field public static final int ACCESS_STREAMING = 2; // 0x2
@@ -38667,6 +38667,7 @@ package android.service.autofill {
  public final class UserData implements android.os.Parcelable {
    method public int describeContents();
    method public java.lang.String getFieldClassificationAlgorithm();
    method public java.lang.String getId();
    method public static int getMaxFieldClassificationIdsSize();
    method public static int getMaxUserDataSize();
    method public static int getMaxValueLength();
@@ -38676,7 +38677,7 @@ package android.service.autofill {
  }
  public static final class UserData.Builder {
    ctor public UserData.Builder(java.lang.String, java.lang.String);
    ctor public UserData.Builder(java.lang.String, java.lang.String, java.lang.String);
    method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String);
    method public android.service.autofill.UserData build();
    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithm(java.lang.String, android.os.Bundle);
@@ -49528,6 +49529,7 @@ package android.view.autofill {
    method public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
    method public java.lang.String getDefaultFieldClassificationAlgorithm();
    method public android.service.autofill.UserData getUserData();
    method public java.lang.String getUserDataId();
    method public boolean hasEnabledAutofillServices();
    method public boolean isAutofillSupported();
    method public boolean isEnabled();
+36 −8
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Settings;
import android.service.autofill.FieldClassification.Match;
import android.text.TextUtils;
import android.util.Log;
import android.view.autofill.AutofillManager;
import android.view.autofill.Helper;
@@ -52,12 +53,14 @@ public final class UserData implements Parcelable {
    private static final int DEFAULT_MIN_VALUE_LENGTH = 5;
    private static final int DEFAULT_MAX_VALUE_LENGTH = 100;

    private final String mId;
    private final String mAlgorithm;
    private final Bundle mAlgorithmArgs;
    private final String[] mRemoteIds;
    private final String[] mValues;

    private UserData(Builder builder) {
        mId = builder.mId;
        mAlgorithm = builder.mAlgorithm;
        mAlgorithmArgs = builder.mAlgorithmArgs;
        mRemoteIds = new String[builder.mRemoteIds.size()];
@@ -75,6 +78,13 @@ public final class UserData implements Parcelable {
        return mAlgorithm;
    }

    /**
     * Gets the id.
     */
    public String getId() {
        return mId;
    }

    /** @hide */
    public Bundle getAlgorithmArgs() {
        return mAlgorithmArgs;
@@ -92,6 +102,7 @@ public final class UserData implements Parcelable {

    /** @hide */
    public void dump(String prefix, PrintWriter pw) {
        pw.print(prefix); pw.print("id: "); pw.print(mId);
        pw.print(prefix); pw.print("Algorithm: "); pw.print(mAlgorithm);
        pw.print(" Args: "); pw.println(mAlgorithmArgs);

@@ -121,6 +132,7 @@ public final class UserData implements Parcelable {
     * A builder for {@link UserData} objects.
     */
    public static final class Builder {
        private final String mId;
        private final ArrayList<String> mRemoteIds;
        private final ArrayList<String> mValues;
        private String mAlgorithm;
@@ -131,16 +143,28 @@ public final class UserData implements Parcelable {
         * Creates a new builder for the user data used for <a href="#FieldClassification">field
         * classification</a>.
         *
         * <p>The user data must contain at least one pair of {@code remoteId} -> {@code value}, and
         * more pairs can be added through the {@link #add(String, String)} method.
         *
         * @param id id used to identify the whole {@link UserData} object. This id is also returned
         * by {@link AutofillManager#getUserDataId()}, which can be used to check if the
         * {@link UserData} is up-to-date without fetching the whole object (through
         * {@link AutofillManager#getUserData()}).
         * @param remoteId unique string used to identify a user data value.
         * @param value value of the user data.
         *
         * @throws IllegalArgumentException if any of the following occurs:
         * <ol>
         *   <li>{@code id} is empty
         *   <li>{@code remoteId} is empty
         *   <li>{@code value} is empty
         *   <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}
         *   <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()}
         * </ol>
         */
        public Builder(@NonNull String remoteId, @NonNull String value) {
            checkValidRemoteId(remoteId);
        public Builder(@NonNull String id, @NonNull String remoteId, @NonNull String value) {
            mId = checkNotEmpty("id", id);
            checkNotEmpty("remoteId", remoteId);
            checkValidValue(value);
            final int capacity = getMaxUserDataSize();
            mRemoteIds = new ArrayList<>(capacity);
@@ -188,7 +212,7 @@ public final class UserData implements Parcelable {
         */
        public Builder add(@NonNull String remoteId, @NonNull String value) {
            throwIfDestroyed();
            checkValidRemoteId(remoteId);
            checkNotEmpty("remoteId", remoteId);
            checkValidValue(value);

            Preconditions.checkState(!mRemoteIds.contains(remoteId),
@@ -205,9 +229,10 @@ public final class UserData implements Parcelable {
            return this;
        }

        private void checkValidRemoteId(@Nullable String remoteId) {
            Preconditions.checkNotNull(remoteId);
            Preconditions.checkArgument(!remoteId.isEmpty(), "remoteId cannot be empty");
        private String checkNotEmpty(@NonNull String name, @Nullable String value) {
            Preconditions.checkNotNull(value);
            Preconditions.checkArgument(!TextUtils.isEmpty(value), "%s cannot be empty", name);
            return value;
        }

        private void checkValidValue(@Nullable String value) {
@@ -246,7 +271,8 @@ public final class UserData implements Parcelable {
    public String toString() {
        if (!sDebug) return super.toString();

        final StringBuilder builder = new StringBuilder("UserData: [algorithm=").append(mAlgorithm);
        final StringBuilder builder = new StringBuilder("UserData: [id=").append(mId)
                .append(", algorithm=").append(mAlgorithm);
        // Cannot disclose remote ids or values because they could contain PII
        builder.append(", remoteIds=");
        Helper.appendRedacted(builder, mRemoteIds);
@@ -266,6 +292,7 @@ public final class UserData implements Parcelable {

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(mId);
        parcel.writeStringArray(mRemoteIds);
        parcel.writeStringArray(mValues);
        parcel.writeString(mAlgorithm);
@@ -279,9 +306,10 @@ public final class UserData 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 String id = parcel.readString();
            final String[] remoteIds = parcel.readStringArray();
            final String[] values = parcel.readStringArray();
            final Builder builder = new Builder(remoteIds[0], values[0])
            final Builder builder = new Builder(id, remoteIds[0], values[0])
                    .setFieldClassificationAlgorithm(parcel.readString(), parcel.readBundle());
            for (int i = 1; i < remoteIds.length; i++) {
                builder.add(remoteIds[i], values[i]);
+25 −1
Original line number Diff line number Diff line
@@ -1098,6 +1098,30 @@ public final class AutofillManager {
        }
    }

    /**
     * Gets the id of the {@link UserData} used for
     * <a href="AutofillService.html#FieldClassification">field classification</a>.
     *
     * <p>This method is useful when the service must check the status of the {@link UserData} in
     * the device without fetching the whole object.
     *
     * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
     * and it's ignored if the caller currently doesn't have an enabled autofill service for
     * the user.
     *
     * @return id of the {@link UserData} previously set by {@link #setUserData(UserData)}
     * or {@code null} if it was reset or if the caller currently does not have an enabled autofill
     * service for the user.
     */
    @Nullable public String getUserDataId() {
        try {
            return mService.getUserDataId();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
        }
    }

    /**
     * Gets the user data used for
     * <a href="AutofillService.html#FieldClassification">field classification</a>.
@@ -1119,7 +1143,7 @@ public final class AutofillManager {
    }

    /**
     * Sets the user data used for
     * Sets the {@link UserData} used for
     * <a href="AutofillService.html#FieldClassification">field classification</a>
     *
     * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ interface IAutoFillManager {
    boolean isServiceEnabled(int userId, String packageName);
    void onPendingSaveUi(int operation, IBinder token);
    UserData getUserData();
    String getUserDataId();
    void setUserData(in UserData userData);
    boolean isFieldClassificationEnabled();
    ComponentName getAutofillServiceComponentName();
+17 −0
Original line number Diff line number Diff line
@@ -616,6 +616,23 @@ public final class AutofillManagerService extends SystemService {
            return null;
        }

        @Override
        public String getUserDataId() throws RemoteException {
            final int userId = UserHandle.getCallingUserId();

            synchronized (mLock) {
                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
                if (service != null) {
                    final UserData userData = service.getUserData(getCallingUid());
                    return userData == null ? null : userData.getId();
                } else if (sVerbose) {
                    Slog.v(TAG, "getUserDataId(): no service for " + userId);
                }
            }

            return null;
        }

        @Override
        public void setUserData(UserData userData) throws RemoteException {
            final int userId = UserHandle.getCallingUserId();