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

Commit a48ea52a authored by TYM Tsai's avatar TYM Tsai
Browse files

Adds new API to cancel current session

Provides a way for users to cancel the Autofill UI for cases where
they don't want autofill keep coming up in every fillable fields.

Bug: 115504636
Test: manual
Test: atest CtsAutoFillServiceTestCases
Change-Id: I43de6e1bdfd7fc6e94b5fb8c2f44b9b171501e43
parent a3eb4278
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -41363,6 +41363,7 @@ package android.service.autofill {
    method @NonNull public android.service.autofill.FillResponse build();
    method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
    method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
    method @NonNull public android.service.autofill.FillResponse.Builder setCancelTargetIds(@Nullable int[]);
    method @NonNull public android.service.autofill.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
    method @NonNull public android.service.autofill.FillResponse.Builder setFieldClassificationIds(@NonNull android.view.autofill.AutofillId...);
    method @NonNull public android.service.autofill.FillResponse.Builder setFlags(int);
+36 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ public final class FillResponse implements Parcelable {
    private final int mFlags;
    private int mRequestId;
    private final @Nullable UserData mUserData;
    private final @Nullable int[] mCancelIds;

    private FillResponse(@NonNull Builder builder) {
        mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -101,6 +102,7 @@ public final class FillResponse implements Parcelable {
        mFlags = builder.mFlags;
        mRequestId = INVALID_REQUEST_ID;
        mUserData = builder.mUserData;
        mCancelIds = builder.mCancelIds;
    }

    /** @hide */
@@ -187,6 +189,12 @@ public final class FillResponse implements Parcelable {
        return mRequestId;
    }

    /** @hide */
    @Nullable
    public int[] getCancelIds() {
        return mCancelIds;
    }

    /**
     * Builder for {@link FillResponse} objects. You must to provide at least
     * one dataset or set an authentication intent with a presentation view.
@@ -206,6 +214,7 @@ public final class FillResponse implements Parcelable {
        private int mFlags;
        private boolean mDestroyed;
        private UserData mUserData;
        private int[] mCancelIds;

        /**
         * Triggers a custom UI before before autofilling the screen with any data set in this
@@ -541,6 +550,25 @@ public final class FillResponse implements Parcelable {
            return this;
        }

        /**
         * Sets targets with the resources IDs of the child view of
         * {@link RemoteViews Presentation Template} which will cancel the session when clicked.
         * Those targets will be respectively applied to a child of the header, footer and
         * each {@link Dataset}.
         *
         * @param ids array of the resource id. Empty list or non-existing id has no effect.
         *
         * @return this builder
         *
         * @throws IllegalStateException if {@link #build()} was already called.
         */
        @NonNull
        public Builder setCancelTargetIds(@Nullable int[] ids) {
            throwIfDestroyed();
            mCancelIds = ids;
            return this;
        }

        /**
         * Builds a new {@link FillResponse} instance.
         *
@@ -639,6 +667,10 @@ public final class FillResponse implements Parcelable {
        if (mUserData != null) {
            builder.append(", userData=").append(mUserData);
        }
        if (mCancelIds != null) {
            builder.append(", mCancelIds=").append(mCancelIds.length);
        }

        return builder.append("]").toString();
    }

@@ -666,6 +698,8 @@ public final class FillResponse implements Parcelable {
        parcel.writeLong(mDisableDuration);
        parcel.writeParcelableArray(mFieldClassificationIds, flags);
        parcel.writeInt(mFlags);
        parcel.writeIntArray(mCancelIds);

        parcel.writeInt(mRequestId);
    }

@@ -718,6 +752,8 @@ public final class FillResponse implements Parcelable {
                builder.setFieldClassificationIds(fieldClassifactionIds);
            }
            builder.setFlags(parcel.readInt());
            final int[] cancelIds = parcel.createIntArray();
            builder.setCancelTargetIds(cancelIds);

            final FillResponse response = builder.build();
            response.setRequestId(parcel.readInt());
+8 −0
Original line number Diff line number Diff line
@@ -1110,6 +1110,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        }
    }

    // AutoFillUiCallback
    @Override
    public void cancelSession() {
        synchronized (mLock) {
            removeSelfLocked();
        }
    }

    // AutoFillUiCallback
    @Override
    public void startIntentSenderAndFinishSession(IntentSender intentSender) {
+8 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ public final class AutoFillUI {
        void startIntentSenderAndFinishSession(IntentSender intentSender);
        void startIntentSender(IntentSender intentSender, Intent intent);
        void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent);
        void cancelSession();
    }

    public AutoFillUI(@NonNull Context context) {
@@ -272,6 +273,13 @@ public final class AutoFillUI {
                        mCallback.dispatchUnhandledKey(focusedId, keyEvent);
                    }
                }

                @Override
                public void cancelSession() {
                    if (mCallback != null) {
                        mCallback.cancelSession();
                    }
                }
            });
        };

+35 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ final class FillUi {
        void requestHideFillUi();
        void startIntentSender(IntentSender intentSender);
        void dispatchUnhandledKey(KeyEvent keyEvent);
        void cancelSession();
    }

    private final @NonNull Point mTempPoint = new Point();
@@ -263,6 +264,7 @@ final class FillUi {
                mHeader = headerPresentation.applyWithTheme(mContext, null, clickBlocker, mThemeId);
                final LinearLayout headerContainer =
                        decor.findViewById(R.id.autofill_dataset_header);
                applyCancelAction(mHeader, response.getCancelIds());
                if (sVerbose) Slog.v(TAG, "adding header");
                headerContainer.addView(mHeader);
                headerContainer.setVisibility(View.VISIBLE);
@@ -279,6 +281,7 @@ final class FillUi {
                    }
                    mFooter = footerPresentation.applyWithTheme(
                            mContext, null, clickBlocker, mThemeId);
                    applyCancelAction(mFooter, response.getCancelIds());
                    // Footer not supported on some platform e.g. TV
                    if (sVerbose) Slog.v(TAG, "adding footer");
                    footerContainer.addView(mFooter);
@@ -330,6 +333,7 @@ final class FillUi {
                        }
                    }

                    applyCancelAction(view, response.getCancelIds());
                    items.add(new ViewItem(dataset, filterPattern, filterable, valueText, view));
                }
            }
@@ -355,6 +359,37 @@ final class FillUi {
        }
    }

    private void applyCancelAction(View rootView, int[] ids) {
        if (ids == null) {
            return;
        }

        if (sDebug) Slog.d(TAG, "fill UI has " + ids.length + " actions");
        if (!(rootView instanceof ViewGroup)) {
            Slog.w(TAG, "cannot apply actions because fill UI root is not a "
                    + "ViewGroup: " + rootView);
            return;
        }

        // Apply click actions.
        final ViewGroup root = (ViewGroup) rootView;
        for (int i = 0; i < ids.length; i++) {
            final int id = ids[i];
            final View child = root.findViewById(id);
            if (child == null) {
                Slog.w(TAG, "Ignoring cancel action for view " + id
                        + " because it's not on " + root);
                continue;
            }
            child.setOnClickListener((v) -> {
                if (sVerbose) {
                    Slog.v(TAG, "Applying " + id + " after " + v + " was clicked");
                }
                mCallback.cancelSession();
            });
        }
    }

    void requestShowFillUi() {
        mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
    }