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

Commit 61c9bf95 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Optimize ViewStructure for autofill by removing irrelevant nodes."

parents 8e4d22b8 d04a697e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -710,6 +710,7 @@ package android {
    field public static final int imeSubtypeMode = 16843501; // 0x10102ed
    field public static final int immersive = 16843456; // 0x10102c0
    field public static final int importantForAccessibility = 16843690; // 0x10103aa
    field public static final int importantForAutofill = 16844123; // 0x101055b
    field public static final int inAnimation = 16843127; // 0x1010177
    field public static final int includeFontPadding = 16843103; // 0x101015f
    field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -45099,6 +45100,7 @@ package android.view {
    method protected int getHorizontalScrollbarHeight();
    method public int getId();
    method public int getImportantForAccessibility();
    method public int getImportantForAutofill();
    method public boolean getKeepScreenOn();
    method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
    method public int getLabelFor();
@@ -45228,6 +45230,7 @@ package android.view {
    method public boolean isHorizontalScrollBarEnabled();
    method public boolean isHovered();
    method public boolean isImportantForAccessibility();
    method public final boolean isImportantForAutofill();
    method public boolean isInEditMode();
    method public boolean isInLayout();
    method public boolean isInTouchMode();
@@ -45410,6 +45413,7 @@ package android.view {
    method public void setHovered(boolean);
    method public void setId(int);
    method public void setImportantForAccessibility(int);
    method public void setImportantForAutofill(int);
    method public void setKeepScreenOn(boolean);
    method public void setKeyboardNavigationCluster(boolean);
    method public void setLabelFor(int);
@@ -45575,6 +45579,9 @@ package android.view {
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
    field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0
    field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1
    field public static final int INVISIBLE = 4; // 0x4
    field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+7 −0
Original line number Diff line number Diff line
@@ -822,6 +822,7 @@ package android {
    field public static final int imeSubtypeMode = 16843501; // 0x10102ed
    field public static final int immersive = 16843456; // 0x10102c0
    field public static final int importantForAccessibility = 16843690; // 0x10103aa
    field public static final int importantForAutofill = 16844123; // 0x101055b
    field public static final int inAnimation = 16843127; // 0x1010177
    field public static final int includeFontPadding = 16843103; // 0x101015f
    field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -48559,6 +48560,7 @@ package android.view {
    method protected int getHorizontalScrollbarHeight();
    method public int getId();
    method public int getImportantForAccessibility();
    method public int getImportantForAutofill();
    method public boolean getKeepScreenOn();
    method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
    method public int getLabelFor();
@@ -48688,6 +48690,7 @@ package android.view {
    method public boolean isHorizontalScrollBarEnabled();
    method public boolean isHovered();
    method public boolean isImportantForAccessibility();
    method public final boolean isImportantForAutofill();
    method public boolean isInEditMode();
    method public boolean isInLayout();
    method public boolean isInTouchMode();
@@ -48870,6 +48873,7 @@ package android.view {
    method public void setHovered(boolean);
    method public void setId(int);
    method public void setImportantForAccessibility(int);
    method public void setImportantForAutofill(int);
    method public void setKeepScreenOn(boolean);
    method public void setKeyboardNavigationCluster(boolean);
    method public void setLabelFor(int);
@@ -49035,6 +49039,9 @@ package android.view {
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
    field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0
    field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1
    field public static final int INVISIBLE = 4; // 0x4
    field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+7 −0
Original line number Diff line number Diff line
@@ -710,6 +710,7 @@ package android {
    field public static final int imeSubtypeMode = 16843501; // 0x10102ed
    field public static final int immersive = 16843456; // 0x10102c0
    field public static final int importantForAccessibility = 16843690; // 0x10103aa
    field public static final int importantForAutofill = 16844123; // 0x101055b
    field public static final int inAnimation = 16843127; // 0x1010177
    field public static final int includeFontPadding = 16843103; // 0x101015f
    field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -45459,6 +45460,7 @@ package android.view {
    method protected int getHorizontalScrollbarHeight();
    method public int getId();
    method public int getImportantForAccessibility();
    method public int getImportantForAutofill();
    method public boolean getKeepScreenOn();
    method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
    method public int getLabelFor();
@@ -45589,6 +45591,7 @@ package android.view {
    method public boolean isHorizontalScrollBarEnabled();
    method public boolean isHovered();
    method public boolean isImportantForAccessibility();
    method public final boolean isImportantForAutofill();
    method public boolean isInEditMode();
    method public boolean isInLayout();
    method public boolean isInTouchMode();
@@ -45773,6 +45776,7 @@ package android.view {
    method public void setHovered(boolean);
    method public void setId(int);
    method public void setImportantForAccessibility(int);
    method public void setImportantForAutofill(int);
    method public void setKeepScreenOn(boolean);
    method public void setKeyboardNavigationCluster(boolean);
    method public void setLabelFor(int);
@@ -45938,6 +45942,9 @@ package android.view {
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
    field public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0; // 0x0
    field public static final int IMPORTANT_FOR_AUTOFILL_NO = 2; // 0x2
    field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1
    field public static final int INVISIBLE = 4; // 0x4
    field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
    field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+156 −1
Original line number Diff line number Diff line
@@ -1174,6 +1174,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    public static final int AUTOFILL_TYPE_DATE = 4;
    /** @hide */
    @IntDef({
            IMPORTANT_FOR_AUTOFILL_AUTO,
            IMPORTANT_FOR_AUTOFILL_YES,
            IMPORTANT_FOR_AUTOFILL_NO
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface AutofillImportance {}
    /**
     * Automatically determine whether a view is important for auto-fill.
     */
    public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0;
    /**
     * The view is important for important for auto-fill.
     */
    public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1;
    /**
     * The view is not important for auto-fill.
     */
    public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2;
    /**
     * This view is enabled. Interpretation varies by subclass.
     * Use with ENABLED_MASK when calling setFlags.
@@ -2745,7 +2769,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *                1                  PFLAG3_FINGER_DOWN
     *               1                   PFLAG3_FOCUSED_BY_DEFAULT
     *             11                    PFLAG3_AUTO_FILL_MODE_MASK
     *           xx                      * NO LONGER NEEDED, SHOULD BE REUSED *
     *           11                      PFLAG3_IMPORTANT_FOR_AUTOFILL
     *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
     *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
     *        1                          PFLAG3_TEMPORARY_DETACH
@@ -2982,6 +3006,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private static final int PFLAG3_AUTO_FILL_MODE_MASK = (AUTO_FILL_MODE_INHERIT
            | AUTO_FILL_MODE_AUTO | AUTO_FILL_MODE_MANUAL) << PFLAG3_AUTO_FILL_MODE_SHIFT;
    /**
     * Shift for the bits in {@link #mPrivateFlags3} related to the
     * "importantForAutofill" attribute.
     */
    static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 21;
    /**
     * Mask for obtaining the bits which specify how to determine
     * whether a view is important for autofill.
     */
    static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO
            | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO)
            << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
    /**
     * Whether this view has rendered elements that overlap (see {@link
     * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
@@ -5009,6 +5047,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                        setAutoFillHint(a.getInt(attr, AUTO_FILL_HINT_NONE));
                    }
                    break;
                case R.styleable.View_importantForAutofill:
                    if (a.peekValue(attr) != null) {
                        setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO));
                    }
                    break;
            }
        }
@@ -7443,6 +7486,118 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return null;
    }
    /**
     * Gets the mode for determining whether this View is important for autofill.
     *
     * <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
     *
     * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to
     * {@link #setImportantForAutofill(int)}.
     *
     * @attr ref android.R.styleable#View_importantForAutofill
     */
    @ViewDebug.ExportedProperty(mapping = {
            @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"),
            @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"),
            @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no")})
    public @AutofillImportance int getImportantForAutofill() {
        return (mPrivateFlags3
                & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
    }
    /**
     * Sets the mode for determining whether this View is important for autofill.
     *
     * <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
     *
     * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES},
     * or {@link #IMPORTANT_FOR_AUTOFILL_NO}.
     *
     * @attr ref android.R.styleable#View_importantForAutofill
     */
    public void setImportantForAutofill(@AutofillImportance int mode) {
        mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK;
        mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT)
                & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK;
    }
    /**
     * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode}
     * associated with this View should be included in a {@link ViewStructure} used for
     * autofill purposes.
     *
     * <p>Generally speaking, a view is important for autofill if:
     * <ol>
     * <li>The view can-be autofilled by an {@link android.service.autofill.AutoFillService}.
     * <li>The view contents can help an {@link android.service.autofill.AutoFillService} to
     * autofill other views.
     * <ol>
     *
     * <p>For example, view containers should typically return {@code false} for performance reasons
     * (since the important info is provided by their children), but if the container is actually
     * whose children are part of a compound view, it should return {@code true} (and then override
     * {@link #dispatchProvideAutoFillStructure(ViewStructure, int)} to simply call
     * {@link #onProvideAutoFillStructure(ViewStructure, int)} so its children are not included in
     * the structure). On the other hand, views representing labels or editable fields should
     * typically return {@code true}, but in some cases they could return {@code false} (for
     * example, if they're part of a "Captcha" mechanism).
     *
     * <p>By default, this method returns {@code true} if {@link #getImportantForAutofill()} returns
     * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@code false } if it returns
     * {@link #IMPORTANT_FOR_AUTOFILL_NO}, and use some heuristics to define the importance when it
     * returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}. Hence, it should rarely be overridden - Views
     * should use {@link #setImportantForAutofill(int)} instead.
     *
     * <p><strong>Note:</strong> returning {@code false} does not guarantee the view will be
     * excluded from the structure; for example, if the user explicitly requested auto-fill, the
     * View might be always included.
     *
     * <p>This decision applies just for the view, not its children - if the view children are not
     * important for autofill, the view should override
     * {@link #dispatchProvideAutoFillStructure(ViewStructure, int)} to simply call
     * {@link #onProvideAutoFillStructure(ViewStructure, int)} (instead of calling
     * {@link #dispatchProvideAutoFillStructure(ViewStructure, int)} for each child).
     *
     * @return whether the view is considered important for autofill.
     *
     * @see #IMPORTANT_FOR_AUTOFILL_AUTO
     * @see #IMPORTANT_FOR_AUTOFILL_YES
     * @see #IMPORTANT_FOR_AUTOFILL_NO
     */
    public final boolean isImportantForAutofill() {
        final int flag = getImportantForAutofill();
        // First, check if view explicity set it to YES or NO
        if ((flag & IMPORTANT_FOR_AUTOFILL_YES) != 0) {
            return true;
        }
        if ((flag & IMPORTANT_FOR_AUTOFILL_NO) != 0) {
            return false;
        }
        // Then use some heuristics to handle AUTO.
        // Always include views that have a explicity resource id.
        final int id = mID;
        if (id != NO_ID && !isViewIdGenerated(id)) {
            final Resources res = getResources();
            String entry = null;
            String pkg = null;
            try {
                entry = res.getResourceEntryName(id);
                pkg = res.getResourcePackageName(id);
            } catch (Resources.NotFoundException e) {
                // ignore
            }
            if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) {
                return true;
            }
        }
        // Otherwise, assume it's not important...
        return false;
    }
    @Nullable
    private AutoFillManager getAutoFillManager() {
        return mContext.getSystemService(AutoFillManager.class);
+122 −66
Original line number Diff line number Diff line
@@ -595,6 +595,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager

    public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        initViewGroup();
        initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
    }
@@ -3341,27 +3342,62 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        dispatchProvideStructureForAssistOrAutoFill(structure, true);
    }

    /** @hide */
    private ArrayList<View> getChildrenForAutofill() {
        final ArrayList<View> list = new ArrayList<>();
        populateChildrenForAutofill(list);
        return list;
    }

    /** @hide */
    private void populateChildrenForAutofill(ArrayList<View> list) {
        final int count = mChildrenCount;
        for (int i = 0; i < count; i++) {
            final View child = mChildren[i];
            if (child.isImportantForAutofill()) {
                list.add(child);
            } else if (child instanceof ViewGroup) {
                ((ViewGroup) child).populateChildrenForAutofill(list);
            }
        }
    }

    private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
            boolean forAutoFill) {
        boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
        if (blocked || structure.getChildCount() != 0) {
            return;
        }
        final View[] childrenArray;
        final ArrayList<View> childrenList;
        final int childrenCount;

        if (forAutoFill) {
            childrenArray = null;
            // TODO(b/33197203): the current algorithm allocates a new list for each children that
            // is a view group; ideally, we should use mAttachInfo.mTempArrayList instead, but that
            // would complicated the algorithm a lot...
            childrenList = getChildrenForAutofill();

            childrenCount = childrenList.size();
        } else {
            childrenArray = mChildren;
            childrenList = null;
            childrenCount = getChildCount();
        }

        if (!blocked) {
            if (structure.getChildCount() == 0) {
                final int childrenCount = getChildCount();
        if (childrenCount > 0) {
            structure.setChildCount(childrenCount);
            ArrayList<View> preorderedList = buildOrderedChildList();
            boolean customOrder = preorderedList == null
                    && isChildrenDrawingOrderEnabled();
                    final View[] children = mChildren;
            for (int i = 0; i < childrenCount; i++) {
                int childIndex;
                try {
                    childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                } catch (IndexOutOfBoundsException e) {
                    childIndex = i;
                            if (mContext.getApplicationInfo().targetSdkVersion
                                    < Build.VERSION_CODES.M) {
                    if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
                        Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
                                + i + " of " + childrenCount, e);
                        // At least one app is failing when we call getChildDrawingOrder
@@ -3395,7 +3431,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                            // Build the final view list.
                            preorderedList = new ArrayList<>(childrenCount);
                            for (int j = 0; j < childrenCount; j++) {
                                        preorderedList.add(children[permutation[j]]);
                                final int index = permutation[j];
                                final View child = forAutoFill
                                        ? childrenList.get(index)
                                        : childrenArray[index];
                                preorderedList.add(child);
                            }
                        }
                    } else {
@@ -3403,8 +3443,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                    }
                }

                        final View child = getAndVerifyPreorderedView(
                                preorderedList, children, childIndex);
                final View child = forAutoFill
                        ? getAndVerifyPreorderedView(preorderedList, childrenList, childIndex)
                        : getAndVerifyPreorderedView(preorderedList, childrenArray, childIndex);
                final ViewStructure cstructure = structure.newChild(i);

                // Must explicitly check which recursive method to call.
@@ -3415,8 +3456,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                    child.dispatchProvideStructure(cstructure);
                }
            }
                    if (preorderedList != null) preorderedList.clear();
                }
            if (preorderedList != null) {
                preorderedList.clear();
            }
        }
    }
@@ -3436,6 +3477,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return child;
    }

    private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList,
            ArrayList<View> children, int childIndex) {
        final View child;
        if (preorderedList != null) {
            child = preorderedList.get(childIndex);
            if (child == null) {
                throw new RuntimeException("Invalid preorderedList contained null child at index "
                        + childIndex);
            }
        } else {
            child = children.get(childIndex);
        }
        return child;
    }

    /** @hide */
    @Override
    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Loading