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

Commit e6ae2241 authored by TYM Tsai's avatar TYM Tsai Committed by Android (Google) Code Review
Browse files

Merge "Make TextView do not show IME when fill dialog popup" into tm-dev

parents 530587fb 8f502801
Loading
Loading
Loading
Loading
+16 −5
Original line number Original line Diff line number Diff line
@@ -105,6 +105,12 @@ public final class FillRequest implements Parcelable {
     */
     */
    public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;
    public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;


    /**
     * Indicates the ime is showing while request coming.
     * @hide
     */
    public static final @RequestFlags int FLAG_IME_SHOWING = 0x80;

    /** @hide */
    /** @hide */
    public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
    public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;


@@ -201,7 +207,8 @@ public final class FillRequest implements Parcelable {
        FLAG_COMPATIBILITY_MODE_REQUEST,
        FLAG_COMPATIBILITY_MODE_REQUEST,
        FLAG_PASSWORD_INPUT_TYPE,
        FLAG_PASSWORD_INPUT_TYPE,
        FLAG_VIEW_NOT_FOCUSED,
        FLAG_VIEW_NOT_FOCUSED,
        FLAG_SUPPORTS_FILL_DIALOG
        FLAG_SUPPORTS_FILL_DIALOG,
        FLAG_IME_SHOWING
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    @DataClass.Generated.Member
    @DataClass.Generated.Member
@@ -227,6 +234,8 @@ public final class FillRequest implements Parcelable {
                    return "FLAG_VIEW_NOT_FOCUSED";
                    return "FLAG_VIEW_NOT_FOCUSED";
            case FLAG_SUPPORTS_FILL_DIALOG:
            case FLAG_SUPPORTS_FILL_DIALOG:
                    return "FLAG_SUPPORTS_FILL_DIALOG";
                    return "FLAG_SUPPORTS_FILL_DIALOG";
            case FLAG_IME_SHOWING:
                    return "FLAG_IME_SHOWING";
            default: return Integer.toHexString(value);
            default: return Integer.toHexString(value);
        }
        }
    }
    }
@@ -302,7 +311,8 @@ public final class FillRequest implements Parcelable {
                        | FLAG_COMPATIBILITY_MODE_REQUEST
                        | FLAG_COMPATIBILITY_MODE_REQUEST
                        | FLAG_PASSWORD_INPUT_TYPE
                        | FLAG_PASSWORD_INPUT_TYPE
                        | FLAG_VIEW_NOT_FOCUSED
                        | FLAG_VIEW_NOT_FOCUSED
                        | FLAG_SUPPORTS_FILL_DIALOG);
                        | FLAG_SUPPORTS_FILL_DIALOG
                        | FLAG_IME_SHOWING);
        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
        this.mDelayedFillIntentSender = delayedFillIntentSender;
        this.mDelayedFillIntentSender = delayedFillIntentSender;


@@ -462,7 +472,8 @@ public final class FillRequest implements Parcelable {
                        | FLAG_COMPATIBILITY_MODE_REQUEST
                        | FLAG_COMPATIBILITY_MODE_REQUEST
                        | FLAG_PASSWORD_INPUT_TYPE
                        | FLAG_PASSWORD_INPUT_TYPE
                        | FLAG_VIEW_NOT_FOCUSED
                        | FLAG_VIEW_NOT_FOCUSED
                        | FLAG_SUPPORTS_FILL_DIALOG);
                        | FLAG_SUPPORTS_FILL_DIALOG
                        | FLAG_IME_SHOWING);
        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
        this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
        this.mDelayedFillIntentSender = delayedFillIntentSender;
        this.mDelayedFillIntentSender = delayedFillIntentSender;


