summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/app/Activity.java11
-rw-r--r--core/java/android/view/View.java62
-rw-r--r--core/java/android/view/autofill/AutofillManager.java48
4 files changed, 113 insertions, 10 deletions
diff --git a/api/current.txt b/api/current.txt
index 18a900c5bec8..57271d6946a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -47617,6 +47617,7 @@ package android.view {
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHints(java.lang.String...);
+ method public void setAutofillId(android.view.autofill.AutofillId);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -49780,6 +49781,7 @@ package android.view.autofill {
method public android.content.ComponentName getAutofillServiceComponentName();
method public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
method public java.lang.String getDefaultFieldClassificationAlgorithm();
+ method public android.view.autofill.AutofillId getNextAutofillId();
method public android.service.autofill.UserData getUserData();
method public java.lang.String getUserDataId();
method public boolean hasEnabledAutofillServices();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a45c50060e17..3ebe89f3a487 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1400,6 +1400,7 @@ public class Activity extends ContextThemeWrapper
*
* {@hide}
*/
+ @Override
public int getNextAutofillId() {
if (mLastAutofillId == Integer.MAX_VALUE - 1) {
mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
@@ -1411,6 +1412,14 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * @hide
+ */
+ @Override
+ public AutofillId autofillClientGetNextAutofillId() {
+ return new AutofillId(getNextAutofillId());
+ }
+
+ /**
* Check whether this activity is running as part of a voice interaction with the user.
* If true, it should perform its interaction with the user through the
* {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
@@ -7752,7 +7761,7 @@ public class Activity extends ContextThemeWrapper
/** @hide */
@Override
- public final boolean autofillIsCompatibilityModeEnabled() {
+ public final boolean autofillClientIsCompatibilityModeEnabled() {
return isAutofillCompatibilityEnabled();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3c7624225eb9..f61b6528bd0e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8144,7 +8144,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Gets the unique identifier of this view in the screen, for autofill purposes.
+ * Gets the unique, logical identifier of this view in the activity, for autofill purposes.
+ *
+ * <p>The autofill id is created on demand, unless it is explicitly set by
+ * {@link #setAutofillId(AutofillId)}.
+ *
+ * <p>See {@link #setAutofillId(AutofillId)} for more info.
*
* @return The View's autofill id.
*/
@@ -8158,6 +8163,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Sets the unique, logical identifier of this view in the activity, for autofill purposes.
+ *
+ * <p>The autofill id is created on demand, and this method should only be called when a view is
+ * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as
+ * that method creates a snapshot of the view that is passed along to the autofill service.
+ *
+ * <p>This method is typically used when view subtrees are recycled to represent different
+ * content* &mdash;in this case, the autofill id can be saved before the view content is swapped
+ * out, and restored later when it's swapped back in. For example:
+ *
+ * <pre>
+ * EditText reusableView = ...;
+ * ViewGroup parentView = ...;
+ * AutofillManager afm = ...;
+ *
+ * // Swap out the view and change its contents
+ * AutofillId oldId = reusableView.getAutofillId();
+ * CharSequence oldText = reusableView.getText();
+ * parentView.removeView(reusableView);
+ * AutofillId newId = afm.getNextAutofillId();
+ * reusableView.setText("New I am");
+ * reusableView.setAutofillId(newId);
+ * parentView.addView(reusableView);
+ *
+ * // Later, swap the old content back in
+ * parentView.removeView(reusableView);
+ * reusableView.setAutofillId(oldId);
+ * reusableView.setText(oldText);
+ * parentView.addView(reusableView);
+ * </pre>
+ *
+ * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view,
+ * or {@code null} to reset it. Usually it's an id previously allocated to another view (and
+ * obtained through {@link #getAutofillId()}), or a new value obtained through
+ * {@link AutofillManager#getNextAutofillId()}.
+ *
+ * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to
+ * a window}.
+ *
+ * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view.
+ */
+ public void setAutofillId(@Nullable AutofillId id) {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(VIEW_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id);
+ }
+ if (isAttachedToWindow()) {
+ throw new IllegalStateException("Cannot set autofill id when view is attached");
+ }
+ if (id.isVirtual()) {
+ throw new IllegalStateException("Cannot set autofill id assigned to virtual views");
+ }
+ mAutofillId = id;
+ }
+
+ /**
* Describes the autofill type of this view, so an
* {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue}
* when autofilling the view.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index dd9b69ffcb07..a4261ebe16a0 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -498,7 +498,17 @@ public final class AutofillManager {
/**
* @return Whether compatibility mode is enabled.
*/
- boolean autofillIsCompatibilityModeEnabled();
+ boolean autofillClientIsCompatibilityModeEnabled();
+
+ /**
+ * Gets the next unique autofill ID.
+ *
+ * <p>Typically used to manage views whose content is recycled - see
+ * {@link View#setAutofillId(AutofillId)} for more info.
+ *
+ * @return An ID that is unique in the activity.
+ */
+ @Nullable AutofillId autofillClientGetNextAutofillId();
}
/**
@@ -781,7 +791,7 @@ public final class AutofillManager {
/** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
- final AutofillId id = getAutofillId(view);
+ final AutofillId id = view.getAutofillId();
if (shouldIgnoreViewEnteredLocked(id, flags)) return null;
AutofillCallback callback = null;
@@ -831,7 +841,7 @@ public final class AutofillManager {
if (mEnabled && isActiveLocked()) {
// dont notify exited when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view);
+ final AutofillId id = view.getAutofillId();
// Update focus on existing session.
updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
@@ -874,6 +884,7 @@ public final class AutofillManager {
if (mEnabled && isActiveLocked()) {
final AutofillId id = virtual ? getAutofillId(view, virtualId)
: view.getAutofillId();
+ if (sVerbose) Log.v(TAG, "visibility changed for " + id + ": " + isVisible);
if (!isVisible && mFillableIds != null) {
if (mFillableIds.contains(id)) {
if (sDebug) Log.d(TAG, "Hidding UI when view " + id + " became invisible");
@@ -882,6 +893,8 @@ public final class AutofillManager {
}
if (mTrackedViews != null) {
mTrackedViews.notifyViewVisibilityChangedLocked(id, isVisible);
+ } else if (sVerbose) {
+ Log.v(TAG, "Ignoring visibility change on " + id + ": no tracked views");
}
}
}
@@ -1012,7 +1025,7 @@ public final class AutofillManager {
if (mLastAutofilledData == null) {
view.setAutofilled(false);
} else {
- id = getAutofillId(view);
+ id = view.getAutofillId();
if (mLastAutofilledData.containsKey(id)) {
value = view.getAutofillValue();
valueWasRead = true;
@@ -1037,7 +1050,7 @@ public final class AutofillManager {
}
if (id == null) {
- id = getAutofillId(view);
+ id = view.getAutofillId();
}
if (!valueWasRead) {
@@ -1437,8 +1450,27 @@ public final class AutofillManager {
}
}
- private static AutofillId getAutofillId(View view) {
- return new AutofillId(view.getAutofillViewId());
+ /**
+ * Gets the next unique autofill ID for the activity context.
+ *
+ * <p>Typically used to manage views whose content is recycled - see
+ * {@link View#setAutofillId(AutofillId)} for more info.
+ *
+ * @return An ID that is unique in the activity, or {@code null} if autofill is not supported in
+ * the {@link Context} associated with this {@link AutofillManager}.
+ */
+ @Nullable
+ public AutofillId getNextAutofillId() {
+ final AutofillClient client = getClient();
+ if (client == null) return null;
+
+ final AutofillId id = client.autofillClientGetNextAutofillId();
+
+ if (id == null && sDebug) {
+ Log.d(TAG, "getNextAutofillId(): client " + client + " returned null");
+ }
+
+ return id;
}
private static AutofillId getAutofillId(View parent, int virtualId) {
@@ -1739,7 +1771,7 @@ public final class AutofillManager {
if (mLastAutofilledData == null) {
mLastAutofilledData = new ParcelableMap(1);
}
- mLastAutofilledData.put(getAutofillId(view), targetValue);
+ mLastAutofilledData.put(view.getAutofillId(), targetValue);
}
view.setAutofilled(true);
}