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

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

Changed FillResponse.setAuthentication() to require field ids.

Currently, authenticate FillResponses do not support partition and follows
the "Highlander approach" (There can be just only one), which causes the
authentication UI to show on all views.

This CL overloads FillResponse.setAuthentication() so it requires the
AutofillIds of the autofillable fields, although behind the scenes it
calls the old method - once clients use the new method, the old method
will be removed and the underlying implementation changed.

The new behavior will be tested by testFillResponseAuthJustOneField()
on LoginActivityTest, although currently it's testing the old behavior.

Test: LoginActivityTest.testFillResponseAuthJustOneField

Bug: 35707731
Bug: 36855717

Change-Id: I601f3e4776aa8763415a06d8d802901a930728d2
parent 9ff3ec48
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -37050,7 +37050,7 @@ package android.service.autofill {
    ctor public FillResponse.Builder();
    ctor public FillResponse.Builder();
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
  }
+1 −1
Original line number Original line Diff line number Diff line
@@ -40116,7 +40116,7 @@ package android.service.autofill {
    ctor public FillResponse.Builder();
    ctor public FillResponse.Builder();
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
  }
+1 −1
Original line number Original line Diff line number Diff line
@@ -37208,7 +37208,7 @@ package android.service.autofill {
    ctor public FillResponse.Builder();
    ctor public FillResponse.Builder();
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
  }
+42 −14
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
 * See the License for the specific language governing permissions and
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * limitations under the License.
 */
 */

package android.service.autofill;
package android.service.autofill;


import static android.view.autofill.Helper.DEBUG;
import static android.view.autofill.Helper.DEBUG;
@@ -23,6 +24,7 @@ import android.content.IntentSender;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager;
import android.widget.RemoteViews;
import android.widget.RemoteViews;


@@ -112,7 +114,7 @@ import java.util.ArrayList;
 *
 *
 * <p>The service could require user authentication at the {@link FillResponse} or the
 * <p>The service could require user authentication at the {@link FillResponse} or the
 * {@link Dataset} level, prior to autofilling an activity - see
 * {@link Dataset} level, prior to autofilling an activity - see
 * {@link FillResponse.Builder#setAuthentication(IntentSender, RemoteViews)} and
 * {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews)} and
 * {@link Dataset.Builder#setAuthentication(IntentSender)}.
 * {@link Dataset.Builder#setAuthentication(IntentSender)}.
 *
 *
 * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
 * <p>It is recommended that you encrypt only the sensitive data but leave the labels unencrypted
@@ -126,7 +128,7 @@ import java.util.ArrayList;
 * possible options) which will start your auth flow and after successfully authenticating
 * possible options) which will start your auth flow and after successfully authenticating
 * the user will be presented with the Home and Work options to pick one. Hence, you have
 * the user will be presented with the Home and Work options to pick one. Hence, you have
 * flexibility how to implement your auth while storing labels non-encrypted and data
 * flexibility how to implement your auth while storing labels non-encrypted and data
 * encrypted provides a better user experience.</p>
 * encrypted provides a better user experience.
 */
 */
