diff --git a/api/current.txt b/api/current.txt index 360c4f2f55964..235a4a6c3d4d3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -46356,6 +46356,7 @@ package android.view { method public abstract void setFocused(boolean); method public abstract void setHint(java.lang.CharSequence); method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String); + method public abstract void setIdEntry(java.lang.String); method public abstract void setInputType(int); method public abstract void setLongClickable(boolean); method public abstract void setOpaque(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 1a0a8bb8faf22..abdcaaa6c1b42 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -49819,6 +49819,7 @@ package android.view { method public abstract void setFocused(boolean); method public abstract void setHint(java.lang.CharSequence); method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String); + method public abstract void setIdEntry(java.lang.String); method public abstract void setInputType(int); method public abstract void setLongClickable(boolean); method public abstract void setOpaque(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index 674ffa610f520..3fb42a400835b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -46725,6 +46725,7 @@ package android.view { method public abstract void setFocused(boolean); method public abstract void setHint(java.lang.CharSequence); method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String); + method public abstract void setIdEntry(java.lang.String); method public abstract void setInputType(int); method public abstract void setLongClickable(boolean); method public abstract void setOpaque(boolean); diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 27bfb512f9dca..e0414570d4556 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -639,6 +639,7 @@ public class AssistStructure implements Parcelable { static final int FLAGS_HAS_CHILDREN = 0x00100000; static final int FLAGS_HAS_URL = 0x00080000; static final int FLAGS_HAS_INPUT_TYPE = 0x00040000; + static final int FLAGS_HAS_ENTRY_ID = 0x00020000; static final int FLAGS_ALL_CONTROL = 0xfff00000; int mFlags; @@ -672,7 +673,10 @@ public class AssistStructure implements Parcelable { mIdPackage = preader.readString(); } } + } else if ((flags&FLAGS_HAS_ENTRY_ID) != 0) { + mIdEntry = preader.readString(); } + if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) { mSanitized = in.readInt() == 1; mAutofillId = in.readParcelable(null); @@ -745,6 +749,8 @@ public class AssistStructure implements Parcelable { int flags = mFlags & ~FLAGS_ALL_CONTROL; if (mId != View.NO_ID) { flags |= FLAGS_HAS_ID; + } else if (mIdEntry != null ){ + flags |= FLAGS_HAS_ENTRY_ID; } if (mAutofillId != null) { flags |= FLAGS_HAS_AUTOFILL_DATA; @@ -805,7 +811,10 @@ public class AssistStructure implements Parcelable { pwriter.writeString(mIdPackage); } } + } else if ((flags&FLAGS_HAS_ENTRY_ID) != 0) { + pwriter.writeString(mIdEntry); } + if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) { writeSensitive = mSanitized || !sanitizeOnWrite; out.writeInt(mSanitized ? 1 : 0); @@ -887,6 +896,10 @@ public class AssistStructure implements Parcelable { * If {@link #getId()} is a resource identifier, this is the entry name of that * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId} * for more information. + * + *

If the node represents a virtual view, it could also represent the entry id set by + * {@link android.view.ViewStructure#setIdEntry ViewStructure.setIdEntry} + * */ public String getIdEntry() { return mIdEntry; @@ -1360,6 +1373,11 @@ public class AssistStructure implements Parcelable { mNode.mIdEntry = entryName; } + @Override + public void setIdEntry(String entryName) { + mNode.mIdEntry = entryName; + } + @Override public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) { mNode.mX = left; diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 989cb13d3e691..40e028569c544 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -40,6 +40,17 @@ public abstract class ViewStructure { */ public abstract void setId(int id, String packageName, String typeName, String entryName); + /** + * Sets the name of the identifier for this view. + * + *

Typically used when adding virtual children (through + * {@link #asyncNewChild(int, int, int)}) that does not map to Android {@link View} + * - otherwise, it's better to call {@link #setId(int, String, String, String)}. + * + * @param entryName The entry name of the view's identifier, or {@code null} if there is none. + */ + public abstract void setIdEntry(String entryName); + /** * Set the basic dimensions of this view. * diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 9a931c2b65f47..c2b4138b90db3 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -41,6 +41,7 @@ import android.os.StrictMode; import android.os.RemoteException; import android.print.PrintDocumentAdapter; import android.security.KeyChain; +import android.text.InputType; import android.util.AttributeSet; import android.util.Log; import android.view.DragEvent; @@ -2611,6 +2612,76 @@ public class WebView extends AbsoluteLayout mProvider.getViewDelegate().onProvideVirtualStructure(structure); } + /** + * {@inheritDoc} + * + *

The {@link ViewStructure} traditionally represents a {@link View}, while for web pages + * it represent HTML nodes. Hence, it's necessary to "map" the HTML properties in a way that is + * understood by the {@link android.service.autofill.AutofillService} implementations: + * + *

    + *
  1. {@link ViewStructure#setClassName(String)} should be use to describe the type of node: + *
      + *
    1. If the Android SDK provides a similar View, the full-qualified class name of that + * view should be used. + *
    2. Otherwise, the class name should be {@code HTML.iframe}. + *
    + *
  2. The W3C autofill field ({@code autocomplete} tag attribute) maps to + * {@link ViewStructure#setAutofillHint(String[])}. + *
  3. The {@code type} attribute of {@code INPUT} tags maps to + * {@link ViewStructure#setInputType(int)}. + *
  4. The {@code name} attribute maps to {@link ViewStructure#setIdEntry(String)}. + *
  5. The {@code value} attribute maps to {@link ViewStructure#setText(CharSequence)}. + *
  6. The {@code placeholder} attribute maps to {@link ViewStructure#setHint(CharSequence)}. + *
  7. {@link ViewStructure#setDataIsSensitive(boolean)} whould only be called with + * {@code true} for form fields whose {@code value} attribute was not pre-loaded. + *
+ * + *

Example1: an HTML form with 2 fields for username and password. + * + *

+     *    
+     *    
+     * 
+ * + *

Would map to: + * + *

+     *     ViewStructure username = //structure.newChildForAutofill(...);
+     *     username.setClassName("input");
+     *     username.setInputType("android.widget.EditText");
+     *     username.setAutofillHints("username");
+     *     username.setIdEntry("username");
+     *     username.setHint("Email or username");
+     *     username.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+     *     username.setAutofillValue(AutofillValue.forText("mr.sparkle"));
+     *     username.setText("mr.sparkle");
+     *     username.setDataIsSensitive(true); // Contains real username, which is sensitive
+     *
+     *     ViewStructure password = //structure.newChildForAutofill(...);
+     *     password.setInputType("android.widget.EditText");
+     *     password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+     *     password.setAutofillHints("current-password");
+     *     password.setIdEntry("password");
+     *     password.setHint("Password");
+     *     password.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+     *     password.setDataIsSensitive(false); // Value is not set
+     * 
+ * + *

Example2: an IFRAME tag. + * + *

+     *