diff --git a/api/current.txt b/api/current.txt index 1bdb49f10e287..f9cfc68ba4336 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47604,6 +47604,7 @@ package android.view.autofill { 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 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index c5a4bbc77bcad..839bde3aa28c8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -51070,6 +51070,7 @@ package android.view.autofill { 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 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 133deb6735751..6bfdafec283d3 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -47973,6 +47973,7 @@ package android.view.autofill { 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 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 244aba7e90347..b852aabe3b3de 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -196,6 +196,9 @@ public final class AutofillManager { ensureServiceClientAddedIfNeeded(); if (!mEnabled) { + if (mCallback != null) { + mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } return; } @@ -241,6 +244,10 @@ public final class AutofillManager { ensureServiceClientAddedIfNeeded(); if (!mEnabled) { + if (mCallback != null) { + mCallback.onAutofillEventVirtual(view, childId, + AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } return; } @@ -538,6 +545,15 @@ public final class AutofillManager { */ public static final int EVENT_INPUT_HIDDEN = 2; + /** + * The auto-fill input UI affordance associated with the view won't be shown because + * autofill is not available. + * + *

If the view provides its own auto-complete UI affordance but was not displaying it + * to avoid flickering, it could shown it upon receiving this event. + */ + public static final int EVENT_INPUT_UNAVAILABLE = 3; + /** * Called after a change in the autofill state associated with a view. * diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 31587867000f1..cde39468244cc 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -69,6 +69,8 @@ import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; +import android.view.autofill.AutofillManager.AutofillCallback; + import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -674,9 +676,17 @@ final class AutofillManagerServiceImpl { public void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName) { if (response == null) { + // Nothing to be done, but need to notify client. + notifyUnavailableToClient(); removeSelf(); return; } + + if ((response.getDatasets() == null || response.getDatasets().isEmpty()) + && response.getAuthentication() == null) { + // Response is "empty" from an UI point of view, need to notify client. + notifyUnavailableToClient(); + } synchronized (mLock) { processResponseLocked(response); } @@ -1091,6 +1101,15 @@ final class AutofillManagerServiceImpl { } } + private void notifyUnavailableToClient() { + if (mCurrentViewState == null) { + // TODO(b/33197203): temporary sanity check; should never happen + Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null"); + return; + } + notifyChangeToClient(mCurrentViewState.mId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } + private void processResponseLocked(FillResponse response) { if (DEBUG) { Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication() @@ -1099,7 +1118,7 @@ final class AutofillManagerServiceImpl { if (mCurrentViewState == null) { // TODO(b/33197203): temporary sanity check; should never happen - Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null"); + Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null"); return; }