public final class FillResponse implements Parcelable {
public final class FillResponse implements Parcelable {


@@ -135,6 +137,7 @@ public final class FillResponse implements Parcelable {
    private final Bundle mExtras;
    private final Bundle mExtras;
    private final RemoteViews mPresentation;
    private final RemoteViews mPresentation;
    private final IntentSender mAuthentication;
    private final IntentSender mAuthentication;
    private AutofillId[] mAuthenticationIds;


    private FillResponse(@NonNull Builder builder) {
    private FillResponse(@NonNull Builder builder) {
        mDatasets = builder.mDatasets;
        mDatasets = builder.mDatasets;
@@ -142,6 +145,7 @@ public final class FillResponse implements Parcelable {
        mExtras = builder.mExtras;
        mExtras = builder.mExtras;
        mPresentation = builder.mPresentation;
        mPresentation = builder.mPresentation;
        mAuthentication = builder.mAuthentication;
        mAuthentication = builder.mAuthentication;
        mAuthenticationIds = builder.mAuthenticationIds;
    }
    }


    /** @hide */
    /** @hide */
@@ -169,6 +173,11 @@ public final class FillResponse implements Parcelable {
        return mAuthentication;
        return mAuthentication;
    }
    }


    /** @hide */
    public @Nullable AutofillId[] getAuthenticationIds() {
        return mAuthenticationIds;
    }

    /**
    /**
     * Builder for {@link FillResponse} objects. You must to provide at least
     * Builder for {@link FillResponse} objects. You must to provide at least
     * one dataset or set an authentication intent with a presentation view.
     * one dataset or set an authentication intent with a presentation view.
@@ -179,6 +188,7 @@ public final class FillResponse implements Parcelable {
        private Bundle mExtras;
        private Bundle mExtras;
        private RemoteViews mPresentation;
        private RemoteViews mPresentation;
        private IntentSender mAuthentication;
        private IntentSender mAuthentication;
        private AutofillId[] mAuthenticationIds;
        private boolean mDestroyed;
        private boolean mDestroyed;


        /**
        /**
@@ -193,7 +203,7 @@ public final class FillResponse implements Parcelable {
         * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
         * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
         * activity which implements your authentication flow. Also if you provide an auth
         * activity which implements your authentication flow. Also if you provide an auth
         * intent you also need to specify the presentation view to be shown in the fill UI
         * intent you also need to specify the presentation view to be shown in the fill UI
         * for the user to trigger your authentication flow.</p>
         * for the user to trigger your authentication flow.
         *
         *
         * <p>When a user triggers autofill, the system launches the provided intent
         * <p>When a user triggers autofill, the system launches the provided intent
         * whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
         * whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
@@ -205,34 +215,48 @@ public final class FillResponse implements Parcelable {
         * user's data was locked and marked that the response needs an authentication then
         * user's data was locked and marked that the response needs an authentication then
         * in the response returned if authentication succeeds you need to provide all
         * in the response returned if authentication succeeds you need to provide all
         * available data sets some of which may need to be further authenticated, for
         * available data sets some of which may need to be further authenticated, for
         * example a credit card whose CVV needs to be entered.</p>
         * example a credit card whose CVV needs to be entered.
         *
         *
         * <p>If you provide an authentication intent you must also provide a presentation
         * <p>If you provide an authentication intent you must also provide a presentation
         * which is used to visualize visualize the response for triggering the authentication
         * which is used to visualize visualize the response for triggering the authentication
         * flow.</p>
         * flow.
         *
         *
         * <p></><strong>Note:</strong> Do not make the provided pending intent
         * <p></><strong>Note:</strong> Do not make the provided pending intent
         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
         * platform needs to fill in the authentication arguments.</p>
         * platform needs to fill in the authentication arguments.
         *
         *
         * @param authentication Intent to an activity with your authentication flow.
         * @param authentication Intent to an activity with your authentication flow.
         * @param presentation The presentation to visualize the response.
         * @param presentation The presentation to visualize the response.
         * @return This builder.
         * @param ids id of Views that when focused will display the authentication UI affordance.
         *
         *
         * @return This builder.
         * @see android.app.PendingIntent#getIntentSender()
         * @see android.app.PendingIntent#getIntentSender()
         */
         */
        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
        public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
                @Nullable RemoteViews presentation) {
                @Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
            throwIfDestroyed();
            throwIfDestroyed();
            // TODO(b/33197203): assert ids is not null nor empty once old version is removed
            if (authentication == null ^ presentation == null) {
            if (authentication == null ^ presentation == null) {
                throw new IllegalArgumentException("authentication and presentation"
                throw new IllegalArgumentException("authentication and presentation"
                        + " must be both non-null or null");
                        + " must be both non-null or null");
            }
            }
            mAuthentication = authentication;
            mAuthentication = authentication;
            mPresentation = presentation;
            mPresentation = presentation;
            mAuthenticationIds = ids;
            return this;
            return this;
        }
        }


        /**
         * TODO(b/33197203): will be removed once clients use the version that takes ids
         * @hide
         * @deprecated
         */
        @Deprecated
        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication,
                @Nullable RemoteViews presentation) {
            return setAuthentication(null, authentication, presentation);
        }

        /**
        /**
         * Adds a new {@link Dataset} to this response.
         * Adds a new {@link Dataset} to this response.
         *
         *
@@ -282,6 +306,7 @@ public final class FillResponse implements Parcelable {
            return this;
            return this;
        }
        }



        /**
        /**
         * Builds a new {@link FillResponse} instance. You must provide at least
         * Builds a new {@link FillResponse} instance. You must provide at least
         * one dataset or some savable ids or an authentication with a presentation
         * one dataset or some savable ids or an authentication with a presentation
@@ -320,6 +345,8 @@ public final class FillResponse implements Parcelable {
                .append(", hasExtras=").append(mExtras != null)
                .append(", hasExtras=").append(mExtras != null)
                .append(", hasPresentation=").append(mPresentation != null)
                .append(", hasPresentation=").append(mPresentation != null)
                .append(", hasAuthentication=").append(mAuthentication != null)
                .append(", hasAuthentication=").append(mAuthentication != null)
                .append(", authenticationSize=").append(mAuthenticationIds != null
                        ? mAuthenticationIds.length : "N/A")
                .toString();
                .toString();
    }
    }


@@ -337,6 +364,7 @@ public final class FillResponse implements Parcelable {
        parcel.writeTypedArrayList(mDatasets, flags);
        parcel.writeTypedArrayList(mDatasets, flags);
        parcel.writeParcelable(mSaveInfo, flags);
        parcel.writeParcelable(mSaveInfo, flags);
        parcel.writeParcelable(mExtras, flags);
        parcel.writeParcelable(mExtras, flags);
        parcel.writeParcelableArray(mAuthenticationIds, flags);
        parcel.writeParcelable(mAuthentication, flags);
        parcel.writeParcelable(mAuthentication, flags);
        parcel.writeParcelable(mPresentation, flags);
        parcel.writeParcelable(mPresentation, flags);
    }
    }
@@ -356,8 +384,8 @@ public final class FillResponse implements Parcelable {
            }
            }
            builder.setSaveInfo(parcel.readParcelable(null));
            builder.setSaveInfo(parcel.readParcelable(null));
            builder.setExtras(parcel.readParcelable(null));
            builder.setExtras(parcel.readParcelable(null));
            builder.setAuthentication(parcel.readParcelable(null),
            builder.setAuthentication(parcel.readParcelableArray(null, AutofillId.class),
                    parcel.readParcelable(null));
                    parcel.readParcelable(null), parcel.readParcelable(null));
            return builder.build();
            return builder.build();
        }
        }