@@ -484,10 +495,10 @@ public final class FillRequest implements Parcelable {
    };
    };


    @DataClass.Generated(
    @DataClass.Generated(
            time = 1647644111186L,
            time = 1647856966565L,
            codegenVersion = "1.0.23",
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
            sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
    @Deprecated
    @Deprecated
    private void __metadata() {}
    private void __metadata() {}


+54 −12
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.view.autofill;
package android.view.autofill;


import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
@@ -70,6 +71,7 @@ import android.view.ContentInfo;
import android.view.KeyEvent;
import android.view.KeyEvent;
import android.view.View;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager;
@@ -647,6 +649,9 @@ public final class AutofillManager {


    private final boolean mIsFillDialogEnabled;
    private final boolean mIsFillDialogEnabled;


    // Indicates whether called the showAutofillDialog() method.
    private boolean mShowAutofillDialogCalled = false;

    /** @hide */
    /** @hide */
    public interface AutofillClient {
    public interface AutofillClient {
        /**
        /**
@@ -1103,6 +1108,14 @@ public final class AutofillManager {
        notifyViewEntered(view, flags);
        notifyViewEntered(view, flags);
    }
    }


    private int getImeStateFlag(View v) {
        final WindowInsets rootWindowInsets = v.getRootWindowInsets();
        if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) {
            return FLAG_IME_SHOWING;
        }
        return 0;
    }

    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private boolean shouldIgnoreViewEnteredLocked(@NonNull AutofillId id, int flags) {
    private boolean shouldIgnoreViewEnteredLocked(@NonNull AutofillId id, int flags) {
        if (isDisabledByServiceLocked()) {
        if (isDisabledByServiceLocked()) {
@@ -1182,6 +1195,8 @@ public final class AutofillManager {
                    flags |= FLAG_PASSWORD_INPUT_TYPE;
                    flags |= FLAG_PASSWORD_INPUT_TYPE;
                }
                }


                flags |= getImeStateFlag(view);

                if (!isActiveLocked()) {
                if (!isActiveLocked()) {
                    // Starts new session.
                    // Starts new session.
                    startSessionLocked(id, null, value, flags);
                    startSessionLocked(id, null, value, flags);
@@ -1358,6 +1373,8 @@ public final class AutofillManager {
                    flags |= FLAG_PASSWORD_INPUT_TYPE;
                    flags |= FLAG_PASSWORD_INPUT_TYPE;
                }
                }


                flags |= getImeStateFlag(view);

                if (!isActiveLocked()) {
                if (!isActiveLocked()) {
                    // Starts new session.
                    // Starts new session.
                    startSessionLocked(id, bounds, null, flags);
                    startSessionLocked(id, bounds, null, flags);
@@ -1473,7 +1490,7 @@ public final class AutofillManager {
                value = view.getAutofillValue();
                value = view.getAutofillValue();
            }
            }


            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, getImeStateFlag(view));
        }
        }
    }
    }


@@ -1498,7 +1515,7 @@ public final class AutofillManager {
            }
            }


            final AutofillId id = getAutofillId(view, virtualId);
            final AutofillId id = getAutofillId(view, virtualId);
            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
            updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, getImeStateFlag(view));
        }
        }
    }
    }


@@ -2057,6 +2074,8 @@ public final class AutofillManager {
        mIdShownFillUi = null;
        mIdShownFillUi = null;
        mIsFillRequested = false;
        mIsFillRequested = false;
        mRequireAutofill = false;
        mRequireAutofill = false;
        mShowAutofillDialogCalled = false;
        mFillDialogTriggerIds = null;
        if (resetEnteredIds) {
        if (resetEnteredIds) {
            mEnteredIds = null;
            mEnteredIds = null;
        }
        }
@@ -3051,8 +3070,9 @@ public final class AutofillManager {
     * dialog-style UI</a> are available for {@code view}, shows a dialog allowing the user to
     * dialog-style UI</a> are available for {@code view}, shows a dialog allowing the user to
     * select a suggestion and returns {@code true}.
     * select a suggestion and returns {@code true}.
     * <p>
     * <p>
     * The dialog may not be available if the autofill service does not support it, or if the
     * The dialog may not be shown if the autofill service does not support it, if the autofill
     * autofill request has not returned a response yet.
     * request has not returned a response yet, if the dialog was shown previously, or if the
     * input method is already shown.
     * <p>
     * <p>
     * It is recommended apps to call this method the first time a user focuses on
     * It is recommended apps to call this method the first time a user focuses on
     * an autofill-able form, and to avoid showing the input method if the dialog is shown. If
     * an autofill-able form, and to avoid showing the input method if the dialog is shown. If
@@ -3068,9 +3088,16 @@ public final class AutofillManager {
    // TODO(b/210926084): Consider whether to include the one-time show logic within this method.
    // TODO(b/210926084): Consider whether to include the one-time show logic within this method.
    public boolean showAutofillDialog(@NonNull View view) {
    public boolean showAutofillDialog(@NonNull View view) {
        Objects.requireNonNull(view);
        Objects.requireNonNull(view);
        if (shouldShowAutofillDialog(view.getAutofillId())) {
        if (shouldShowAutofillDialog(view, view.getAutofillId())) {
            // If the id matches a trigger id, this will trigger the fill dialog.
            mShowAutofillDialogCalled = true;
            notifyViewEntered(view);
            final WeakReference<View> wrView = new WeakReference<>(view);
            // The id matches a trigger id, this will trigger the fill dialog.
            post(() -> {
                final View v = wrView.get();
                if (v != null) {
                    notifyViewEntered(v);
                }
            });
            return true;
            return true;
        }
        }
        return false;
        return false;
@@ -3099,18 +3126,33 @@ public final class AutofillManager {
     */
     */
    public boolean showAutofillDialog(@NonNull View view, int virtualId) {
    public boolean showAutofillDialog(@NonNull View view, int virtualId) {
        Objects.requireNonNull(view);
        Objects.requireNonNull(view);
        if (shouldShowAutofillDialog(getAutofillId(view, virtualId))) {
        if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) {
            // If the id matches a trigger id, this will trigger the fill dialog.
            mShowAutofillDialogCalled = true;
            notifyViewEntered(view, virtualId, /* bounds= */ null, /* flags= */ 0);
            final WeakReference<View> wrView = new WeakReference<>(view);
            // The id matches a trigger id, this will trigger the fill dialog.
            post(() -> {
                final View v = wrView.get();
                if (v != null) {
                    notifyViewEntered(v, virtualId, /* bounds= */ null, /* flags= */ 0);
                }
            });
            return true;
            return true;
        }
        }
        return false;
        return false;
    }
    }


    private boolean shouldShowAutofillDialog(AutofillId id) {
    private boolean shouldShowAutofillDialog(View view, AutofillId id) {
        if (!hasFillDialogUiFeature() || mFillDialogTriggerIds == null) {
        if (!hasFillDialogUiFeature()
                || mShowAutofillDialogCalled
                || mFillDialogTriggerIds == null) {
            return false;
            return false;
        }
        }

        if (getImeStateFlag(view) == FLAG_IME_SHOWING) {
            // IME is showing
            return false;
        }

        final int size = mFillDialogTriggerIds.size();
        final int size = mFillDialogTriggerIds.size();
        for (int i = 0; i < size; i++) {
        for (int i = 0; i < size; i++) {
            AutofillId fillId = mFillDialogTriggerIds.get(i);
            AutofillId fillId = mFillDialogTriggerIds.get(i);
+18 −1
Original line number Original line Diff line number Diff line
@@ -11458,7 +11458,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                // Show the IME, except when selecting in read-only text.
                // Show the IME, except when selecting in read-only text.
                final InputMethodManager imm = getInputMethodManager();
                final InputMethodManager imm = getInputMethodManager();
                viewClicked(imm);
                viewClicked(imm);
                if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null
                        && !showAutofillDialog()) {
                    imm.showSoftInput(this, 0);
                    imm.showSoftInput(this, 0);
                }
                }
@@ -11476,6 +11477,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return superResult;
        return superResult;
    }
    }
    /**
     * The fill dialog UI is a more conspicuous and efficient interface than dropdown UI.
     * If autofill suggestions are available when the user clicks on a field that supports filling
     * the dialog UI, Autofill will pop up a fill dialog. The dialog will take up a larger area
     * to display the datasets, so it is easy for users to pay attention to the datasets and
     * selecting a dataset. The autofill dialog is shown as the bottom sheet, the better
     * experience is not to show the IME if there is a fill dialog.
     */
    private boolean showAutofillDialog() {
        final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
        if (afm != null) {
            return afm.showAutofillDialog(this);
        }
        return false;
    }
    @Override
    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
    public boolean onGenericMotionEvent(MotionEvent event) {
        if (mMovement != null && mText instanceof Spannable && mLayout != null) {
        if (mMovement != null && mText instanceof Spannable && mLayout != null) {
+8 −3
Original line number Original line Diff line number Diff line
@@ -3182,7 +3182,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState


    @Override
    @Override
    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
            @Nullable AutofillValue value) {
            @Nullable AutofillValue value, int flags) {
        synchronized (mLock) {
        synchronized (mLock) {
            if (mDestroyed) {
            if (mDestroyed) {
                Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
                Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
@@ -3207,7 +3207,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            return;
            return;
        }
        }


        if (requestShowFillDialog(response, filledId, filterText)) {
        if (requestShowFillDialog(response, filledId, filterText, flags)) {
            synchronized (mLock) {
            synchronized (mLock) {
                final ViewState currentView = mViewStates.get(mCurrentViewId);
                final ViewState currentView = mViewStates.get(mCurrentViewId);
                currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
                currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
@@ -3312,12 +3312,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    }
    }


    private boolean requestShowFillDialog(FillResponse response,
    private boolean requestShowFillDialog(FillResponse response,
            AutofillId filledId, String filterText) {
            AutofillId filledId, String filterText, int flags) {
        if (!isFillDialogUiEnabled()) {
        if (!isFillDialogUiEnabled()) {
            // Unsupported fill dialog UI
            // Unsupported fill dialog UI
            return false;
            return false;
        }
        }


        if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) {
            // IME is showing, fallback to normal suggestions UI
            return false;
        }

        final AutofillId[] ids = response.getFillDialogTriggerIds();
        final AutofillId[] ids = response.getFillDialogTriggerIds();
        if (ids == null || !ArrayUtils.contains(ids, filledId)) {
        if (ids == null || !ArrayUtils.contains(ids, filledId)) {
            return false;
            return false;
+3 −3
Original line number Original line Diff line number Diff line
@@ -43,7 +43,7 @@ final class ViewState {
         * Called when the fill UI is ready to be shown for this view.
         * Called when the fill UI is ready to be shown for this view.
         */
         */
        void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
        void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
                @Nullable AutofillValue value);
                @Nullable AutofillValue value, int flags);
    }
    }


    private static final String TAG = "ViewState";
    private static final String TAG = "ViewState";
@@ -202,7 +202,7 @@ final class ViewState {


    /**
    /**
     * Calls {@link
     * Calls {@link
     * Listener#onFillReady(FillResponse, AutofillId, AutofillValue)} if the
     * Listener#onFillReady(FillResponse, AutofillId, AutofillValue, int)} if the
     * fill UI is ready to be displayed (i.e. when response and bounds are set).
     * fill UI is ready to be displayed (i.e. when response and bounds are set).
     */
     */
    void maybeCallOnFillReady(int flags) {
    void maybeCallOnFillReady(int flags) {
@@ -213,7 +213,7 @@ final class ViewState {
        // First try the current response associated with this View.
        // First try the current response associated with this View.
        if (mResponse != null) {
        if (mResponse != null) {
            if (mResponse.getDatasets() != null || mResponse.getAuthentication() != null) {
            if (mResponse.getDatasets() != null || mResponse.getAuthentication() != null) {
                mListener.onFillReady(mResponse, this.id, mCurrentValue);
                mListener.onFillReady(mResponse, this.id, mCurrentValue, flags);
            }
            }
        }
        }
    }
    }