From 5dc45ca3496e9ff0340adeb83bc875d9282deef9 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 3 Jan 2018 09:02:27 -0800 Subject: [PATCH] Added new Autofill APIs to get name of id used on android:text. Such resource id is useful to help the autofill service heuristics to figure out the meaning of the labels without relying on their localized text. For example, the id could be "username", while the text could be "Nome do usuario". Test: atest CtsAutoFillServiceTestCases:LoginWithStringsActivityTest Fixes: 71552872 Change-Id: I13f7080fb3c67f91492a113115ffa43d185d192a --- api/current.txt | 2 ++ .../android/app/assist/AssistStructure.java | 26 ++++++++++++++-- core/java/android/view/ViewStructure.java | 12 ++++++++ core/java/android/widget/TextView.java | 30 ++++++++++++------- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/api/current.txt b/api/current.txt index 8925846610841..5eb4b6e7939f7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6749,6 +6749,7 @@ package android.app.assist { method public java.lang.CharSequence getText(); method public int getTextBackgroundColor(); method public int getTextColor(); + method public java.lang.String getTextIdEntry(); method public int[] getTextLineBaselines(); method public int[] getTextLineCharOffsets(); method public int getTextSelectionEnd(); @@ -47257,6 +47258,7 @@ package android.view { method public abstract void setSelected(boolean); method public abstract void setText(java.lang.CharSequence); method public abstract void setText(java.lang.CharSequence, int, int); + method public void setTextIdEntry(java.lang.String); method public abstract void setTextLines(int[], int[]); method public abstract void setTextStyle(float, int, int, int); method public abstract void setTransformation(android.graphics.Matrix); diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 7b549cd59666a..87f2271295866 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -32,6 +32,8 @@ import android.view.WindowManagerGlobal; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; +import com.android.internal.util.Preconditions; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -624,6 +626,7 @@ public class AssistStructure implements Parcelable { int mMinEms = -1; int mMaxEms = -1; int mMaxLength = -1; + @Nullable String mTextIdEntry; // POJO used to override some autofill-related values when the node is parcelized. // Not written to parcel. @@ -701,7 +704,7 @@ public class AssistStructure implements Parcelable { final int flags = mFlags; if ((flags&FLAGS_HAS_ID) != 0) { mId = in.readInt(); - if (mId != 0) { + if (mId != View.NO_ID) { mIdEntry = preader.readString(); if (mIdEntry != null) { mIdType = preader.readString(); @@ -724,6 +727,7 @@ public class AssistStructure implements Parcelable { mMinEms = in.readInt(); mMaxEms = in.readInt(); mMaxLength = in.readInt(); + mTextIdEntry = preader.readString(); } if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { mX = in.readInt(); @@ -857,7 +861,7 @@ public class AssistStructure implements Parcelable { out.writeInt(writtenFlags); if ((flags&FLAGS_HAS_ID) != 0) { out.writeInt(mId); - if (mId != 0) { + if (mId != View.NO_ID) { pwriter.writeString(mIdEntry); if (mIdEntry != null) { pwriter.writeString(mIdType); @@ -890,6 +894,7 @@ public class AssistStructure implements Parcelable { out.writeInt(mMinEms); out.writeInt(mMaxEms); out.writeInt(mMaxLength); + pwriter.writeString(mTextIdEntry); } if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) { out.writeInt(mX); @@ -1429,6 +1434,17 @@ public class AssistStructure implements Parcelable { return mText != null ? mText.mLineBaselines : null; } + /** + * Gets the identifier used to set the text associated with this view. + * + *

It's only relevant when the {@link AssistStructure} is used for autofill purposes, + * not for assist purposes. + */ + @Nullable + public String getTextIdEntry() { + return mTextIdEntry; + } + /** * Return additional hint text associated with the node; this is typically used with * a node that takes user input, describing to the user what the input means. @@ -1683,6 +1699,11 @@ public class AssistStructure implements Parcelable { t.mLineBaselines = baselines; } + @Override + public void setTextIdEntry(@NonNull String entryName) { + mNode.mTextIdEntry = Preconditions.checkNotNull(entryName); + } + @Override public void setHint(CharSequence hint) { getNodeText().mHint = hint != null ? hint.toString() : null; @@ -2082,6 +2103,7 @@ public class AssistStructure implements Parcelable { Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor()) + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor())); Log.i(TAG, prefix + " Input type: " + node.getInputType()); + Log.i(TAG, prefix + " Resource id: " + node.getTextIdEntry()); } String webDomain = node.getWebDomain(); if (webDomain != null) { diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index d665dde39afe1..1d94abeb51a2e 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -26,6 +26,8 @@ import android.util.Pair; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; +import com.android.internal.util.Preconditions; + import java.util.List; /** @@ -203,6 +205,16 @@ public abstract class ViewStructure { */ public abstract void setTextLines(int[] charOffsets, int[] baselines); + /** + * Sets the identifier used to set the text associated with this view. + * + *

Should only be set when the node is used for autofill purposes - it will be ignored + * when used for Assist. + */ + public void setTextIdEntry(@NonNull String entryName) { + Preconditions.checkNotNull(entryName); + } + /** * Set optional hint text associated with this view; this is for example the text that is * shown by an EditText when it is empty to indicate to the user the kind of text to input. diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 1e17f34af2a68..1618d620738fa 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -44,6 +44,7 @@ import android.content.UndoManager; import android.content.res.ColorStateList; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.ResourceId; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; @@ -785,9 +786,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // mAutoSizeStepGranularityInPx. private boolean mHasPresetAutoSizeValues = false; - // Indicates whether the text was set from resources or dynamically, so it can be used to + // Indicates whether the text was set statically or dynamically, so it can be used to // sanitize autofill requests. - private boolean mTextFromResource = false; + private boolean mSetFromXmlOrResourceId = false; + // Resource id used to set the text - used for autofill purposes. + private @StringRes int mTextId = ResourceId.ID_NULL; /** * Kick-start the font cache for the zygote process (to pay the cost of @@ -926,7 +929,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int n = a.getIndexCount(); - boolean fromResourceId = false; + // Must set id in a temporary variable because it will be reset by setText() + boolean setFromXml = false; for (int i = 0; i < n; i++) { int attr = a.getIndex(i); @@ -1068,7 +1072,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextView_text: - fromResourceId = true; + setFromXml = true; + mTextId = a.getResourceId(attr, ResourceId.ID_NULL); text = a.getText(attr); break; @@ -1460,8 +1465,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } setText(text, bufferType); - if (fromResourceId) { - mTextFromResource = true; + if (setFromXml) { + mSetFromXmlOrResourceId = true; } if (hint != null) setHint(hint); @@ -5278,7 +5283,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) { - mTextFromResource = false; + mSetFromXmlOrResourceId = false; if (text == null) { text = ""; } @@ -5516,7 +5521,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @android.view.RemotableViewMethod public final void setText(@StringRes int resid) { setText(getContext().getResources().getText(resid)); - mTextFromResource = true; + mSetFromXmlOrResourceId = true; + mTextId = resid; } /** @@ -5543,7 +5549,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public final void setText(@StringRes int resid, BufferType type) { setText(getContext().getResources().getText(resid), type); - mTextFromResource = true; + mSetFromXmlOrResourceId = true; + mTextId = resid; } /** @@ -10234,7 +10241,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod() || isPasswordInputType(getInputType()); if (forAutofill) { - structure.setDataIsSensitive(!mTextFromResource); + structure.setDataIsSensitive(!mSetFromXmlOrResourceId); + if (mTextId != ResourceId.ID_NULL) { + structure.setTextIdEntry(getResources().getResourceEntryName(mTextId)); + } } if (!isPassword || forAutofill) {