Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25bf787f authored by Felipe Leme's avatar Felipe Leme
Browse files

Created an HtmlInfo object on ViewStructure.

The ViewStructure typically represents a View, but it it can also be a virtual
view; in particular, WebView uses virtual views to represent HTML elements.

Although most of the properties of the HTML element maps to properties of
Android Views, some properties (such as 'name' and 'id' on <INPUT> fields)
don't, and those are crucial for autofilling web pages.

Rather than trying to artificially map these properties, it's better to create
a generic representation, for the following reasons:

1. Web standards move in a different velocity than Android APIs
2. Android APIs cannot be changed easily. Deprecated APIs continue to work,
   and new added APIs don't work in older versions
3. The data used for autofill is opaque to the Framework - it's only relevant
   to the node producers (like WebView) and consumers (Autofill services).

Also removed the setIdEntry() that was used for the same purpose.

Fixes: 36696757
Bug: 36718508
Test: VirtualContainerActivityTest with new checks pass

Change-Id: Ia626bd1f640b0b5861e81a5915504b95029874c9
parent 94696c5a
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -6592,6 +6592,7 @@ package android.app.assist {
    method public android.os.Bundle getExtras();
    method public int getHeight();
    method public java.lang.String getHint();
    method public android.view.ViewStructure.HtmlInfo getHtmlInfo();
    method public int getId();
    method public java.lang.String getIdEntry();
    method public java.lang.String getIdPackage();
@@ -46385,6 +46386,7 @@ package android.view {
    method public abstract int getTextSelectionStart();
    method public abstract boolean hasExtras();
    method public abstract android.view.ViewStructure newChild(int);
    method public abstract android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(java.lang.String);
    method public abstract void setAccessibilityFocused(boolean);
    method public abstract void setActivated(boolean);
    method public abstract void setAlpha(float);
@@ -46407,8 +46409,8 @@ package android.view {
    method public abstract void setFocusable(boolean);
    method public abstract void setFocused(boolean);
    method public abstract void setHint(java.lang.CharSequence);
    method public abstract void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
    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 setLocaleList(android.os.LocaleList);
    method public abstract void setLongClickable(boolean);
@@ -46423,6 +46425,18 @@ package android.view {
    method public abstract void setVisibility(int);
  }
  public static abstract class ViewStructure.HtmlInfo {
    ctor public ViewStructure.HtmlInfo();
    method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
    method public abstract java.lang.String getTag();
  }
  public static abstract class ViewStructure.HtmlInfo.Builder {
    ctor public ViewStructure.HtmlInfo.Builder();
    method public abstract android.view.ViewStructure.HtmlInfo.Builder addAttribute(java.lang.String, java.lang.String);
    method public abstract android.view.ViewStructure.HtmlInfo build();
  }
  public final class ViewStub extends android.view.View {
    ctor public ViewStub(android.content.Context);
    ctor public ViewStub(android.content.Context, int);
+15 −1
Original line number Diff line number Diff line
@@ -6828,6 +6828,7 @@ package android.app.assist {
    method public android.os.Bundle getExtras();
    method public int getHeight();
    method public java.lang.String getHint();
    method public android.view.ViewStructure.HtmlInfo getHtmlInfo();
    method public int getId();
    method public java.lang.String getIdEntry();
    method public java.lang.String getIdPackage();
@@ -49840,6 +49841,7 @@ package android.view {
    method public abstract int getTextSelectionStart();
    method public abstract boolean hasExtras();
    method public abstract android.view.ViewStructure newChild(int);
    method public abstract android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(java.lang.String);
    method public abstract void setAccessibilityFocused(boolean);
    method public abstract void setActivated(boolean);
    method public abstract void setAlpha(float);
@@ -49862,8 +49864,8 @@ package android.view {
    method public abstract void setFocusable(boolean);
    method public abstract void setFocused(boolean);
    method public abstract void setHint(java.lang.CharSequence);
    method public abstract void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
    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 setLocaleList(android.os.LocaleList);
    method public abstract void setLongClickable(boolean);
@@ -49878,6 +49880,18 @@ package android.view {
    method public abstract void setVisibility(int);
  }
  public static abstract class ViewStructure.HtmlInfo {
    ctor public ViewStructure.HtmlInfo();
    method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
    method public abstract java.lang.String getTag();
  }
  public static abstract class ViewStructure.HtmlInfo.Builder {
    ctor public ViewStructure.HtmlInfo.Builder();
    method public abstract android.view.ViewStructure.HtmlInfo.Builder addAttribute(java.lang.String, java.lang.String);
    method public abstract android.view.ViewStructure.HtmlInfo build();
  }
  public final class ViewStub extends android.view.View {
    ctor public ViewStub(android.content.Context);
    ctor public ViewStub(android.content.Context, int);
+15 −1
Original line number Diff line number Diff line
@@ -6621,6 +6621,7 @@ package android.app.assist {
    method public android.os.Bundle getExtras();
    method public int getHeight();
    method public java.lang.String getHint();
    method public android.view.ViewStructure.HtmlInfo getHtmlInfo();
    method public int getId();
    method public java.lang.String getIdEntry();
    method public java.lang.String getIdPackage();
@@ -46766,6 +46767,7 @@ package android.view {
    method public abstract int getTextSelectionStart();
    method public abstract boolean hasExtras();
    method public abstract android.view.ViewStructure newChild(int);
    method public abstract android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(java.lang.String);
    method public abstract void setAccessibilityFocused(boolean);
    method public abstract void setActivated(boolean);
    method public abstract void setAlpha(float);
@@ -46788,8 +46790,8 @@ package android.view {
    method public abstract void setFocusable(boolean);
    method public abstract void setFocused(boolean);
    method public abstract void setHint(java.lang.CharSequence);
    method public abstract void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
    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 setLocaleList(android.os.LocaleList);
    method public abstract void setLongClickable(boolean);
@@ -46804,6 +46806,18 @@ package android.view {
    method public abstract void setVisibility(int);
  }
  public static abstract class ViewStructure.HtmlInfo {
    ctor public ViewStructure.HtmlInfo();
    method public abstract java.util.ArrayList<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
    method public abstract java.lang.String getTag();
  }
  public static abstract class ViewStructure.HtmlInfo.Builder {
    ctor public ViewStructure.HtmlInfo.Builder();
    method public abstract android.view.ViewStructure.HtmlInfo.Builder addAttribute(java.lang.String, java.lang.String);
    method public abstract android.view.ViewStructure.HtmlInfo build();
  }
  public final class ViewStub extends android.view.View {
    ctor public ViewStub(android.content.Context);
    ctor public ViewStub(android.content.Context, int);
+148 −22
Original line number Diff line number Diff line
@@ -19,9 +19,12 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.ViewStructure;
import android.view.ViewStructure.HtmlInfo;
import android.view.ViewStructure.HtmlInfo.Builder;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.autofill.AutoFillId;
@@ -597,6 +600,7 @@ public class AssistStructure implements Parcelable {
        AutofillValue mAutofillValue;
        String[] mAutofillOptions;
        boolean mSanitized;
        HtmlInfo mHtmlInfo;

        int mX;
        int mY;
@@ -641,7 +645,6 @@ 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_HAS_LOCALE_LIST = 0x00010000;
        static final int FLAGS_ALL_CONTROL = 0xfff00000;

@@ -677,8 +680,6 @@ 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) {
@@ -688,6 +689,10 @@ public class AssistStructure implements Parcelable {
                mAutofillHint = in.readStringArray();
                mAutofillValue = in.readParcelable(null);
                mAutofillOptions = in.readStringArray();
                final Parcelable p = in.readParcelable(null);
                if (p instanceof HtmlInfo) {
                    mHtmlInfo = (HtmlInfo) p;
                }
            }
            if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                mX = in.readInt();
@@ -756,8 +761,6 @@ 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;
@@ -821,8 +824,6 @@ 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) {
@@ -834,6 +835,11 @@ public class AssistStructure implements Parcelable {
                final AutofillValue sanitizedValue = writeSensitive ? mAutofillValue : null;
                out.writeParcelable(sanitizedValue,  0);
                out.writeStringArray(mAutofillOptions);
                if (mHtmlInfo instanceof Parcelable) {
                    out.writeParcelable((Parcelable) mHtmlInfo, 0);
                } else {
                    out.writeParcelable(null, 0);
                }
            }
            if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                out.writeInt(mX);
@@ -908,10 +914,6 @@ 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.
         *
         * <p>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;
@@ -1233,12 +1235,8 @@ public class AssistStructure implements Parcelable {
        /**
         * Returns the URL represented by this node.
         *
         * <p>Typically used in 2 categories of nodes:
         *
         * <ol>
         * <li>Root node (containing the URL of the HTML page)
         * <li>Child nodes that represent hyperlinks (contains the hyperlink URL).
         * </ol>
         * <p>Typically used when the view associated with the node is a container for an HTML
         * document.
         *
         * <strong>WARNING:</strong> a {@link android.service.autofill.AutofillService} should only
         * use this URL for autofill purposes when it trusts the app generating it (i.e., the app
@@ -1248,6 +1246,16 @@ public class AssistStructure implements Parcelable {
            return mUrl;
        }

        /**
         * Returns the HTML properties associated with this node.
         *
         * <p>It's only set when the {@link AssistStructure} is used for autofilling purposes, not
         * for assist.
         */
        public HtmlInfo getHtmlInfo() {
            return mHtmlInfo;
        }

        /**
         * Returns the the list of locales associated with this node.
         */
@@ -1392,11 +1400,6 @@ 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;
@@ -1711,6 +1714,123 @@ public class AssistStructure implements Parcelable {
        public void setLocaleList(LocaleList localeList) {
            mNode.mLocaleList = localeList;
        }

        @Override
        public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) {
            return new HtmlInfoNodeBuilder(tagName);
        }

        @Override
        public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
            mNode.mHtmlInfo = htmlInfo;
        }
    }

    private static final class HtmlInfoNode extends HtmlInfo implements Parcelable {
        private final String mTag;
        private final String[] mNames;
        private final String[] mValues;

        // Not parcelable
        private ArrayList<Pair<String, String>> mAttributes;

        private HtmlInfoNode(HtmlInfoNodeBuilder builder) {
            mTag = builder.mTag;
            if (builder.mNames == null) {
                mNames = null;
                mValues = null;
            } else {
                mNames = new String[builder.mNames.size()];
                mValues = new String[builder.mValues.size()];
                builder.mNames.toArray(mNames);
                builder.mValues.toArray(mValues);
            }
        }

        @Override
        public String getTag() {
            return mTag;
        }

        @Override
        public ArrayList<Pair<String, String>> getAttributes() {
            if (mAttributes == null && mNames != null) {
                mAttributes = new ArrayList<>(mNames.length);
                for (int i = 0; i < mNames.length; i++) {
                    final Pair<String, String> pair = new Pair<>(mNames[i], mValues[i]);
                    mAttributes.add(i, pair);
                }
            }
            return mAttributes;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(mTag);
            parcel.writeStringArray(mNames);
            parcel.writeStringArray(mValues);
        }

        @SuppressWarnings("hiding")
        public static final Creator<HtmlInfoNode> CREATOR = new Creator<HtmlInfoNode>() {
            @Override
            public HtmlInfoNode createFromParcel(Parcel parcel) {
                // Always go through the builder to ensure the data ingested by
                // the system obeys the contract of the builder to avoid attacks
                // using specially crafted parcels.
                final String tag = parcel.readString();
                final HtmlInfoNodeBuilder builder = new HtmlInfoNodeBuilder(tag);
                final String[] names = parcel.readStringArray();
                final String[] values = parcel.readStringArray();
                if (names != null && values != null) {
                    if (names.length != values.length) {
                        Log.w(TAG, "HtmlInfo attributes mismatch: names=" + names.length
                                + ", values=" + values.length);
                    } else {
                        for (int i = 0; i < names.length; i++) {
                            builder.addAttribute(names[i], values[i]);
                        }
                    }
                }
                return builder.build();
            }

            @Override
            public HtmlInfoNode[] newArray(int size) {
                return new HtmlInfoNode[size];
            }
        };
    }

    private static final class HtmlInfoNodeBuilder extends HtmlInfo.Builder {
        private final String mTag;
        private ArrayList<String> mNames;
        private ArrayList<String> mValues;

        HtmlInfoNodeBuilder(String tag) {
            mTag = tag;
        }

        @Override
        public Builder addAttribute(String name, String value) {
            if (mNames == null) {
                mNames = new ArrayList<>();
                mValues = new ArrayList<>();
            }
            mNames.add(name);
            mValues.add(value);
            return this;
        }

        @Override
        public HtmlInfoNode build() {
            return new HtmlInfoNode(this);
        }
    }

    /** @hide */
@@ -1813,6 +1933,12 @@ public class AssistStructure implements Parcelable {
        if (url != null) {
            Log.i(TAG, prefix + "  URL: " + url);
        }
        HtmlInfo htmlInfo = node.getHtmlInfo();
        if (htmlInfo != null) {
            Log.i(TAG, prefix + "  HtmlInfo: tag=" + htmlInfo.getTag()
                    + ", attr="+ htmlInfo.getAttributes());
        }

        LocaleList localeList = node.getLocaleList();
        if (localeList != null) {
            Log.i(TAG, prefix + "  LocaleList: " + localeList);
+64 −18
Original line number Diff line number Diff line
@@ -22,9 +22,12 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.LocaleList;
import android.util.Pair;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;

import java.util.ArrayList;

/**
 * Container for storing additional per-view data generated by {@link View#onProvideStructure
 * View.onProvideStructure} and {@link View#onProvideAutofillStructure
@@ -42,17 +45,6 @@ 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.
     *
     * <p>Typically used when adding virtual children (through
     * {@link #asyncNewChild(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.
     *
@@ -372,13 +364,7 @@ public abstract class ViewStructure {
    /**
     * Sets the URL represented by this node.
     *
     * <p>Typically used in the following situations:
     *
     * <ol>
     * <li>In a {@link android.app.assist.AssistStructure.WindowNode#getRootViewNode()}, to set up
     * the main URL of an HTML page.
     * <li>On child nodes represening hyperlinks.
     * </ol>
     * <p>Typically used when the view is a container for an HTML document.
     */
    public abstract void setUrl(String url);

@@ -386,4 +372,64 @@ public abstract class ViewStructure {
     * Sets the the list of locales associated with this node.
     */
    public abstract void setLocaleList(LocaleList localeList);

    /**
     * Creates a new {@link HtmlInfo.Builder} for the given HTML tag.
     *
     * @param tagName name of the HTML tag.
     * @return a new builder.
     */
    public abstract HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName);

    /**
     * Sets the HTML properties of this node when it represents an HTML element.
     *
     * <p>Should only be set when the node is used for autofill purposes - it will be ignored
     * when used for assist.
     *
     * @param htmlInfo HTML properties.
     */
    public abstract void setHtmlInfo(@NonNull HtmlInfo htmlInfo);

    /**
     * Simplified representation of the HTML properties of a node that represents an HTML element.
     */
    public abstract static class HtmlInfo {

        /**
         * Gets the HTML tag.
         */
        @NonNull
        public abstract String getTag();

        /**
         * Gets the list of HTML attributes.
         *
         * @return list of key/value pairs; could contain pairs with the same keys.
         */
        @Nullable
        public abstract ArrayList<Pair<String, String>> getAttributes();

        /**
         * Builder for {@link HtmlInfo} objects.
         */
        public abstract static class Builder {

            /**
             * Adds an HTML attribute.
             *
             * @param name name of the attribute.
             * @param value value of the attribute.
             * @return same builder, for chaining.
             */
            public abstract Builder addAttribute(@NonNull String name, @NonNull String value);

            /**
             * Builds the {@link HtmlInfo} object.
             *
             * @return a new {@link HtmlInfo} instance.
             */
            public abstract HtmlInfo build();
        }
    }
}
Loading