OSDN Git Service

Provide a way to set AutofillId on ViewStructure.
authorFelipe Leme <felipeal@google.com>
Tue, 25 Apr 2017 17:21:45 +0000 (10:21 -0700)
committerFelipe Leme <felipeal@google.com>
Tue, 25 Apr 2017 21:12:03 +0000 (14:12 -0700)
So far that was done indirectly by public methods that could
be overridden in away that does not set the proper id in the structure,
which would crash apps.

Bug: 36171235
Test: modified VirtualContainerActivityTest#testAutofillOverrideDispatchprovideAutofillStructure

Change-Id: I3f1c64020125cbb8349971a0bc52ccd1e0c81e62

api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/app/assist/AssistStructure.java
core/java/android/view/View.java
core/java/android/view/ViewStructure.java
core/java/android/widget/DatePicker.java
core/java/android/widget/TimePicker.java

index c7fd3dc..23f0306 100644 (file)
@@ -45419,6 +45419,7 @@ package android.view {
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public java.lang.String[] getAutofillHints();
+    method public final android.view.autofill.AutofillId getAutofillId();
     method public int getAutofillType();
     method public android.view.autofill.AutofillValue getAutofillValue();
     method public android.graphics.drawable.Drawable getBackground();
@@ -46541,6 +46542,7 @@ package android.view {
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.autofill.AutofillId getAutofillId();
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46554,7 +46556,8 @@ package android.view {
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHints(java.lang.String[]);
-    method public abstract void setAutofillId(android.view.ViewStructure, int);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId, int);
     method public abstract void setAutofillOptions(java.lang.CharSequence[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
@@ -46584,7 +46587,6 @@ package android.view {
     method public abstract void setTextLines(int[], int[]);
     method public abstract void setTextStyle(float, int, int, int);
     method public abstract void setTransformation(android.graphics.Matrix);
-    method public abstract deprecated void setUrl(java.lang.String);
     method public abstract void setVisibility(int);
     method public abstract void setWebDomain(java.lang.String);
   }
index 78f911a..d9fe039 100644 (file)
@@ -49001,6 +49001,7 @@ package android.view {
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public java.lang.String[] getAutofillHints();
+    method public final android.view.autofill.AutofillId getAutofillId();
     method public int getAutofillType();
     method public android.view.autofill.AutofillValue getAutofillValue();
     method public android.graphics.drawable.Drawable getBackground();
@@ -50123,6 +50124,7 @@ package android.view {
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.autofill.AutofillId getAutofillId();
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -50136,7 +50138,8 @@ package android.view {
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHints(java.lang.String[]);
-    method public abstract void setAutofillId(android.view.ViewStructure, int);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId, int);
     method public abstract void setAutofillOptions(java.lang.CharSequence[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
@@ -50166,7 +50169,6 @@ package android.view {
     method public abstract void setTextLines(int[], int[]);
     method public abstract void setTextStyle(float, int, int, int);
     method public abstract void setTransformation(android.graphics.Matrix);
-    method public abstract deprecated void setUrl(java.lang.String);
     method public abstract void setVisibility(int);
     method public abstract void setWebDomain(java.lang.String);
   }
index 4ad78c5..1ed0ea6 100644 (file)
@@ -45786,6 +45786,7 @@ package android.view {
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public java.lang.String[] getAutofillHints();
+    method public final android.view.autofill.AutofillId getAutofillId();
     method public int getAutofillType();
     method public android.view.autofill.AutofillValue getAutofillValue();
     method public android.graphics.drawable.Drawable getBackground();
@@ -46916,6 +46917,7 @@ package android.view {
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.autofill.AutofillId getAutofillId();
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -46929,7 +46931,8 @@ package android.view {
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
     method public abstract void setAutofillHints(java.lang.String[]);
-    method public abstract void setAutofillId(android.view.ViewStructure, int);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId);
+    method public abstract void setAutofillId(android.view.autofill.AutofillId, int);
     method public abstract void setAutofillOptions(java.lang.CharSequence[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
@@ -46959,7 +46962,6 @@ package android.view {
     method public abstract void setTextLines(int[], int[]);
     method public abstract void setTextStyle(float, int, int, int);
     method public abstract void setTransformation(android.graphics.Matrix);
-    method public abstract deprecated void setUrl(java.lang.String);
     method public abstract void setVisibility(int);
     method public abstract void setWebDomain(java.lang.String);
   }
index d757f3e..d6b89a1 100644 (file)
@@ -1644,7 +1644,7 @@ public class AssistStructure implements Parcelable {
 
         @Override
         public void setAutofillId(@NonNull ViewStructure parent, int virtualId) {
-            mNode.mAutofillId = new AutofillId(parent.getAutofillId(), virtualId);
+            setAutofillId(parent.getAutofillId(), virtualId);
         }
 
         @Override
@@ -1685,8 +1685,13 @@ public class AssistStructure implements Parcelable {
         }
 
         @Override
-        public void setAutofillId(int viewId) {
-            mNode.mAutofillId = new AutofillId(viewId);
+        public void setAutofillId(@NonNull AutofillId id) {
+            mNode.mAutofillId = id;
+        }
+
+        @Override
+        public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
+            mNode.mAutofillId = new AutofillId(parentId, virtualId);
         }
 
         @Override
index d42c6db..64489b4 100644 (file)
@@ -100,6 +100,7 @@ import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
@@ -1068,10 +1069,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
 
     /**
-     * Hintd for the autofill services that describes the content of the view.
+     * Hints for the autofill services that describes the content of the view.
      */
     private @Nullable String[] mAutofillHints;
 
+    /**
+     * Autofill id, lazily created on calls to {@link #getAutofillId()}.
+     */
+    private AutofillId mAutofillId;
+
     /** @hide */
     @IntDef({
             AUTOFILL_TYPE_NONE,
@@ -7276,13 +7282,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      *
      * <p>This method already provides most of what's needed for autofill, but should be overridden
      * when:
-     * <ol>
-     * <li>The view contents does not include PII (Personally Identifiable Information), so it
+     * <ul>
+     *   <li>The view contents does not include PII (Personally Identifiable Information), so it
      * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}.
-     * <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
+     *   <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
      * {@link ViewStructure#setAutofillOptions(CharSequence[])},
-     * or {@link ViewStructure#setUrl(String)}.
-     * </ol>
+     * or {@link ViewStructure#setWebDomain(String)}.
+     * </ul>
      *
      * @param structure Fill in with structured view data. The default implementation
      * fills in all data that can be inferred from the view itself.
@@ -7292,12 +7298,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         onProvideStructureForAssistOrAutofill(structure, true);
     }
 
-    private void setAutofillId(ViewStructure structure) {
-        // The autofill id needs to be unique, but its value doesn't matter,
-        // so it's better to reuse the accessibility id to save space.
-        structure.setAutofillId(getAccessibilityViewId());
-    }
-
     private void onProvideStructureForAssistOrAutofill(ViewStructure structure,
             boolean forAutofill) {
         final int id = mID;
@@ -7317,7 +7317,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         }
 
         if (forAutofill) {
-            setAutofillId(structure);
             final @AutofillType int autofillType = getAutofillType();
             // Don't need to fill autofill info if view does not support it.
             // For example, only TextViews that are editable support autofill
@@ -7418,10 +7417,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      * @param flags optional flags (currently {@code 0}).
      */
     public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
-        // TODO(b/36171235): need a way to let apps set the ViewStructure without forcing them
-        // to call super() (in case they override both this method and dispatchProvide....
-        // Perhaps the best solution would simply make setAutofillId(ViewStructure) public.
-        setAutofillId(structure);
     }
 
     /**
@@ -7470,6 +7465,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     }
 
     /**
+     * Gets the unique identifier of this view on the screen for Autofill purposes.
+     *
+     * @return The View's Autofill id.
+     */
+    public final AutofillId getAutofillId() {
+        if (mAutofillId == null) {
+            // The autofill id needs to be unique, but its value doesn't matter,
+            // so it's better to reuse the accessibility id to save space.
+            mAutofillId = new AutofillId(getAccessibilityViewId());
+        }
+        return mAutofillId;
+    }
+
+    /**
      * Describes the autofill type that should be used on calls to
      * {@link #autofill(AutofillValue)} and {@link #autofill(SparseArray)}.
      *
@@ -7705,16 +7714,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     /**
      * Dispatch creation of {@link ViewStructure} down the hierarchy.
      *
-     * <p>The structure must be filled according to the request type, which is set in the
-     * {@code flags} parameter - see the documentation on each flag for more details.
+     * <p>The default implementation does the following:
+     *
+     * <ul>
+     *   <li>Sets the {@link AutofillId} in the structure.
+     *   <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}.
+     *   <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}.
+     * </ul>
      *
-     * <p>The default implementation calls {@link #onProvideAutofillStructure(ViewStructure, int)}
-     * and {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}.
+     * <p>When overridden, it must either call
+     * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly
+     * set the {@link AutofillId} in the structure (for example, by calling
+     * {@code structure.setAutofillId(getAutofillId())}).
      *
      * @param structure Fill in with structured view data.
      * @param flags optional flags (currently {@code 0}).
      */
-    public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
+    public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, int flags) {
         dispatchProvideStructureForAssistOrAutofill(structure, true);
     }
 
@@ -7723,7 +7739,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked();
         if (!blocked) {
             if (forAutofill) {
-                setAutofillId(structure);
+                structure.setAutofillId(getAutofillId());
                 // NOTE: flags are not currently supported, hence 0
                 onProvideAutofillStructure(structure, 0);
                 onProvideAutofillVirtualStructure(structure, 0);
index 387a9ce..fb910b8 100644 (file)
@@ -284,12 +284,30 @@ public abstract class ViewStructure {
     public abstract ViewStructure asyncNewChild(int index);
 
     /**
+     * Gets the {@link AutofillId} associated with this node.
+     */
+    @Nullable
+    public abstract AutofillId getAutofillId();
+
+    /**
+     * Sets the {@link AutofillId} associated with this node.
+     */
+    public abstract void setAutofillId(@NonNull AutofillId id);
+
+    /**
      * Sets the {@link AutofillId} for this virtual node.
      *
-     * @param parent parent node.
+     * @param parentId id of the parent node.
      * @param virtualId an opaque ID to the Android System; it's the same id used on
      *            {@link View#autofill(android.util.SparseArray)}.
      */
+    public abstract void setAutofillId(@NonNull AutofillId parentId, int virtualId);
+
+    /**
+     * @deprecated - use {@link #setAutofillId(AutofillId, int)} instead
+     * @hide
+     */
+    @Deprecated
     public abstract void setAutofillId(@NonNull ViewStructure parent, int virtualId);
 
     /**
@@ -355,14 +373,9 @@ public abstract class ViewStructure {
     /** @hide */
     public abstract Rect getTempRect();
 
-    /** @hide */
-    public abstract void setAutofillId(int viewId);
-
-    /** @hide */
-    public abstract AutofillId getAutofillId();
-
     /**
      * @deprecated - use {@link #setWebDomain(String)} instead.
+     * @hide
      */
     @Deprecated
     public abstract void setUrl(String url);
index 0dce079..8094bfc 100644 (file)
@@ -769,6 +769,7 @@ public class DatePicker extends FrameLayout {
         // This view is self-sufficient for autofill, so it needs to call
         // onProvideAutoFillStructure() to fill itself, but it does not need to call
         // dispatchProvideAutoFillStructure() to fill its children.
+        structure.setAutofillId(getAutofillId());
         onProvideAutofillStructure(structure, flags);
     }
 
index df99fb4..de289bb 100644 (file)
@@ -524,6 +524,7 @@ public class TimePicker extends FrameLayout {
         // This view is self-sufficient for autofill, so it needs to call
         // onProvideAutoFillStructure() to fill itself, but it does not need to call
         // dispatchProvideAutoFillStructure() to fill its children.
+        structure.setAutofillId(getAutofillId());
         onProvideAutofillStructure(structure, flags);
     }