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

Commit b42d133c authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Overlay a highlight over autofilled views

Also clear this overlay once the data changes. Some views call
notifyValueUpdated even if the value did not change. Hence remeber the
data that was autofilled and check if the data really changed.

Make the autofilledDrawable publicly accessible so that virtual views
can use the same UI.

As the activity is not aware that the views were autofilled the state
has to be explicitly persisted over activity lifecycle events as part
of the view. The lifecyle does not work yet as the AutofillIds are not
stable over activity lifecycle events.

Fixes: 34946006
Test: Autofilled and changed all supported views.
      cts-tradefed run cts-dev -m CtsUiRenderingTestCases
Change-Id: I58b105bb221f1b6466dd136dfe5062d3babb5aa8
parent 630671a6
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -1609,6 +1609,7 @@ package android {
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int autofilled_highlight = 17301684; // 0x10800b4
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default_small = 17301509; // 0x1080005
    field public static final int btn_default_small = 17301509; // 0x1080005
+1 −0
Original line number Original line Diff line number Diff line
@@ -1727,6 +1727,7 @@ package android {
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int autofilled_highlight = 17301684; // 0x10800b4
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default_small = 17301509; // 0x1080005
    field public static final int btn_default_small = 17301509; // 0x1080005
+2 −0
Original line number Original line Diff line number Diff line
@@ -1609,6 +1609,7 @@ package android {
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int alert_light_frame = 17301505; // 0x1080001
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_down_float = 17301506; // 0x1080002
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int arrow_up_float = 17301507; // 0x1080003
    field public static final int autofilled_highlight = 17301684; // 0x10800b4
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int bottom_bar = 17301658; // 0x108009a
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default = 17301508; // 0x1080004
    field public static final int btn_default_small = 17301509; // 0x1080005
    field public static final int btn_default_small = 17301509; // 0x1080005
@@ -46039,6 +46040,7 @@ package android.view {
    method public void setAnimation(android.view.animation.Animation);
    method public void setAnimation(android.view.animation.Animation);
    method public void setAutofillHints(java.lang.String...);
    method public void setAutofillHints(java.lang.String...);
    method public void setAutofillMode(int);
    method public void setAutofillMode(int);
    method public void setAutofilled(boolean);
    method public void setBackground(android.graphics.drawable.Drawable);
    method public void setBackground(android.graphics.drawable.Drawable);
    method public void setBackgroundColor(int);
    method public void setBackgroundColor(int);
    method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
    method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
+11 −0
Original line number Original line Diff line number Diff line
@@ -724,6 +724,7 @@ public class Activity extends ContextThemeWrapper
    public static final int FINISH_TASK_WITH_ACTIVITY = 2;
    public static final int FINISH_TASK_WITH_ACTIVITY = 2;


    static final String FRAGMENTS_TAG = "android:fragments";
    static final String FRAGMENTS_TAG = "android:fragments";
    static final String AUTOFILL_RESET_NEEDED_TAG = "android:autofillResetNeeded";


    private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
    private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
    private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
    private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
@@ -1057,6 +1058,12 @@ public class Activity extends ContextThemeWrapper
     * @see #onSaveInstanceState
     * @see #onSaveInstanceState
     */
     */
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED_TAG, false);

        if (mAutoFillResetNeeded) {
            getSystemService(AutofillManager.class).onRestoreInstanceState(savedInstanceState);
        }

        if (mWindow != null) {
        if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
            if (windowState != null) {
@@ -1502,6 +1509,10 @@ public class Activity extends ContextThemeWrapper
        if (p != null) {
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        }
        if (mAutoFillResetNeeded) {
            outState.putBoolean(AUTOFILL_RESET_NEEDED_TAG, mAutoFillResetNeeded);
            getSystemService(AutofillManager.class).onSaveInstanceState(outState);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }
    }


+121 −5
Original line number Original line Diff line number Diff line
@@ -2750,7 +2750,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *                    1              PFLAG3_SCROLL_INDICATOR_END
     *                    1              PFLAG3_SCROLL_INDICATOR_END
     *                   1               PFLAG3_ASSIST_BLOCKED
     *                   1               PFLAG3_ASSIST_BLOCKED
     *                  1                PFLAG3_CLUSTER
     *                  1                PFLAG3_CLUSTER
     *                 x                 * NO LONGER NEEDED, SHOULD BE REUSED *
     *                 1                 PFLAG3_IS_AUTOFILLED
     *                1                  PFLAG3_FINGER_DOWN
     *                1                  PFLAG3_FINGER_DOWN
     *               1                   PFLAG3_FOCUSED_BY_DEFAULT
     *               1                   PFLAG3_FOCUSED_BY_DEFAULT
     *             11                    PFLAG3_AUTO_FILL_MODE_MASK
     *             11                    PFLAG3_AUTO_FILL_MODE_MASK
@@ -2960,6 +2960,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
     */
    private static final int PFLAG3_CLUSTER = 0x8000;
    private static final int PFLAG3_CLUSTER = 0x8000;
    /**
     * Flag indicating that the view is autofilled
     *
     * @see #isAutofilled()
     * @see #setAutofilled(boolean)
     */
    private static final int PFLAG3_IS_AUTOFILLED = 0x10000;
    /**
    /**
     * Indicates that the user is currently touching the screen.
     * Indicates that the user is currently touching the screen.
     * Currently used for the tooltip positioning only.
     * Currently used for the tooltip positioning only.
@@ -7440,10 +7448,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * <ol>
     * <ol>
     * <li>Calling the proper getter method on {@link AutofillValue} to fetch the actual value.
     * <li>Calling the proper getter method on {@link AutofillValue} to fetch the actual value.
     * <li>Passing the actual value to the equivalent setter in the view.
     * <li>Passing the actual value to the equivalent setter in the view.
     * <ol>
     * </ol>
     *
     *
     * <p>For example, a text-field view would call:
     * <p>For example, a text-field view would call:
     *
     * <pre class="prettyprint">
     * <pre class="prettyprint">
     * CharSequence text = value.getTextValue();
     * CharSequence text = value.getTextValue();
     * if (text != null) {
     * if (text != null) {
@@ -7451,6 +7458,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * }
     * }
     * </pre>
     * </pre>
     *
     *
     * <p>If the value is updated asyncronously the next call to
     * {@link AutofillManager#notifyValueChanged(View)} must happen <u>after</u> the value was
     * changed to the autofilled value. If not, the view will not be considered autofilled.
     *
     * @param value value to be autofilled.
     * @param value value to be autofilled.
     */
     */
    public void autofill(@SuppressWarnings("unused") AutofillValue value) {
    public void autofill(@SuppressWarnings("unused") AutofillValue value) {
@@ -7461,6 +7472,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     *
     *
     * <p>See {@link #autofill(AutofillValue)} and
     * <p>See {@link #autofill(AutofillValue)} and
     * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info.
     * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info.
     * <p>To indicate that a virtual view was autofilled
     * <code>@android:drawable/autofilled_highlight</code> should be drawn over it until the data
     * changes.
     *
     *
     * @param values map of values to be autofilled, keyed by virtual child id.
     * @param values map of values to be autofilled, keyed by virtual child id.
     */
     */
@@ -7490,6 +7504,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return mAutofillHints;
        return mAutofillHints;
    }
    }
    /**
     * @hide
     */
    public boolean isAutofilled() {
        return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0;
    }
    /**
    /**
     * Gets the {@link View}'s current autofill value.
     * Gets the {@link View}'s current autofill value.
     *
     *
@@ -9130,6 +9151,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        }
    }
    }
    /**
     * @hide
     */
    @TestApi
    public void setAutofilled(boolean isAutofilled) {
        boolean wasChanged = isAutofilled != isAutofilled();
        if (wasChanged) {
            if (isAutofilled) {
                mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED;
            } else {
                mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED;
            }
            invalidate();
        }
    }
    /**
    /**
     * Set whether this view should have sound effects enabled for events such as
     * Set whether this view should have sound effects enabled for events such as
     * clicking and touching.
     * clicking and touching.
@@ -17117,9 +17156,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    @CallSuper
    @CallSuper
    protected Parcelable onSaveInstanceState() {
    protected Parcelable onSaveInstanceState() {
        mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
        mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
        if (mStartActivityRequestWho != null) {
        if (mStartActivityRequestWho != null || isAutofilled()) {
            BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
            BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
            if (mStartActivityRequestWho != null) {
                state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED;
            }
            if (isAutofilled()) {
                state.mSavedData |= BaseSavedState.IS_AUTOFILLED;
            }
            state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
            state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
            state.mIsAutofilled = isAutofilled();
            return state;
            return state;
        }
        }
        return BaseSavedState.EMPTY_STATE;
        return BaseSavedState.EMPTY_STATE;
@@ -17189,7 +17238,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    + "other views do not use the same id.");
                    + "other views do not use the same id.");
        }
        }
        if (state != null && state instanceof BaseSavedState) {
        if (state != null && state instanceof BaseSavedState) {
            mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved;
            BaseSavedState baseState = (BaseSavedState) state;
            if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) {
                mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved;
            }
            if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
                setAutofilled(baseState.mIsAutofilled);
            }
        }
        }
    }
    }
@@ -17570,6 +17626,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    // Fast path for layouts with no backgrounds
                    // Fast path for layouts with no backgrounds
                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                        dispatchDraw(canvas);
                        dispatchDraw(canvas);
                        drawAutofilledHighlight(canvas);
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                            mOverlay.getOverlayView().draw(canvas);
                            mOverlay.getOverlayView().draw(canvas);
                        }
                        }
@@ -17870,6 +17927,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
            dispatchDraw(canvas);
            dispatchDraw(canvas);
            drawAutofilledHighlight(canvas);
            if (mOverlay != null && !mOverlay.isEmpty()) {
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().draw(canvas);
                mOverlay.getOverlayView().draw(canvas);
            }
            }
@@ -17946,6 +18004,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        // Fast path for layouts with no backgrounds
        // Fast path for layouts with no backgrounds
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
            dispatchDraw(canvas);
            dispatchDraw(canvas);
            drawAutofilledHighlight(canvas);
            if (mOverlay != null && !mOverlay.isEmpty()) {
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().draw(canvas);
                mOverlay.getOverlayView().draw(canvas);
            }
            }
@@ -18630,6 +18689,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            // Step 4, draw the children
            // Step 4, draw the children
            dispatchDraw(canvas);
            dispatchDraw(canvas);
            drawAutofilledHighlight(canvas);
            // Overlay is part of the content and draws beneath Foreground
            // Overlay is part of the content and draws beneath Foreground
            if (mOverlay != null && !mOverlay.isEmpty()) {
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
                mOverlay.getOverlayView().dispatchDraw(canvas);
@@ -18783,6 +18844,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        canvas.restoreToCount(saveCount);
        canvas.restoreToCount(saveCount);
        drawAutofilledHighlight(canvas);
        // Overlay is part of the content and draws beneath Foreground
        // Overlay is part of the content and draws beneath Foreground
        if (mOverlay != null && !mOverlay.isEmpty()) {
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
            mOverlay.getOverlayView().dispatchDraw(canvas);
@@ -20140,6 +20203,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        }
    }
    }
    /**
     * Get the drawable to be overlayed when a view is autofilled
     *
     * @return The drawable
     *
     * @throws IllegalStateException if the drawable could not be found.
     */
    @NonNull private Drawable getAutofilledDrawable() {
        // Lazily load the isAutofilled drawable.
        if (mAttachInfo.mAutofilledDrawable == null) {
            mAttachInfo.mAutofilledDrawable = mContext.getDrawable(R.drawable.autofilled_highlight);
            if (mAttachInfo.mAutofilledDrawable == null) {
                throw new IllegalStateException(
                        "Could not find android:drawable/autofilled_highlight");
            }
        }
        return mAttachInfo.mAutofilledDrawable;
    }
    /**
     * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled.
     *
     * @param canvas The canvas to draw on
     */
    private void drawAutofilledHighlight(@NonNull Canvas canvas) {
        if (isAutofilled()) {
            Drawable autofilledHighlight = getAutofilledDrawable();
            autofilledHighlight.setBounds(0, 0, getWidth(), getHeight());
            autofilledHighlight.draw(canvas);
        }
    }
    /**
    /**
     * Draw any foreground content for this view.
     * Draw any foreground content for this view.
     *
     *
@@ -24305,7 +24403,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * state in {@link android.view.View#onSaveInstanceState()}.
     * state in {@link android.view.View#onSaveInstanceState()}.
     */
     */
    public static class BaseSavedState extends AbsSavedState {
    public static class BaseSavedState extends AbsSavedState {
        static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1;
        static final int IS_AUTOFILLED = 0b10;
        // Flags that describe what data in this state is valid
        int mSavedData;
        String mStartActivityRequestWhoSaved;
        String mStartActivityRequestWhoSaved;
        boolean mIsAutofilled;
        /**
        /**
         * Constructor used when reading from a parcel. Reads the state of the superclass.
         * Constructor used when reading from a parcel. Reads the state of the superclass.
@@ -24325,7 +24429,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         */
         */
        public BaseSavedState(Parcel source, ClassLoader loader) {
        public BaseSavedState(Parcel source, ClassLoader loader) {
            super(source, loader);
            super(source, loader);
            mSavedData = source.readInt();
            mStartActivityRequestWhoSaved = source.readString();
            mStartActivityRequestWhoSaved = source.readString();
            mIsAutofilled = source.readBoolean();
        }
        }
        /**
        /**
@@ -24340,7 +24446,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        @Override
        @Override
        public void writeToParcel(Parcel out, int flags) {
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            super.writeToParcel(out, flags);
            out.writeInt(mSavedData);
            out.writeString(mStartActivityRequestWhoSaved);
            out.writeString(mStartActivityRequestWhoSaved);
            out.writeBoolean(mIsAutofilled);
        }
        }
        public static final Parcelable.Creator<BaseSavedState> CREATOR
        public static final Parcelable.Creator<BaseSavedState> CREATOR
@@ -24740,6 +24849,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         */
         */
        Drawable mAccessibilityFocusDrawable;
        Drawable mAccessibilityFocusDrawable;
        /**
         * The drawable for highlighting autofilled views.
         *
         * @see #isAutofilled()
         */
        Drawable mAutofilledDrawable;
        /**
        /**
         * Show where the margins, bounds and layout bounds are for each view.
         * Show where the margins, bounds and layout bounds are for each view.
         */
         */
Loading