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

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

Provided an AutofillCallback API.

Some custom views - like WebView - might have their own auto-complete mechanism,
so we need to provide a way for them to know when the auto-fill UI is shown or
hidden.

Fixes: 35948429
Test: CtsAutoFillServiceTestCases (with new tests) pass
Test: m update-api
Test: manual verification

Change-Id: I5682a3b9645d5d077a4a2446e79256d6f77b4b5a
parent eb7ca5ca
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -47436,17 +47436,27 @@ package android.view.autofill {
  }
  public final class AutoFillManager {
    method public void registerCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void reset();
    method public void startAutoFillRequest(android.view.View);
    method public void startAutoFillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
    method public void stopAutoFillRequest(android.view.View);
    method public void stopAutoFillRequestOnVirtualView(android.view.View, int);
    method public void unregisterCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void valueChanged(android.view.View);
    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
  }
  public static abstract class AutoFillManager.AutofillCallback {
    ctor public AutoFillManager.AutofillCallback();
    method public void onAutofillEvent(android.view.View, int);
    method public void onAutofillEventVirtual(android.view.View, int, int);
    field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
    field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
  }
  public final class AutoFillType implements android.os.Parcelable {
    method public int describeContents();
    method public static android.view.autofill.AutoFillType forDate();
+10 −0
Original line number Diff line number Diff line
@@ -50899,17 +50899,27 @@ package android.view.autofill {
  }
  public final class AutoFillManager {
    method public void registerCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void reset();
    method public void startAutoFillRequest(android.view.View);
    method public void startAutoFillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
    method public void stopAutoFillRequest(android.view.View);
    method public void stopAutoFillRequestOnVirtualView(android.view.View, int);
    method public void unregisterCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void valueChanged(android.view.View);
    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
  }
  public static abstract class AutoFillManager.AutofillCallback {
    ctor public AutoFillManager.AutofillCallback();
    method public void onAutofillEvent(android.view.View, int);
    method public void onAutofillEventVirtual(android.view.View, int, int);
    field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
    field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
  }
  public final class AutoFillType implements android.os.Parcelable {
    method public int describeContents();
    method public static android.view.autofill.AutoFillType forDate();
+10 −0
Original line number Diff line number Diff line
@@ -47805,17 +47805,27 @@ package android.view.autofill {
  }
  public final class AutoFillManager {
    method public void registerCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void reset();
    method public void startAutoFillRequest(android.view.View);
    method public void startAutoFillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
    method public void stopAutoFillRequest(android.view.View);
    method public void stopAutoFillRequestOnVirtualView(android.view.View, int);
    method public void unregisterCallback(android.view.autofill.AutoFillManager.AutofillCallback);
    method public void valueChanged(android.view.View);
    method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutoFillValue);
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
  }
  public static abstract class AutoFillManager.AutofillCallback {
    ctor public AutoFillManager.AutofillCallback();
    method public void onAutofillEvent(android.view.View, int);
    method public void onAutofillEventVirtual(android.view.View, int, int);
    field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
    field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
  }
  public final class AutoFillType implements android.os.Parcelable {
    method public int describeContents();
    method public static android.view.autofill.AutoFillType forDate();
+138 −4
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package android.view.autofill;
import static android.view.autofill.Helper.DEBUG;
import static android.view.autofill.Helper.VERBOSE;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -30,7 +32,10 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.WindowManagerGlobal;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.List;

@@ -76,6 +81,8 @@ public final class AutoFillManager {
    private final IAutoFillManager mService;
    private IAutoFillManagerClient mServiceClient;

    private AutofillCallback mCallback;

    private Context mContext;

    private boolean mHasSession;
@@ -276,11 +283,11 @@ public final class AutoFillManager {
        }
    }

    private AutoFillId getAutoFillId(View view) {
    private static AutoFillId getAutoFillId(View view) {
        return new AutoFillId(view.getAccessibilityViewId());
    }

    private AutoFillId getAutoFillId(View parent, int childId) {
    private static AutoFillId getAutoFillId(View parent, int childId) {
        return new AutoFillId(parent.getAccessibilityViewId(), childId);
    }

@@ -289,10 +296,12 @@ public final class AutoFillManager {
        if (DEBUG) {
            Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value);
        }

        try {
            mService.startSession(mContext.getActivityToken(), windowToken,
                    mServiceClient.asBinder(), id, bounds, value, mContext.getUserId());
            AutoFillClient client = getClient();
                    mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                    mCallback != null);
            final AutoFillClient client = getClient();
            if (client != null) {
                client.resetableStateAvailable();
            }
@@ -344,6 +353,119 @@ public final class AutoFillManager {
        }
    }

    /**
     * Registers a {@link AutofillCallback} to receive autofill events.
     *
     * @param callback callback to receive events.
     */
    public void registerCallback(@Nullable AutofillCallback callback) {
        if (callback == null) return;

        final boolean hadCallback = mCallback != null;
        mCallback = callback;

        if (mHasSession && !hadCallback) {
            try {
                mService.setHasCallback(mContext.getActivityToken(), mContext.getUserId(), true);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

    /**
     * Unregisters a {@link AutofillCallback} to receive autofill events.
     *
     * @param callback callback to stop receiving events.
     */
    public void unregisterCallback(@Nullable AutofillCallback callback) {
        if (callback == null || mCallback == null || callback != mCallback) return;

        mCallback = null;

        if (mHasSession) {
            try {
                mService.setHasCallback(mContext.getActivityToken(), mContext.getUserId(), false);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

    private void onAutofillEvent(IBinder windowToken, AutoFillId id, int event) {
        if (mCallback == null) return;
        if (id == null) {
            Log.w(TAG, "onAutofillEvent(): no id for event " + event);
            return;
        }

        final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
        if (root == null) {
            Log.w(TAG, "onAutofillEvent() for " + id + ": root view gone");
            return;
        }
        final View view = root.findViewByAccessibilityIdTraversal(id.getViewId());
        if (view == null) {
            Log.w(TAG, "onAutofillEvent() for " + id + ": view gone");
            return;
        }
        if (id.isVirtual()) {
            mCallback.onAutofillEventVirtual(view, id.getVirtualChildId(), event);
        } else {
            mCallback.onAutofillEvent(view, event);
        }
    }

    /**
     * Callback for auto-fill related events.
     *
     * <p>Typically used for applications that display their own "auto-complete" views, so they can
     * enable / disable such views when the auto-fill UI affordance is shown / hidden.
     */
    public abstract static class AutofillCallback {

        /** @hide */
        @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
        @Retention(RetentionPolicy.SOURCE)
        public @interface AutofillEventType {}

        /**
         * The auto-fill input UI affordance associated with the view was shown.
         *
         * <p>If the view provides its own auto-complete UI affordance and its currently shown, it
         * should be hidden upon receiving this event.
         */
        public static final int EVENT_INPUT_SHOWN = 1;

        /**
         * The auto-fill input UI affordance associated with the view was hidden.
         *
         * <p>If the view provides its own auto-complete UI affordance that was hidden upon a
         * {@link #EVENT_INPUT_SHOWN} event, it could be shown again now.
         */
        public static final int EVENT_INPUT_HIDDEN = 2;

        /**
         * Called after a change in the autofill state associated with a view.
         *
         * @param view view associated with the change.
         *
         * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}.
         */
        public void onAutofillEvent(@NonNull View view, @AutofillEventType int event) {}

        /**
         * Called after a change in the autofill state associated with a virtual view.
         *
         * @param view parent view associated with the change.
         * @param childId id identifying the virtual child inside the parent view.
         *
         * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}.
         */
        public void onAutofillEventVirtual(@NonNull View view, int childId,
                @AutofillEventType int event) {}
    }

    private static final class AutoFillManagerClient extends IAutoFillManagerClient.Stub {
        private final WeakReference<AutoFillManager> mAutoFillManager;

@@ -385,5 +507,17 @@ public final class AutoFillManager {
                });
            }
        }

        @Override
        public void onAutofillEvent(IBinder windowToken, AutoFillId id, int event) {
            final AutoFillManager autoFillManager = mAutoFillManager.get();
            if (autoFillManager != null) {
                autoFillManager.mContext.getMainThreadHandler().post(() -> {
                    if (autoFillManager.getClient() != null) {
                        autoFillManager.onAutofillEvent(windowToken, id, event);
                    }
                });
            }
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -31,10 +31,12 @@ import android.view.autofill.IAutoFillManagerClient;
interface IAutoFillManager {
    boolean addClient(in IAutoFillManagerClient client, int userId);
    oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback,
            in AutoFillId autoFillId, in Rect bounds, in AutoFillValue value, int userId);
            in AutoFillId autoFillId, in Rect bounds, in AutoFillValue value, int userId,
            boolean hasCallback);
    oneway void updateSession(in IBinder activityToken, in AutoFillId id, in Rect bounds,
            in AutoFillValue value, int flags, int userId);
    oneway void finishSession(in IBinder activityToken, int userId);
    oneway void setAuthenticationResult(in Bundle data,
            in IBinder activityToken, int userId);
    oneway void setHasCallback(in IBinder activityToken, int userId, boolean hasIt);
}
Loading