Add API for virtual view is ready to user
When the view is ready to the user, notify autofill can do something
if needed before the user start to input. And then autofill start to
prepare suggestions for some features, e.g. a prefill request for the
fill dialog.
Bug: 258077433
Test: atest android.autofillservice.cts.dialog
Change-Id: I0c6c964fb158c2da35b3470528d92d0d5bf74aa7
diff --git a/core/api/current.txt b/core/api/current.txt
index 0ad7d80..16d5607 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -54194,6 +54194,7 @@
method public void notifyViewExited(@NonNull android.view.View, int);
method public void notifyViewVisibilityChanged(@NonNull android.view.View, boolean);
method public void notifyViewVisibilityChanged(@NonNull android.view.View, int, boolean);
+ method public void notifyVirtualViewsReady(@NonNull android.view.View, @NonNull android.util.SparseArray<android.view.autofill.VirtualViewFillInfo>);
method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
method public void requestAutofill(@NonNull android.view.View);
method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
@@ -54240,6 +54241,16 @@
field @NonNull public static final android.os.Parcelable.Creator<android.view.autofill.AutofillValue> CREATOR;
}
+ public final class VirtualViewFillInfo {
+ method @Nullable public String[] getAutofillHints();
+ }
+
+ public static final class VirtualViewFillInfo.Builder {
+ ctor public VirtualViewFillInfo.Builder();
+ method @NonNull public android.view.autofill.VirtualViewFillInfo build();
+ method @NonNull public android.view.autofill.VirtualViewFillInfo.Builder setAutofillHints(@NonNull java.lang.String...);
+ }
+
}
package android.view.contentcapture {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 58e7a70..7569523 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1088,6 +1088,42 @@
}
/**
+ * Called when the virtual views are ready to the user for autofill.
+ *
+ * This method is used to notify autofill system the views are ready to the user. And then
+ * Autofill can do initialization if needed before the user starts to input. For example, do
+ * a pre-fill request for the
+ * <a href="/reference/android/service/autofill/Dataset.html#FillDialogUI">fill dialog</a>.
+ *
+ * @param view the host view that holds a virtual view hierarchy.
+ * @param infos extra information for the virtual views. The key is virtual id which represents
+ * the virtual view in the host view.
+ *
+ * @throws IllegalArgumentException if the {@code infos} was empty
+ */
+ public void notifyVirtualViewsReady(
+ @NonNull View view, @NonNull SparseArray<VirtualViewFillInfo> infos) {
+ Objects.requireNonNull(infos);
+ if (infos.size() == 0) {
+ throw new IllegalArgumentException("No VirtualViewInfo found");
+ }
+ if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
+ && view.isCredential()) {
+ if (sDebug) {
+ Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
+ + view.getAutofillId().toString());
+ }
+ return;
+ }
+ for (int i = 0; i < infos.size(); i++) {
+ final VirtualViewFillInfo info = infos.valueAt(i);
+ final int virtualId = infos.indexOfKey(i);
+ notifyViewReadyInner(getAutofillId(view, virtualId),
+ (info == null) ? null : info.getAutofillHints());
+ }
+ }
+
+ /**
* The {@link AutofillFeatureFlags#DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or
* the view have the allowed autofill hints, performs a fill request to know there is any field
* supported fill dialog.
@@ -1098,9 +1134,6 @@
if (sDebug) {
Log.d(TAG, "notifyViewEnteredForFillDialog:" + v.getAutofillId());
}
- if (!hasAutofillFeature()) {
- return;
- }
if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
&& v.isCredential()) {
if (sDebug) {
@@ -1109,6 +1142,13 @@
}
return;
}
+ notifyViewReadyInner(v.getAutofillId(), v.getAutofillHints());
+ }
+
+ private void notifyViewReadyInner(AutofillId id, String[] autofillHints) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (mTrackedViews != null) {
@@ -1116,7 +1156,7 @@
// different pages but in the same Activity. We need to reset the
// mIsFillRequested flag to allow asking for a new FillRequest when
// user switches to other page
- mTrackedViews.checkViewState(v.getAutofillId());
+ mTrackedViews.checkViewState(id);
}
}
@@ -1126,9 +1166,9 @@
}
if (mIsFillDialogEnabled
- || ArrayUtils.containsAny(v.getAutofillHints(), mFillDialogEnabledHints)) {
+ || ArrayUtils.containsAny(autofillHints, mFillDialogEnabledHints)) {
if (sDebug) {
- Log.d(TAG, "Trigger fill request at view entered");
+ Log.d(TAG, "Trigger fill request when the view is ready.");
}
int flags = FLAG_SUPPORTS_FILL_DIALOG;
diff --git a/core/java/android/view/autofill/VirtualViewFillInfo.java b/core/java/android/view/autofill/VirtualViewFillInfo.java
new file mode 100644
index 0000000..4bec5a4
--- /dev/null
+++ b/core/java/android/view/autofill/VirtualViewFillInfo.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.view.View;
+
+import com.android.internal.util.DataClass;
+
+
+/**
+ * Information for the virtual view to the autofill framework.
+ */
+@DataClass(genBuilder = true)
+public final class VirtualViewFillInfo {
+
+ /**
+ * Autofill hints of the virtual view.
+ *
+ * @see View#setAutofillHints(String...)
+ */
+ @Nullable
+ @SuppressLint("NullableCollection")
+ private String[] mAutofillHints;
+
+ private static String[] defaultAutofillHints() {
+ return null;
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/autofill/VirtualViewFillInfo.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ /* package-private */ VirtualViewFillInfo(
+ @Nullable @SuppressLint("NullableCollection") String[] autofillHints) {
+ this.mAutofillHints = autofillHints;
+ com.android.internal.util.AnnotationValidations.validate(
+ SuppressLint.class, null, mAutofillHints,
+ "value", "NullableCollection");
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Autofill hints of the virtual view.
+ *
+ * @see View#setAutofillHints(String...)
+ */
+ @DataClass.Generated.Member
+ public @Nullable @SuppressLint("NullableCollection") String[] getAutofillHints() {
+ return mAutofillHints;
+ }
+
+ /**
+ * A builder for {@link VirtualViewFillInfo}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static final class Builder {
+
+ private @Nullable @SuppressLint("NullableCollection") String[] mAutofillHints;
+
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * Autofill hints of the virtual view.
+ *
+ * @see View#setAutofillHints(String...)
+ */
+ @DataClass.Generated.Member
+ public @android.annotation.NonNull Builder setAutofillHints(@SuppressLint("NullableCollection") @android.annotation.NonNull String... value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mAutofillHints = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @android.annotation.NonNull VirtualViewFillInfo build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mAutofillHints = defaultAutofillHints();
+ }
+ VirtualViewFillInfo o = new VirtualViewFillInfo(
+ mAutofillHints);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1674023010954L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/view/autofill/VirtualViewFillInfo.java",
+ inputSignatures = "private @android.annotation.Nullable @android.annotation.SuppressLint java.lang.String[] mAutofillHints\nprivate static java.lang.String[] defaultAutofillHints()\nclass VirtualViewFillInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}