YAMAFFR - Yet Another Major AutoFill Framework Refactoring

- Explicitly split View methods into Assist and AutoFill methods, rather
  than use an overloaded method that takes flags.
- Simarly, renamed ASSIST_FLAG_SANITIZED_TEXT and
  ASSIST_FLAG_NON_SANITIZED_TEXT flags to
  AUTO_FILL_FLAG_TYPE_FILL and AUTO_FILL_FLAG_TYPE_SAVE respectively.
- Created a AutoFillUI class to host the auto-fill bar and other UI
  affordances.
- Moved the temporary notifications to AutoFillUI (eventually that
  class will host the real UI).
- Moved FillData to android.app.view.autofill package.
- Split IAutoFillCallback in 2 (IAutoFillAppCallback and
  IAutoFillServerCallback, residing at the app and system_server
  respectively), so service cannot fill the app directly (which lets
  the framework control the UI).
- Moved assist's IResultReceiver to AutoFillServiceImpl so
  system_server can act as a mediator between the AutoFillService
  implementation and the app being auto-filled.
- Replaced FillData and FillableInputFields by a bunch of new objects:
  - FillResponse contains a group of Datasets, each representing
  different values
    that can be used to auto-fill an activity (for example, different
    user accounts), optional id of fields the service is interested
    to save, and an optional bundle for service-side extras.
  - Dataset contains a name, Fields, and an optional bundle for
    service-side extras.
  - Fields contain an AutoFillId (parcelable) and a value (Bundle)
- Changed the temporary notifications to emulate the new workflow:
  - Initial notification requests the auto-fill data but do not
    auto-fill.
  - Once service calls back, a new notification is shown with the
    results.
  - Then if the user selects a dataset, the activity is auto-filled
    with it.
  - It also shows a notification to emulate what can be saved.
- Created an VirtualViewDelegate for views that uses a virtual
  hierarchy for assist data.
- Added new methods on ViewStructure to add children with virtual ids.
- Added 2 methods on View to support auto-fill:
  - autoFill(Bundle) to auto-fill the view.
  - getAutoFillType() to return how the view can be auto-filled.
- AutoFillType defines the input fields that support auto-fill:
  - Text fields (like EditText)
  - Toggle fields (like CheckBox)
  - Lists (like RadioGroup)
- AutoFillType can also have a sub-type representing its semantic (for
  now only text fields have it, and it's the same as getInputType()).
- etc :-)

Bug: 31001899
Test: manual verification
Change-Id: I2dd2fdedcb3ecd1e4403f9c32fa644cb914e186f
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0d9e8a0..87e5416 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -70,9 +70,8 @@
 import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.service.autofill.FillableInputField;
 import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillAppCallback;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextAssistant;
@@ -115,6 +114,11 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.VirtualViewDelegate;
+import android.view.autofill.Dataset;
+import android.view.autofill.DatasetField;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
 import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.Toast;
@@ -130,6 +134,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -697,6 +702,9 @@
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
+    // TODO(b/33197203): set to false once stable
+    private static final boolean DEBUG_AUTO_FILL = true;
+
     /** Standard activity result: operation canceled. */
     public static final int RESULT_CANCELED    = 0;
     /** Standard activity result: operation succeeded. */
@@ -847,7 +855,10 @@
     private boolean mEatKeyUpEvent;
 
     @GuardedBy("this")
-    private IAutoFillCallback mAutoFillCallback;
+    private WeakReference<IAutoFillAppCallback> mAutoFillCallback;
+
+    @GuardedBy("this")
+    private VirtualViewDelegate.Callback mAutoFillDelegateCallback;
 
     private static native String getDlWarning();
 
@@ -1718,47 +1729,73 @@
     }
 
     /**
-     * Lazily gets the {@code IAutoFillCallback} for this activitity.
+     * Lazily sets the {@link #mAutoFillDelegateCallback}.
+     */
+    private void setAutoFillDelegateCallback() {
+        synchronized (this) {
+            if (mAutoFillDelegateCallback == null) {
+                mAutoFillDelegateCallback = new VirtualViewDelegate.Callback() {
+                    // TODO(b/33197203): implement
+                };
+            }
+        }
+    }
+
+    /**
+     * Lazily gets the {@link IAutoFillAppCallback} for this activitity.
      *
      * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields.
      */
-    IAutoFillCallback getAutoFillCallback() {
+    WeakReference<IAutoFillAppCallback> getAutoFillCallback() {
         synchronized (this) {
             if (mAutoFillCallback == null) {
-                mAutoFillCallback = new IAutoFillCallback.Stub() {
+                final IAutoFillAppCallback cb = new IAutoFillAppCallback.Stub() {
                     @Override
-                    public void autofill(@SuppressWarnings("rawtypes") List fields)
-                            throws RemoteException {
+                    public void autoFill(Dataset dataset) throws RemoteException {
+                        // TODO(b/33197203): must keep the dataset so subsequent calls pass the same
+                        // dataset.extras to service
                         runOnUiThread(() -> {
                             final View root = getWindow().getDecorView().getRootView();
-                            for (Object field : fields) {
-                                if (!(field instanceof FillableInputField)) {
-                                    Slog.w(TAG,  "autofill(): invalid type " + field.getClass());
+                            for (DatasetField field : dataset.getFields()) {
+                                final AutoFillId id = field.getId();
+                                if (id == null) {
+                                    Log.w(TAG, "autoFill(): null id on " + field);
                                     continue;
                                 }
-                                FillableInputField autoFillField = (FillableInputField) field;
-                                final int viewId = autoFillField.getId();
+                                final int viewId = id.getViewId();
                                 final View view = root.findViewByAccessibilityIdTraversal(viewId);
-                                // TODO(b/33197203): should handle other types of view as well, but
-                                // that will require:
-                                // - a new interface like AutoFillable
-                                // - a way for the views to define the type of the autofield value
-                                if ((view instanceof EditText)) {
-                                    ((EditText) view).setText(autoFillField.getValue());
+                                if (view == null) {
+                                    Log.w(TAG, "autoFill(): no View with id " + viewId);
+                                    continue;
+                                }
+
+                                // TODO(b/33197203): handle protected value (like credit card)
+                                if (id.isVirtual()) {
+                                    // Delegate virtual fields to provider.
+                                    setAutoFillDelegateCallback();
+                                    final VirtualViewDelegate mgr = view
+                                            .getAutoFillVirtualViewDelegate(
+                                                    mAutoFillDelegateCallback);
+                                    if (mgr == null) {
+                                        Log.w(TAG, "autoFill(): cannot fill virtual " + id
+                                                + "; no auto-fill provider for view "
+                                                + view.getClass());
+                                        continue;
+                                    }
+                                    if (DEBUG_AUTO_FILL) {
+                                        Log.d(TAG, "autoFill(): delegating " + id
+                                                + " to virtual manager  " + mgr);
+                                    }
+                                    mgr.autoFill(id.getVirtualChildId(), field.getValue());
+                                } else {
+                                    // Handle non-virtual fields itself.
+                                    view.autoFill(field.getValue());
                                 }
                             }
                         });
                     }
-
-                    @Override
-                    public void showError(String message) {
-                        runOnUiThread(() -> {
-                            // TODO(b/33197203): temporary show a toast until it uses the Snack bar.
-                            Toast.makeText(Activity.this, "Auto-fill request failed: " + message,
-                                    Toast.LENGTH_LONG).show();
-                        });
-                    }
                 };
+                mAutoFillCallback = new WeakReference<IAutoFillAppCallback>(cb);
             }
         }
         return mAutoFillCallback;
@@ -6096,7 +6133,7 @@
 
         if (mAutoFillCallback != null) {
             writer.print(prefix); writer.print("mAutoFillCallback: " );
-                    writer.println(mAutoFillCallback);
+                    writer.println(mAutoFillCallback.get());
         }
 
         mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cd50c4d..d362b01 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -483,6 +483,12 @@
     /** @hide requestType for assist context: generate full AssistStructure. */
     public static final int ASSIST_CONTEXT_FULL = 1;
 
+    /** @hide requestType for assist context: generate full AssistStructure for auto-fill. */
+    public static final int ASSIST_CONTEXT_AUTO_FILL = 2;
+
+    /** @hide requestType for assist context: generate full AssistStructure for auto-fill save. */
+    public static final int ASSIST_CONTEXT_AUTO_FILL_SAVE = 3;
+
     /** @hide Flag for registerUidObserver: report changes in process state. */
     public static final int UID_OBSERVER_PROCSTATE = 1<<0;
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e34fabc..e3bbc92 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -89,7 +89,7 @@
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
 import android.service.autofill.AutoFillService;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillAppCallback;
 import android.service.voice.VoiceInteractionSession;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
@@ -2884,9 +2884,8 @@
         // - it does not call onProvideAssistData()
         // - it needs an IAutoFillCallback
         // - it sets the flags so views can provide autofill-specific data (such as passwords)
-        boolean forAutoFill = (cmd.flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+        boolean forAutoFill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL
+                || cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
 
         // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         if (mLastSessionId != cmd.sessionId) {
@@ -2910,22 +2909,23 @@
             if (!forAutoFill) {
                 r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
                 r.activity.onProvideAssistData(data);
+                referrer = r.activity.onProvideReferrer();
             }
-            referrer = r.activity.onProvideReferrer();
             if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
                 structure = new AssistStructure(r.activity, cmd.flags);
                 Intent activityIntent = r.activity.getIntent();
-                if (cmd.flags > 0) {
+                if (forAutoFill) {
                     data.putInt(VoiceInteractionSession.KEY_FLAGS, cmd.flags);
                 }
+                boolean addAutoFillCallback = false;
                 // TODO(b/33197203): re-evaluate conditions below for auto-fill. In particular,
                 // FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
-                if (activityIntent != null && (r.window == null ||
+                boolean notSecure = r.window == null ||
                         (r.window.getAttributes().flags
-                                & WindowManager.LayoutParams.FLAG_SECURE) == 0)) {
+                                & WindowManager.LayoutParams.FLAG_SECURE) == 0;
+                if (activityIntent != null && notSecure) {
                     if (forAutoFill) {
-                        IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback();
-                        data.putBinder(AutoFillService.KEY_CALLBACK, autoFillCallback.asBinder());
+                        addAutoFillCallback = true;
                     } else {
                         Intent intent = new Intent(activityIntent);
                         intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -2936,10 +2936,21 @@
                 } else {
                     if (!forAutoFill) {
                         content.setDefaultIntent(new Intent());
+                    } else {
+                        // activityIntent is unlikely to be null, but if it is, we should still
+                        // set the auto-fill callback.
+                        addAutoFillCallback = notSecure;
                     }
                 }
                 if (!forAutoFill) {
                     r.activity.onProvideAssistContent(content);
+                } else if (addAutoFillCallback) {
+                    IAutoFillAppCallback cb = r.activity.getAutoFillCallback().get();
+                    if (cb != null) {
+                        data.putBinder(AutoFillService.KEY_CALLBACK, cb.asBinder());
+                    } else {
+                        Slog.w(TAG, "handleRequestAssistContextExtras(): callback was GCed");
+                    }
                 }
             }
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 21854d3..a2d9c45 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -586,7 +586,7 @@
     void unregisterTaskStackListener(ITaskStackListener listener);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
-            in IBinder activityToken, int flags);
+            int resultCode, in IBinder activityToken, int flags);
     void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
     int restartUserInBackground(int userId);
 
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1988e42..b94264e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -21,6 +21,8 @@
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillId;
 
 import java.util.ArrayList;
 
@@ -411,25 +413,30 @@
             mTitle = root.getTitle();
             mDisplayId = root.getDisplayId();
             mRoot = new ViewNode();
+
+            // Must explicitly call the proper method based on flags since we don't know which
+            // method (if any) was overridden by the View subclass.
+            boolean forAutoFill = (flags
+                    & (View.AUTO_FILL_FLAG_TYPE_FILL
+                            | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
+
             ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
             if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 // This is a secure window, so it doesn't want a screenshot, and that
                 // means we should also not copy out its view hierarchy.
 
-                // Must explicitly set which method to calls since View subclasses might
-                // have implemented the deprecated method.
-                if (flags == 0) {
-                    view.onProvideStructure(builder);
+                if (forAutoFill) {
+                    view.onProvideAutoFillStructure(builder, flags);
                 } else {
-                    view.onProvideStructure(builder, flags);
+                    view.onProvideStructure(builder);
                 }
                 builder.setAssistBlocked(true);
                 return;
             }
-            if (flags == 0) {
-                view.dispatchProvideStructure(builder);
+            if (forAutoFill) {
+                view.dispatchProvideAutoFillStructure(builder, flags);
             } else {
-                view.dispatchProvideStructure(builder, flags);
+                view.dispatchProvideStructure(builder);
             }
         }
 
@@ -526,7 +533,10 @@
         String mIdPackage;
         String mIdType;
         String mIdEntry;
-        int mAutoFillId = View.NO_ID;
+        // TODO(b/33197203): once we have more flags, it might be better to store the individual
+        // fields (viewId and childId) of the field.
+        AutoFillId mAutoFillId;
+        AutoFillType mAutoFillType;
         int mX;
         int mY;
         int mScrollX;
@@ -551,7 +561,11 @@
         static final int FLAGS_ACTIVATED = 0x00002000;
         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
 
-        static final int FLAGS_HAS_AUTO_FILL_ID = 0x80000000;
+        // TODO(b/33197203): auto-fill data is made of many fields and ideally we should verify
+        // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
+        // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
+        // So, to keep thinkg simpler for now, let's just use on flag for all of them...
+        static final int FLAGS_HAS_AUTO_FILL_DATA = 0x80000000;
         static final int FLAGS_HAS_MATRIX = 0x40000000;
         static final int FLAGS_HAS_ALPHA = 0x20000000;
         static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -595,8 +609,9 @@
                     }
                 }
             }
-            if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
-                mAutoFillId = in.readInt();
+            if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+                mAutoFillId = in.readParcelable(null);
+                mAutoFillType = in.readParcelable(null);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -653,8 +668,8 @@
             if (mId != View.NO_ID) {
                 flags |= FLAGS_HAS_ID;
             }
-            if (mAutoFillId != View.NO_ID) {
-                flags |= FLAGS_HAS_AUTO_FILL_ID;
+            if (mAutoFillId != null) {
+                flags |= FLAGS_HAS_AUTO_FILL_DATA;
             }
             if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
                     || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
@@ -700,8 +715,9 @@
                     }
                 }
             }
-            if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
-                out.writeInt(mAutoFillId);
+            if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+                out.writeParcelable(mAutoFillId, 0);
+                out.writeParcelable(mAutoFillType,  0);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -773,16 +789,26 @@
         }
 
         /**
-         * Returns the id that can be used to auto-fill the view.
+         * Gets the id that can be used to auto-fill the view contents.
          *
          * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
          * for assist.
          */
-        public int getAutoFillId() {
+        public AutoFillId getAutoFillId() {
             return mAutoFillId;
         }
 
         /**
+         * Gets the the type of value that can be used to auto-fill the view contents.
+         *
+         * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+         * for assist.
+         */
+        public AutoFillType getAutoFillType() {
+            return mAutoFillType;
+        }
+
+        /**
          * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
          */
         public int getLeft() {
@@ -1318,17 +1344,23 @@
             return mNode.mChildren != null ? mNode.mChildren.length : 0;
         }
 
-        @Override
-        public ViewStructure newChild(int index) {
+        private void setAutoFillId(ViewNode child, boolean forAutoFill, int virtualId) {
+            if (forAutoFill) {
+                child.mAutoFillId = new AutoFillId(mNode.mAutoFillId, virtualId);
+            }
+        }
+
+        private ViewStructure newChild(int index, boolean forAutoFill, int virtualId) {
             ViewNode node = new ViewNode();
+            setAutoFillId(node, forAutoFill, virtualId);
             mNode.mChildren[index] = node;
             return new ViewNodeBuilder(mAssist, node, false);
         }
 
-        @Override
-        public ViewStructure asyncNewChild(int index) {
+        private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId) {
             synchronized (mAssist) {
                 ViewNode node = new ViewNode();
+                setAutoFillId(node, forAutoFill, virtualId);
                 mNode.mChildren[index] = node;
                 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
                 mAssist.mPendingAsyncChildren.add(builder);
@@ -1337,6 +1369,26 @@
         }
 
         @Override
+        public ViewStructure newChild(int index) {
+            return newChild(index, false, 0);
+        }
+
+        @Override
+        public ViewStructure newChild(int index, int virtualId) {
+            return newChild(index, true, virtualId);
+        }
+
+        @Override
+        public ViewStructure asyncNewChild(int index) {
+            return asyncNewChild(index, false, 0);
+        }
+
+        @Override
+        public ViewStructure asyncNewChild(int index, int virtualId) {
+            return asyncNewChild(index, true, virtualId);
+        }
+
+        @Override
         public void asyncCommit() {
             synchronized (mAssist) {
                 if (!mAsync) {
@@ -1356,9 +1408,20 @@
         }
 
         @Override
-        public void setAutoFillId(int autoFillId) {
-            mNode.mAutoFillId = autoFillId;
+        public void setAutoFillId(int viewId) {
+            mNode.mAutoFillId = new AutoFillId(viewId);
         }
+
+        @Override
+        public AutoFillId getAutoFillId() {
+            return mNode.mAutoFillId;
+        }
+
+        @Override
+        public void setAutoFillType(AutoFillType type) {
+           mNode.mAutoFillType = type;
+        }
+
     }
 
     /** @hide */
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index a7941c7..c2e980c 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -17,8 +17,8 @@
 
 import static android.service.voice.VoiceInteractionSession.KEY_FLAGS;
 import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.View.ASSIST_FLAG_SANITIZED_TEXT;
-import static android.view.View.ASSIST_FLAG_NON_SANITIZED_TEXT;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
 
 import android.annotation.SdkConstant;
 import android.app.Activity;
@@ -32,12 +32,15 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 
-// TODO(b/33197203): improve javadoc (class and methods)
+// TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
+// life-cycle (and how state could be maintained on server-side) is well documented.
 
 /**
  * Top-level service of the current auto-fill service for a given user.
@@ -58,40 +61,50 @@
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
 
-    // Bundle keys.
-    /** @hide */
-    public static final String KEY_CALLBACK = "callback";
+    // Internal bundle keys.
+    /** @hide */ public static final String KEY_CALLBACK = "callback";
+    /** @hide */ public static final String KEY_SAVABLE_IDS = "savable_ids";
+
+    // Prefix for public bundle keys.
+    private static final String KEY_PREFIX = "android.service.autofill.extra.";
+
+    /**
+     * Key of the {@link Bundle} passed to methods such as
+     * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
+     * containing the extras set by
+     * {@link android.view.autofill.FillResponse.Builder#setExtras(Bundle)}.
+     */
+    public static final String EXTRA_RESPONSE_EXTRAS = KEY_PREFIX + "RESPONSE_EXTRAS";
+
+    /**
+     * Key of the {@link Bundle} passed to methods such as
+     * {@link #onSaveRequest(AssistStructure, Bundle, CancellationSignal, SaveCallback)}
+     * containing the extras set by
+     * {@link android.view.autofill.Dataset.Builder#setExtras(Bundle)}.
+     */
+    public static final String EXTRA_DATASET_EXTRAS = KEY_PREFIX + "DATASET_EXTRAS";
 
     // Handler messages.
     private static final int MSG_CONNECT = 1;
     private static final int MSG_AUTO_FILL_ACTIVITY = 2;
     private static final int MSG_DISCONNECT = 3;
 
-    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
-        @Override
-        public void send(int resultCode, Bundle resultData) throws RemoteException {
-            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
-            final IBinder binder = resultData.getBinder(KEY_CALLBACK);
-            final int flags = resultData.getInt(KEY_FLAGS, 0);
+    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
 
+        @Override
+        public void autoFill(AssistStructure structure, IAutoFillServerCallback callback,
+                Bundle extras, int flags) {
             mHandlerCaller
-                .obtainMessageIOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, binder).sendToTarget();
+                    .obtainMessageIOOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, extras, callback)
+                    .sendToTarget();
         }
 
-    };
-
-    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
         @Override
         public void onConnected() {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT));
         }
 
         @Override
-        public IResultReceiver getAssistReceiver() {
-            return mAssistReceiver;
-        }
-
-        @Override
         public void onDisconnected() {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT));
         }
@@ -107,10 +120,11 @@
                     break;
                 } case MSG_AUTO_FILL_ACTIVITY: {
                     final SomeArgs args = (SomeArgs) msg.obj;
-                    final AssistStructure structure = (AssistStructure) args.arg1;
-                    final IBinder binder = (IBinder) args.arg2;
                     final int flags = msg.arg1;
-                    requestAutoFill(structure, flags, binder);
+                    final AssistStructure structure = (AssistStructure) args.arg1;
+                    final Bundle extras = (Bundle) args.arg2;
+                    final IAutoFillServerCallback callback = (IAutoFillServerCallback) args.arg3;
+                    requestAutoFill(callback, structure, extras, flags);
                     break;
                 } case MSG_DISCONNECT: {
                     onDisconnected();
@@ -146,7 +160,7 @@
     }
 
     /**
-     * Called when the Android System connects to service.
+     * Called when the Android system connects to service.
      *
      * <p>You should generally do initialization here rather than in {@link #onCreate}.
      */
@@ -155,12 +169,19 @@
     }
 
     /**
-     * Called when user requests service to auto-fill an {@link Activity}.
+     * Called by the Android system do decide if an {@link Activity} can be auto-filled by the
+     * service.
      *
-     * @param structure {@link Activity}'s view structure .
-     * @param data bundle with optional parameters (currently none) which is passed along on
-     * subsequent calls (so it can be used by the service to share data).
+     * <p>Service must call one of the {@link FillCallback} methods (like
+     * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)})
+     * to notify the result of the request.
+     *
+     * @param structure {@link Activity}'s view structure.
+     * @param data bundle containing additional arguments set by the Android system (currently none)
+     * or data passed by the service on previous calls to fullfill other sections of this activity
+     * (see {@link FillResponse} Javadoc for examples of multiple-sections requests).
      * @param cancellationSignal signal for observing cancel requests.
+     * @param callback object used to notify the result of the request.
      */
     public abstract void onFillRequest(AssistStructure structure,
             Bundle data, CancellationSignal cancellationSignal, FillCallback callback);
@@ -168,29 +189,31 @@
     /**
      * Called when user requests service to save the fields of an {@link Activity}.
      *
+     * <p>Service must call one of the {@link SaveCallback} methods (like
+     * {@link SaveCallback#onSuccess(AutoFillId[])} or {@link SaveCallback#onFailure(CharSequence)})
+     * to notify the result of the request.
+     *
      * @param structure {@link Activity}'s view structure.
-     * @param data same bundle passed to
-     * {@link #onFillRequest(AssistStructure, Bundle, CancellationSignal, FillCallback)};
-     * might also contain with optional parameters (currently none).
+     * @param data bundle containing additional arguments set by the Android system (currently none)
+     * or data passed by the service in the {@link FillResponse} that originated this call.
      * @param cancellationSignal signal for observing cancel requests.
      * @param callback object used to notify the result of the request.
      */
     public abstract void onSaveRequest(AssistStructure structure,
             Bundle data, CancellationSignal cancellationSignal, SaveCallback callback);
 
-    private void requestAutoFill(AssistStructure structure, int flags, IBinder binder) {
-        // TODO(b/33197203): pass the Bundle received from mAssistReceiver instead?
-        final Bundle data = new Bundle();
+    private void requestAutoFill(IAutoFillServerCallback callback, AssistStructure structure,
+            Bundle data, int flags) {
         switch (flags) {
-            case ASSIST_FLAG_SANITIZED_TEXT:
-                final FillCallback fillCallback = new FillCallback(binder);
+            case AUTO_FILL_FLAG_TYPE_FILL:
+                final FillCallback fillCallback = new FillCallback(callback);
                 // TODO(b/33197203): hook up the cancelationSignal
                 onFillRequest(structure, data, new CancellationSignal(), fillCallback);
                 break;
-            case ASSIST_FLAG_NON_SANITIZED_TEXT:
-                final SaveCallback saveCallback = new SaveCallback(binder);
+            case AUTO_FILL_FLAG_TYPE_SAVE:
+                final SaveCallback saveCallback = new SaveCallback(callback);
                 // TODO(b/33197203): hook up the cancelationSignal
-                onSaveRequest(structure, null, new CancellationSignal(), saveCallback);
+                onSaveRequest(structure, data, new CancellationSignal(), saveCallback);
                 break;
             default:
                 Log.w(TAG, "invalid flag on requestAutoFill(): " + flags);
@@ -198,7 +221,7 @@
     }
 
     /**
-     * Called when the Android System disconnects from the service.
+     * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AutoFillService}.
      */
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 3284b90..5a9a9f6 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -18,19 +18,16 @@
 
 import static android.service.autofill.AutoFillService.DEBUG;
 
+import android.annotation.Nullable;
 import android.app.Activity;
-import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.SparseArray;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.util.Preconditions;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being
  * auto-filled.
@@ -39,40 +36,50 @@
 
     private static final String TAG = "FillCallback";
 
-    private final IAutoFillCallback mCallback;
+    private final IAutoFillServerCallback mCallback;
+
+    private boolean mReplied = false;
 
     /** @hide */
-    FillCallback(IBinder binder) {
-        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    FillCallback(IAutoFillServerCallback callback) {
+        mCallback = callback;
     }
 
     /**
-     * Auto-fills the {@link Activity}.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
+     * was successfully fulfilled by the service.
      *
-     * @throws RuntimeException if an error occurred while auto-filling it.
+     * @param response auto-fill information for that activity, or {@code null} when the activity
+     * cannot be auto-filled (for example, if it only contains read-only fields).
+     *
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
-    public void onSuccess(FillData data) {
-        if (DEBUG) Log.d(TAG, "onSuccess(): data=" + data);
+    public void onSuccess(@Nullable FillResponse response) {
+        if (DEBUG) Log.d(TAG, "onSuccess(): respose=" + response);
 
-        Preconditions.checkArgument(data != null, "data cannot be null");
+        checkNotRepliedYet();
 
         try {
-            mCallback.autofill(data.asList());
+            mCallback.showResponse(response);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Notifies the {@link Activity} that the auto-fill request failed.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, FillCallback)}
+     * could not be fulfilled by the service.
      *
-     * @param message error message to be displayed.
+     * @param message error message to be displayed to the user.
      *
-     * @throws RuntimeException if an error occurred while notifying the activity.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
+        checkNotRepliedYet();
         Preconditions.checkArgument(message != null, "message cannot be null");
 
         try {
@@ -82,70 +89,9 @@
         }
     }
 
-    /**
-     * Data used to fill the fields of an {@link Activity}.
-     *
-     * <p>This class is immutable.
-     */
-    public static final class FillData {
-
-        private final List<FillableInputField> mList;
-
-        private FillData(Builder builder) {
-            final int size = builder.mFields.size();
-            final List<FillableInputField> list = new ArrayList<>(size);
-            for (int i = 0; i < size; i++) {
-                list.add(builder.mFields.valueAt(i));
-            }
-            mList = Collections.unmodifiableList(list);
-            // TODO: use FastImmutableArraySet or a similar structure instead?
-        }
-
-        /**
-         * Gets the response as a {@code List} so it can be used in a binder call.
-         */
-        List<FillableInputField> asList() {
-            return mList;
-        }
-
-        @Override
-        public String toString() {
-            return "[AutoFillResponse: " + mList + "]";
-        }
-
-        /**
-         * Builder for {@link FillData} objects.
-         *
-         * <p>Typical usage:
-         *
-         * <pre class="prettyprint">
-         * FillCallback.FillData data = new FillCallback.FillData.Builder()
-         *     .setTextField(id1, "value 1")
-         *     .setTextField(id2, "value 2")
-         *     .build()
-         * </pre>
-         */
-        public static class Builder {
-            private final SparseArray<FillableInputField> mFields = new SparseArray<>();
-
-            /**
-             * Auto-fills a text field.
-             *
-             * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
-             * @param text text to be auto-filled.
-             * @return same builder so it can be chained.
-             */
-            public Builder setTextField(int id, String text) {
-                mFields.put(id, FillableInputField.forText(id, text));
-                return this;
-            }
-
-            /**
-             * Builds a new {@link FillData} instance.
-             */
-            public FillData build() {
-                return new FillData(this);
-            }
-        }
+    // There can be only one!!
+    private void checkNotRepliedYet() {
+        Preconditions.checkState(!mReplied, "already replied");
+        mReplied = true;
     }
 }
diff --git a/core/java/android/service/autofill/FillableInputField.java b/core/java/android/service/autofill/FillableInputField.java
deleted file mode 100644
index 62950b4..0000000
--- a/core/java/android/service/autofill/FillableInputField.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.autofill;
-
-import android.app.assist.AssistStructure.ViewNode;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents a view field that can be auto-filled.
- *
- * <p>Currently only text-fields are supported, so the value of the field can be obtained through
- * {@link #getValue()}.
- *
- * @hide
- */
-public final class FillableInputField implements Parcelable {
-
-    private final int mId;
-    private final String mValue;
-
-    private FillableInputField(int id, String value) {
-        mId = id;
-        mValue = value;
-    }
-
-    private FillableInputField(Parcel parcel) {
-        mId = parcel.readInt();
-        mValue = parcel.readString();
-    }
-
-    /**
-     * Gets the view id as returned by {@link ViewNode#getAutoFillId()}.
-     */
-    public int getId() {
-        return mId;
-    }
-
-    /**
-     * Gets the value of this field.
-     */
-    public String getValue() {
-        return mValue;
-
-    }
-
-    @Override
-    public String toString() {
-        return "[AutoFillField: " + mId + "=" + mValue + "]";
-    }
-
-    /**
-     * Creates an {@code AutoFillField} for a text field.
-     *
-     * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
-     * @param text value to be auto-filled.
-     */
-    public static FillableInputField forText(int id, String text) {
-        return new FillableInputField(id, text);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mId);
-        parcel.writeString(mValue);
-    }
-
-    public static final Parcelable.Creator<FillableInputField> CREATOR =
-            new Parcelable.Creator<FillableInputField>() {
-        @Override
-        public FillableInputField createFromParcel(Parcel source) {
-            return new FillableInputField(source);
-        }
-
-        @Override
-        public FillableInputField[] newArray(int size) {
-            return new FillableInputField[size];
-        }
-    };
-}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
similarity index 85%
rename from core/java/android/service/autofill/IAutoFillCallback.aidl
rename to core/java/android/service/autofill/IAutoFillAppCallback.aidl
index d6d4f39..629b1f0 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillAppCallback.aidl
@@ -18,10 +18,11 @@
 
 import java.util.List;
 
+import android.view.autofill.Dataset;
+
 /**
  * @hide
  */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
+oneway interface IAutoFillAppCallback {
+    void autoFill(in Dataset dataset);
 }
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index f1251c0..f8ae57b 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -24,6 +24,5 @@
  * {@hide}
  */
 oneway interface IAutoFillManagerService {
-
-    void requestAutoFill(IBinder activityToken, int userId, int flags);
+    void requestAutoFill(IBinder activityToken, int userId, in Bundle extras, int flags);
 }
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
similarity index 76%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/service/autofill/IAutoFillServerCallback.aidl
index d6d4f39..9d58c99 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
@@ -18,10 +18,14 @@
 
 import java.util.List;
 
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
+
 /**
  * @hide
  */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
+oneway interface IAutoFillServerCallback {
+    void showResponse(in FillResponse response);
     void showError(String message);
+    void highlightSavedFields(in AutoFillId[] ids);
 }
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index bb122e5..a1f22bf 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -18,14 +18,15 @@
 
 import android.app.assist.AssistStructure;
 import android.os.Bundle;
-import android.service.autofill.IAutoFillCallback;
+import android.service.autofill.IAutoFillServerCallback;
 import com.android.internal.os.IResultReceiver;
 
 /**
  * @hide
  */
-interface IAutoFillService {
-    oneway void onConnected();
-    oneway void onDisconnected();
-    IResultReceiver getAssistReceiver();
+oneway interface IAutoFillService {
+    void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback,
+                  in Bundle extras, int flags);
+    void onConnected();
+    void onDisconnected();
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 4dc7392..627d74c 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -20,9 +20,11 @@
 
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.autofill.AutoFillId;
 
 import com.android.internal.util.Preconditions;
 
@@ -34,41 +36,53 @@
 
     private static final String TAG = "SaveCallback";
 
-    private final IAutoFillCallback mCallback;
+    private final IAutoFillServerCallback mCallback;
+
+    private boolean mReplied = false;
 
     /** @hide */
-    SaveCallback(IBinder binder) {
-        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    SaveCallback(IAutoFillServerCallback callback) {
+        mCallback = callback;
     }
 
     /**
-     * Notifies the {@link Activity} that the save request succeeded.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
+     * was successfully fulfilled by the service.
      *
      * @param ids ids ({@link ViewNode#getAutoFillId()}) of the fields that were saved.
      *
-     * @throws RuntimeException if an error occurred while saving the data.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
-    public void onSuccess(int[] ids) {
+    public void onSuccess(AutoFillId[] ids) {
+        if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ((ids == null) ? "null" : ids.length));
+
         Preconditions.checkArgument(ids != null, "ids cannot be null");
+        checkNotRepliedYet();
 
         Preconditions.checkArgument(ids.length > 0, "ids cannot be empty");
 
-        if (DEBUG) Log.d(TAG, "onSuccess(): ids=" + ids.length);
-
-        // TODO(b/33197203): display which ids were saved
+        try {
+            mCallback.highlightSavedFields(ids);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
     }
 
     /**
-     * Notifies the {@link Activity} that the save request failed.
+     * Notifies the Android System that an
+     * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, android.os.CancellationSignal, SaveCallback)}
+     * could not be fulfilled by the service.
      *
-     * @param message error message to be displayed.
+     * @param message error message to be displayed to the user.
      *
-     * @throws RuntimeException if an error occurred while notifying the activity.
+     * @throws RuntimeException if an error occurred while calling the Android System.
      */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
         Preconditions.checkArgument(message != null, "message cannot be null");
+        checkNotRepliedYet();
 
         try {
             mCallback.showError(message.toString());
@@ -76,4 +90,10 @@
             e.rethrowAsRuntimeException();
         }
     }
+
+    // There can be only one!!
+    private void checkNotRepliedYet() {
+        Preconditions.checkState(!mReplied, "already replied");
+        mReplied = true;
+    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0b1dfa2..aedd0df 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -39,6 +39,7 @@
 import android.annotation.Size;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
+import android.app.Application.OnProvideAssistDataListener;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -103,6 +104,9 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.VirtualViewDelegate;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -4025,18 +4029,34 @@
 
 
     /**
-     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain
-     * PII (Personally Identifiable Information).
+     * Set when a request was made to decide if views in an {@link android.app.Activity} can be
+     * auto-filled by an {@link android.service.autofill.AutoFillService}.
+     *
+     * <p>Since this request is made without a explicit user consent, the resulting
+     * {@link android.app.assist.AssistStructure} should not contain any PII
+     * (Personally Identifiable Information).
+     *
+     * <p>Examples:
+     * <ul>
+     * <li>{@link android.widget.TextView} texts should only be included when they were set by
+     * static resources.
+     * <li>{@link android.webkit.WebView} virtual children should be restricted to a subset of
+     * input fields and tags (like {@code id}).
+     * </ul>
      */
-    // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc.
-    public static final int ASSIST_FLAG_SANITIZED_TEXT = 0x1;
+    // TODO(b/33197203) (b/34078930): improve documentation: mention all cases, show examples, etc.
+    // In particular, be more specific about webview restrictions
+    public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x1;
 
     /**
-     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should contain all
-     * type of data, even sensitive PII (Personally Identifiable Information) like passwords or
-     * credit card numbers.
+     * Set when the user explicitly asked a {@link android.service.autofill.AutoFillService} to save
+     * the value of the {@link View}s in an {@link android.app.Activity}.
+     *
+     * <p>The resulting {@link android.app.assist.AssistStructure} can contain any kind of PII
+     * (Personally Identifiable Information). For example, the text of password fields should be
+     * included since that's what's typically saved.
      */
-    public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2;
+    public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x2;
 
     /**
      * Set to true when drawing cache is enabled and cannot be created.
@@ -6873,35 +6893,32 @@
      * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
      * @param structure Fill in with structured view data.  The default implementation
      * fills in all data that can be inferred from the view itself.
-     *
-     * @deprecated As of API O sub-classes should override
-     * {@link #onProvideStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void onProvideStructure(ViewStructure structure) {
-        onProvideStructure(structure, 0);
+        onProvideStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
-     * Called when assist structure is being retrieved from a view as part of
-     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
-     * of an auto-fill request.
-     *
-     * <p>The default implementation fills in all data that can be inferred from the view itself.
+     * Called when assist structure is being retrieved from a view as part of an auto-fill request.
      *
      * <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.
      *
-     * @param structure Fill in with structured view data. The default implementation
+     * @param structure Fill in with structured view data.  The default implementation
      * fills in all data that can be inferred from the view itself.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void onProvideStructure(ViewStructure structure, int flags) {
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        onProvideStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
         final int id = mID;
         if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
                 && (id&0x0000ffff) != 0) {
@@ -6923,6 +6940,8 @@
             // The auto-fill 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());
+
+            structure.setAutoFillType(getAutoFillType());
         }
 
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
@@ -6973,40 +6992,33 @@
      * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
      * view's virtual accessibility nodes, if any.  You can override this for a more
      * optimal implementation providing this data.
-     *
-     * @deprecated As of API O, sub-classes should override
-     * {@link #onProvideVirtualStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void onProvideVirtualStructure(ViewStructure structure) {
-        onProvideVirtualStructure(structure, 0);
+        onProvideVirtualStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
-     * Called when assist structure is being retrieved from a view as part of
-     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} or as part
-     * of an auto-fill request to generate additional virtual structure under this view.
+     * Called when assist structure is being retrieved from a view as part of an auto-fill request
+     * to generate additional virtual structure under this view.
      *
      * <p>The defaullt implementation uses {@link #getAccessibilityNodeProvider()} to try to
-     * generate this from the view's virtual accessibility nodes, if any.  You can override this
+     * generate this from the view's virtual accessibility nodes, if any. You can override this
      * for a more optimal implementation providing this data.
      *
      * <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.
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
-        boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0;
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        onProvideVirtualStructureForAssistOrAutoFill(structure, flags);
+    }
 
-        if (sanitize) {
-            // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case.
-            return;
-        }
-
+    private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
@@ -7017,8 +7029,66 @@
         }
     }
 
+    /**
+     * Gets the {@link VirtualViewDelegate} responsible for auto-filling the virtual children of
+     * this view.
+     *
+     * <p>By default returns {@code null} but should be overridden when view provides a virtual
+     * hierachy on {@link OnProvideAssistDataListener} that takes flags used by the AutoFill
+     * Framework (such as {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE}).
+     */
+    @Nullable
+    public VirtualViewDelegate getAutoFillVirtualViewDelegate(
+            @SuppressWarnings("unused") VirtualViewDelegate.Callback callback) {
+        return null;
+    }
+
+    /**
+     * Automatically fills the content of this view with the {@code value}.
+     *
+     * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()} to
+     * support the AutoFill Framework.
+     *
+     * <p>Typically, it is implemented by:
+     *
+     * <ol>
+     * <li>Call the proper getter method on {@link AutoFillValue} to fetch the actual value.
+     * <li>Pass the actual value to the equivalent setter in the view.
+     * <ol>
+     *
+     * <p>For example, a text-field view would call:
+     *
+     * <pre class="prettyprint">
+     * CharSequence text = value.getTextValue();
+     * if (text != null) {
+     *     setText(text);
+     * }
+     * </pre>
+     */
+    public void autoFill(@SuppressWarnings("unused") AutoFillValue value) {
+    }
+
+    /**
+     * Describes the auto-fill type that should be used on callas to
+     * {@link #autoFill(AutoFillValue)} and
+     * {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     *
+     * <p>By default returns {@code null}, but views should override it (and
+     * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework.
+     */
+    @Nullable
+    public AutoFillType getAutoFillType() {
+        return null;
+    }
+
     private void populateVirtualStructure(ViewStructure structure,
             AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
+
+        final boolean sanitized = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
+
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
                 null, null, null);
         Rect rect = structure.getTempRect();
@@ -7056,7 +7126,10 @@
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
-        if (info.getText() != null || info.getError() != null) {
+        if (!sanitized && (info.getText() != null || info.getError() != null)) {
+            // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to
+            // just set sanitized values (like text coming from resource files), rather than not
+            // setting it at all.
             structure.setText(info.getText(), info.getTextSelectionStart(),
                     info.getTextSelectionEnd());
         }
@@ -7077,14 +7150,9 @@
      * Dispatch creation of {@link ViewStructure} down the hierarchy.  The default
      * implementation calls {@link #onProvideStructure} and
      * {@link #onProvideVirtualStructure}.
-     *
-     * @deprecated As of API O,  sub-classes should override
-     * {@link #dispatchProvideStructure(ViewStructure, int)} instead.
      */
-    // TODO(b/33197203): set proper API above
-    @Deprecated
     public void dispatchProvideStructure(ViewStructure structure) {
-        dispatchProvideStructure(structure, 0);
+        dispatchProvideStructureForAssistOrAutoFill(structure, 0);
     }
 
     /**
@@ -7093,22 +7161,33 @@
      * <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 calls {@link #onProvideStructure(ViewStructure, int)} and
-     * {@link #onProvideVirtualStructure(ViewStructure, int)}.
+     * <p>The default implementation calls {@link #onProvideAutoFillStructure(ViewStructure, int)}
+     * and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (see {@link #ASSIST_FLAG_SANITIZED_TEXT} and
-     * {@link #ASSIST_FLAG_NON_SANITIZED_TEXT} for more info).
+     * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
+     * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
      */
-    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+    public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+        dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
 
         boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
         if (!blocked) {
-            onProvideStructure(structure, flags);
-            onProvideVirtualStructure(structure, flags);
+            if (forAutoFill) {
+                onProvideAutoFillStructure(structure, flags);
+                onProvideAutoFillVirtualStructure(structure, flags);
+            } else {
+                onProvideStructure(structure);
+                onProvideVirtualStructure(structure);
+            }
         } else {
             structure.setClassName(getAccessibilityClassName().toString());
             structure.setAssistBlocked(true);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 56501ec..1f1af4b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3156,18 +3156,34 @@
     }
 
     /**
+     * Dispatch creation of {@link ViewStructure} down the hierarchy.  This implementation
+     * adds in all child views of the view group, in addition to calling the default View
+     * implementation.
+     */
+    @Override
+    public void dispatchProvideStructure(ViewStructure structure) {
+        super.dispatchProvideStructure(structure);
+        dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+    }
+
+    /**
      * {@inheritDoc}
      *
      * <p>This implementation adds in all child views of the view group, in addition to calling the
      * default {@link View} implementation.
      */
     @Override
-    public void dispatchProvideStructure(ViewStructure structure, int flags) {
-        super.dispatchProvideStructure(structure, flags);
+    public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.dispatchProvideAutoFillStructure(structure, flags);
+        dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+    }
 
+    private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         boolean forAutoFill = (flags
-                & (View.ASSIST_FLAG_SANITIZED_TEXT
-                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+                & (View.AUTO_FILL_FLAG_TYPE_FILL
+                        | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
 
         boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
 
@@ -3233,12 +3249,11 @@
                                 preorderedList, children, childIndex);
                         final ViewStructure cstructure = structure.newChild(i);
 
-                        // Must explicitly check which recursive method to call because child might
-                        // not be overriding the new, flags-based version
-                        if (flags == 0) {
-                            child.dispatchProvideStructure(cstructure);
+                        // Must explicitly check which recursive method to call.
+                        if (forAutoFill) {
+                            child.dispatchProvideAutoFillStructure(cstructure, flags);
                         } else {
-                            child.dispatchProvideStructure(cstructure, flags);
+                            child.dispatchProvideStructure(cstructure);
                         }
                     }
                     if (preorderedList != null) preorderedList.clear();
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index e9ff9d0..839e11c 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -19,6 +19,10 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
+import android.view.autofill.VirtualViewDelegate;
 
 /**
  * Container for storing additional per-view data generated by {@link View#onProvideStructure
@@ -258,6 +262,12 @@
     public abstract ViewStructure newChild(int index);
 
     /**
+     * Like {@link #newChild(int)}, but providing a {@code virtualId} to the child so it can be
+     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     */
+    public abstract ViewStructure newChild(int index, int virtualId);
+
+    /**
      * Like {@link #newChild}, but allows the caller to asynchronously populate the returned
      * child.  It can transfer the returned {@link ViewStructure} to another thread for it
      * to build its content (and children etc).  Once done, some thread must call
@@ -268,6 +278,17 @@
     public abstract ViewStructure asyncNewChild(int index);
 
     /**
+     * Like {@link #asyncNewChild(int)}, but providing a {@code virtualId} to the child so it can be
+     * auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+     */
+    public abstract ViewStructure asyncNewChild(int index, int virtualId);
+
+    /**
+     * Sets the {@link AutoFillType} that can be used to auto-fill this node.
+     */
+    public abstract void setAutoFillType(AutoFillType info);
+
+    /**
      * Call when done populating a {@link ViewStructure} returned by
      * {@link #asyncNewChild}.
      */
@@ -277,5 +298,8 @@
     public abstract Rect getTempRect();
 
     /** @hide */
-    public abstract void setAutoFillId(int autoFillId);
+    public abstract void setAutoFillId(int viewId);
+
+    /** @hide */
+    public abstract AutoFillId getAutoFillId();
 }
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillId.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillId.aidl
index d6d4f39..56f0338 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillId.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2017, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillId;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
new file mode 100644
index 0000000..b7b694d
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A unique identifier for an auto-fill node inside an {@link android.app.Activity}.
+ */
+public final class AutoFillId implements Parcelable {
+
+    private int mViewId;
+    private boolean mVirtual;
+    private int mVirtualId;
+
+    /** @hide */
+    public AutoFillId(int id) {
+        mVirtual = false;
+        mViewId = id;
+    }
+
+    /** @hide */
+    public AutoFillId(AutoFillId parent, int virtualChildId) {
+        mVirtual = true;
+        mViewId = parent.mViewId;
+        mVirtualId = virtualChildId;
+    }
+
+    /** @hide */
+    public int getViewId() {
+        return mViewId;
+    }
+
+    /** @hide */
+    public int getVirtualChildId() {
+        return mVirtualId;
+    }
+
+    /** @hide */
+    public boolean isVirtual() {
+        return mVirtual;
+    }
+
+    /////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mViewId;
+        result = prime * result + mVirtualId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final AutoFillId other = (AutoFillId) obj;
+        if (mViewId != other.mViewId) return false;
+        if (mVirtualId != other.mVirtualId) return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("FieldId [viewId=").append(mViewId);
+        if (mVirtual) {
+            builder.append(", virtualId=").append(mVirtualId);
+        }
+        return builder.append(']').toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mViewId);
+        parcel.writeInt(mVirtual ? 1 : 0);
+        parcel.writeInt(mVirtualId);
+    }
+
+    private AutoFillId(Parcel parcel) {
+        mViewId = parcel.readInt();
+        mVirtual = parcel.readInt() == 1;
+        mVirtualId = parcel.readInt();
+    }
+
+    public static final Parcelable.Creator<AutoFillId> CREATOR =
+            new Parcelable.Creator<AutoFillId>() {
+        @Override
+        public AutoFillId createFromParcel(Parcel source) {
+            return new AutoFillId(source);
+        }
+
+        @Override
+        public AutoFillId[] newArray(int size) {
+            return new AutoFillId[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillType.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillType.aidl
index d6d4f39..a63d7c5 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillType.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillType;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillType.java b/core/java/android/view/autofill/AutoFillType.java
new file mode 100644
index 0000000..017f7f8
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillType.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Defines the type of a object that can be used to auto-fill a {@link View} so the
+ * {@link android.service.autofill.AutoFillService} can use the proper {@link AutoFillValue} to
+ * fill it.
+ *
+ * <p>Some {@link AutoFillType}s can have an optional {@code sub-type}: the
+ * main {@code type} defines the view's UI control category (like a text field), while the optional
+ * {@code sub-type} define its semantics (like a postal address).
+ */
+public final class AutoFillType implements Parcelable {
+
+    // Cached instance for types that don't have subtype; it uses the "lazy initialization holder
+    // class idiom" (Effective Java, Item 71) to avoid memory utilization when auto-fill is not
+    // enabled.
+    private static class DefaultTypesHolder {
+        static final AutoFillType TOGGLE = new AutoFillType(TYPE_TOGGLE, 0);
+        static final AutoFillType LIST = new AutoFillType(TYPE_LIST, 0);
+    }
+
+    private static final int TYPE_TEXT = 1;
+    private static final int TYPE_TOGGLE = 2;
+    // TODO(b/33197203): make sure it works with Spinners and/or add a new type for them
+    // (since they're often used for credit card selection)
+    private static final int TYPE_LIST = 3;
+
+    // TODO(b/33197203): add others, like date picker? That would be trick, because they're set as:
+    // updateDate(int year, int month, int dayOfMonth)
+    // So, we would have to either use a long representing the Date.time(), or a custom long
+    // representing:
+    // year * 10000 + month * 100 + day
+    // Then a custom getDatePickerValue(Bundle) that returns an immutable object with these 3 fields
+
+    private final int mType;
+    private final int mSubType;
+
+    private AutoFillType(int type, int subType) {
+        mType = type;
+        mSubType = subType;
+    }
+
+    /**
+     * Checks if this is a type for a text field, which is filled by a {@link CharSequence}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forText(CharSequence)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getTextValue()}.
+     *
+     * <p>Sub-type for this type is the value defined by {@link TextView#getInputType()}.
+     */
+    public boolean isText() {
+        return mType == TYPE_TEXT;
+    }
+
+    /**
+     * Checks if this is a a type for a togglable field, which is filled by a {@code boolean}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forToggle(boolean)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getToggleValue()}.
+     *
+     * <p>This type has no sub-types.
+     */
+    public boolean isToggle() {
+        return mType == TYPE_TOGGLE;
+    }
+
+    /**
+     * Checks if this is a type for a selection list field, which is filled by a {@code integer}
+     * representing the element index inside the list (starting at {@code 0}.
+     *
+     * <p>{@link AutoFillValue} instances for auto-filling a {@link View} can be obtained through
+     * {@link AutoFillValue#forList(int)}, and the value of a bundle passed to auto-fill a
+     * {@link View} can be fetched through {@link AutoFillValue#getListValue()}.
+     *
+     * <p>This type has no sub-types.
+     */
+    public boolean isList() {
+        return mType == TYPE_LIST;
+    }
+
+
+    /**
+     * Gets the optional sub-type, representing the {@link View}'s semantic.
+     *
+     * @return {@code 0} if type does not support sub-types.
+     */
+    public int getSubType() {
+        return mSubType;
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "AutoFillType [type=" + mType + ", subType=" + mSubType + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mSubType;
+        result = prime * result + mType;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final AutoFillType other = (AutoFillType) obj;
+        if (mSubType != other.mSubType) return false;
+        if (mType != other.mType) return false;
+        return true;
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeInt(mSubType);
+    }
+
+    private AutoFillType(Parcel parcel) {
+        mType = parcel.readInt();
+        mSubType = parcel.readInt();
+    }
+
+    public static final Parcelable.Creator<AutoFillType> CREATOR =
+            new Parcelable.Creator<AutoFillType>() {
+        @Override
+        public AutoFillType createFromParcel(Parcel source) {
+            return new AutoFillType(source);
+        }
+
+        @Override
+        public AutoFillType[] newArray(int size) {
+            return new AutoFillType[size];
+        }
+    };
+
+    ////////////////////
+    // Factory methods //
+    ////////////////////
+
+    /**
+     * Creates a text field type, which is filled by a {@link CharSequence}.
+     *
+     * <p>See {@link #isText()} for more info.
+     */
+    public static AutoFillType forText(int inputType) {
+        return new AutoFillType(TYPE_TEXT, inputType);
+    }
+
+    /**
+     * Creates a type that can be toggled which is filled by a {@code boolean}.
+     *
+     * <p>See {@link #isToggle()} for more info.
+     */
+    public static AutoFillType forToggle() {
+        return DefaultTypesHolder.TOGGLE;
+    }
+
+    /**
+     * Creates a selection list, which is filled by a {@code integer} representing the element index
+     * inside the list (starting at {@code 0}.
+     *
+     * <p>See {@link #isList()} for more info.
+     */
+    public static AutoFillType forList() {
+        return DefaultTypesHolder.LIST;
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/AutoFillValue.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/AutoFillValue.aidl
index d6d4f39..3b284b9 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/AutoFillValue.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable AutoFillValue;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
new file mode 100644
index 0000000..c39f26b
--- /dev/null
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.View;
+
+/**
+ * Abstracts how a {@link View} can be auto-filled by an
+ * {@link android.service.autofill.AutoFillService}.
+ *
+ * <p>Each {@link AutoFillValue} has a {@code type} and optionally a {@code sub-type}: the
+ * {@code type} defines the view's UI control category (like a text field), while the optional
+ * {@code sub-type} define its semantics (like a postal address).
+ */
+public final class AutoFillValue implements Parcelable {
+
+    private final CharSequence mText;
+    private final int mListIndex;
+    private final boolean mToggle;
+
+    private AutoFillValue(CharSequence text, int listIndex, boolean toggle) {
+        mText = text;
+        mListIndex = listIndex;
+        mToggle = toggle;
+    }
+
+    /**
+     * Gets the value to auto-fill a text field.
+     *
+     * <p>See {@link AutoFillType#isText()} for more info.
+     */
+    public CharSequence getTextValue() {
+        return mText;
+    }
+
+    /**
+     * Gets the value to auto-fill a toggable field.
+     *
+     * <p>See {@link AutoFillType#isToggle()} for more info.
+     */
+    public boolean getToggleValue() {
+        return mToggle;
+    }
+
+    /**
+     * Gets the value to auto-fill a selection list field.
+     *
+     * <p>See {@link AutoFillType#isList()} for more info.
+     */
+    public int getListValue() {
+        return mListIndex;
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "AutoFillValue[text=" + mText + ", listIndex=" + mListIndex + ", toggle=" + mToggle
+                + "]";
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mText);
+        parcel.writeInt(mListIndex);
+        parcel.writeInt(mToggle ? 1 : 0);
+    }
+
+    private AutoFillValue(Parcel parcel) {
+        mText = parcel.readCharSequence();
+        mListIndex = parcel.readInt();
+        mToggle = parcel.readInt() == 1;
+    }
+
+    public static final Parcelable.Creator<AutoFillValue> CREATOR =
+            new Parcelable.Creator<AutoFillValue>() {
+        @Override
+        public AutoFillValue createFromParcel(Parcel source) {
+            return new AutoFillValue(source);
+        }
+
+        @Override
+        public AutoFillValue[] newArray(int size) {
+            return new AutoFillValue[size];
+        }
+    };
+
+    ////////////////////
+    // Factory methods //
+    ////////////////////
+
+    // TODO(b/33197203): add unit tests for each supported type (new / get should return same value)
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a text field.
+     *
+     * <p>See {@link AutoFillType#isText()} for more info.
+     */
+    public static AutoFillValue forText(CharSequence value) {
+        return new AutoFillValue(value, 0, false);
+    }
+
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a toggable field.
+     *
+     * <p>See {@link AutoFillType#isToggle()} for more info.
+     */
+    public static AutoFillValue forToggle(boolean value) {
+        return new AutoFillValue(null, 0, value);
+    }
+
+    /**
+     * Creates a new {@link AutoFillValue} to auto-fill a selection list field.
+     *
+     * <p>See {@link AutoFillType#isList()} for more info.
+     */
+    public static AutoFillValue forList(int value) {
+        return new AutoFillValue(null, value, false);
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/Dataset.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/Dataset.aidl
index d6d4f39..2a8e67c 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/Dataset.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable Dataset;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/Dataset.java b/core/java/android/view/autofill/Dataset.java
new file mode 100644
index 0000000..a73eb774
--- /dev/null
+++ b/core/java/android/view/autofill/Dataset.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.append;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.autofill.AutoFillService;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A set of data that can be used to auto-fill an {@link Activity}.
+ *
+ * <p>It contains:
+ *
+ * <ol>
+ *   <li>A name used to identify the dataset in the UI.
+ *   <li>A list of id/value pairs for the fields that can be auto-filled.
+ *   <li>An optional {@link Bundle} with extras (used only by the service creating it).
+ * </ol>
+ *
+ * See {@link FillResponse} for examples.
+ */
+public final class Dataset implements Parcelable {
+
+    private final CharSequence mName;
+    private final ArrayList<DatasetField> mFields;
+    private final Bundle mExtras;
+
+    private Dataset(Dataset.Builder builder) {
+        mName = builder.mName;
+        // TODO(b/33197203): make an immutable copy of mFields?
+        mFields = builder.mFields;
+        mExtras = builder.mExtras;
+    }
+
+    /** @hide */
+    public CharSequence getName() {
+        return mName;
+    }
+
+    /** @hide */
+    public List<DatasetField> getFields() {
+        return mFields;
+    }
+
+    /** @hide */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("Dataset [name=").append(mName)
+                .append(", fields=").append(mFields).append(", extras=");
+        append(builder, mExtras);
+        return builder.append(']').toString();
+    }
+
+    /**
+     * A builder for {@link Dataset} objects.
+     */
+    public static final class Builder {
+        private CharSequence mName;
+        private final ArrayList<DatasetField> mFields = new ArrayList<>();
+        private Bundle mExtras;
+
+        /**
+         * Creates a new builder.
+         *
+         * @param name Name used to identify the dataset in the UI. Typically it's the same value as
+         * the first field in the dataset (like username or email address) or an user-provided name
+         * (like "My Work Address").
+         */
+        public Builder(CharSequence name) {
+            mName = Preconditions.checkStringNotEmpty(name, "name cannot be empty or null");
+        }
+
+        /**
+         * Sets the value of a field.
+         *
+         * @param id id returned by {@link ViewNode#getAutoFillId()}.
+         * @param value value to be auto filled.
+         */
+        public Dataset.Builder setValue(AutoFillId id, AutoFillValue value) {
+            putField(new DatasetField(id, value));
+            return this;
+        }
+
+        /**
+         * Creates a new {@link Dataset} instance.
+         */
+        public Dataset build() {
+            return new Dataset(this);
+        }
+
+        /**
+         * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
+         * methods such as
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
+         * {@link AutoFillService#EXTRA_DATASET_EXTRAS} as the key.
+         *
+         * <p>It can be used to keep service state in between calls.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+            return this;
+        }
+
+        /**
+         * Emulates {@code Map.put()} by adding a new field to the list if its id is not the yet,
+         * or replacing the existing one.
+         */
+        private void putField(DatasetField field) {
+            // TODO(b/33197203): check if already exists and replaces it if so
+            mFields.add(field);
+        }
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mName);
+        parcel.writeList(mFields);
+        parcel.writeBundle(mExtras);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Dataset(Parcel parcel) {
+        mName = parcel.readCharSequence();
+        mFields = parcel.readArrayList(null);
+        mExtras = parcel.readBundle();
+    }
+
+    public static final Parcelable.Creator<Dataset> CREATOR = new Parcelable.Creator<Dataset>() {
+        @Override
+        public Dataset createFromParcel(Parcel source) {
+            return new Dataset(source);
+        }
+
+        @Override
+        public Dataset[] newArray(int size) {
+            return new Dataset[size];
+        }
+    };
+}
diff --git a/core/java/android/view/autofill/DatasetField.java b/core/java/android/view/autofill/DatasetField.java
new file mode 100644
index 0000000..c6b92ac
--- /dev/null
+++ b/core/java/android/view/autofill/DatasetField.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class DatasetField implements Parcelable {
+
+    private final AutoFillId mId;
+    private final AutoFillValue mValue;
+
+    DatasetField(AutoFillId id, AutoFillValue value) {
+        mId = id;
+        mValue = value;
+    }
+
+    public AutoFillId getId() {
+        return mId;
+    }
+
+    public AutoFillValue getValue() {
+        return mValue;
+    }
+
+    /////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////
+
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        return "DatasetField [id=" + mId + ", value=" + mValue + "]";
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mId, 0);
+        parcel.writeParcelable(mValue, 0);
+    }
+
+    private DatasetField(Parcel parcel) {
+        mId = parcel.readParcelable(null);
+        mValue = parcel.readParcelable(null);
+    }
+
+    public static final Parcelable.Creator<DatasetField> CREATOR =
+            new Parcelable.Creator<DatasetField>() {
+        @Override
+        public DatasetField createFromParcel(Parcel source) {
+            return new DatasetField(source);
+        }
+
+        @Override
+        public DatasetField[] newArray(int size) {
+            return new DatasetField[size];
+        }
+    };
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/FieldId.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/FieldId.aidl
index d6d4f39..35af645 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/FieldId.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable FieldId;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/view/autofill/FillResponse.aidl
similarity index 63%
copy from core/java/android/service/autofill/IAutoFillCallback.aidl
copy to core/java/android/view/autofill/FillResponse.aidl
index d6d4f39..b018f15 100644
--- a/core/java/android/service/autofill/IAutoFillCallback.aidl
+++ b/core/java/android/view/autofill/FillResponse.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
+/**
+ * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.view.autofill;
 
-import java.util.List;
-
-/**
- * @hide
- */
-oneway interface IAutoFillCallback {
-    void autofill(in List values);
-    void showError(String message);
-}
+parcelable FillResponse;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/FillResponse.java b/core/java/android/view/autofill/FillResponse.java
new file mode 100644
index 0000000..3a14767
--- /dev/null
+++ b/core/java/android/view/autofill/FillResponse.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import static android.view.autofill.Helper.DEBUG;
+import static android.view.autofill.Helper.append;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.autofill.AutoFillService;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Response for a
+ * {@link AutoFillService#onFillRequest(android.app.assist.AssistStructure, Bundle,
+ * android.os.CancellationSignal, android.service.autofill.FillCallback)}
+ * request.
+ *
+ * <p>The response typically contains one or more {@link Dataset}s, each representing a set of
+ * fields that can be auto-filled together. For example, for a login page with username/password
+ * where the user only have one account in the service, the response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("homer")
+ *          .setTextFieldValue(id1, "homer")
+ *          .setTextFieldValue(id2, "D'OH!")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>If the user had 2 accounts, each with its own user-provided names, the response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Homer's Account")
+ *          .setTextFieldValue(id1, "homer")
+ *          .setTextFieldValue(id2, "D'OH!")
+ *          .build())
+ *      .add(new Dataset.Builder("Bart's Account")
+ *          .setTextFieldValue(id1, "elbarto")
+ *          .setTextFieldValue(id2, "cowabonga")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>If the user does not have any data associated with this {@link Activity} but the service
+ * wants to offer the user the option to save the data that was entered, then the service could
+ * populate the response with {@code savableIds} instead of {@link Dataset}s:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .addSavableFields(id1, id2)
+ *      .build();
+ * </pre>
+ *
+ * <p>Similarly, there might be cases where the user data on the service is enough to populate some
+ * fields but not all, and the service would still be interested on saving the other fields. In this
+ * scenario, the service could populate the response with both {@link Dataset}s and
+ * {@code savableIds}:
+ *
+ * <pre class="prettyprint">
+ *   new FillResponse.Builder()
+ *       .add(new Dataset.Builder("Homer")
+ *          .setTextFieldValue(id1, "Homer")                  // first name
+ *          .setTextFieldValue(id2, "Simpson")                // last name
+ *          .setTextFieldValue(id3, "742 Evergreen Terrace")  // street
+ *          .setTextFieldValue(id4, "Springfield")            // city
+ *          .build())
+ *       .addSavableFields(id5, id6) // state and zipcode
+ *       .build();
+ *
+ * </pre>
+ *
+ * <p>Notice that the ids that are part of a dataset (ids 1 to 4, in this example) are automatically
+ * added to the {@code savableIds} list.
+ *
+ * <p>If the service has multiple {@link Dataset}s with multiple options for some fields on each
+ * dataset (for example, multiple accounts with both a home and work address), then it should
+ * "partition" the {@link Activity} in sections and populate the response with just a subset of the
+ * data that would fulfill the first section; then once the user fills the first section and taps
+ * a field from the next section, the Android system would issue another request for that section,
+ * and so on. For example, the first response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Homer")
+ *          .setTextFieldValue(id1, "Homer")
+ *          .setTextFieldValue(id2, "Simpson")
+ *          .build())
+ *      .add(new Dataset.Builder("Bart")
+ *          .setTextFieldValue(id1, "Bart")
+ *          .setTextFieldValue(id2, "Simpson")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>Then after the user picks the {@code Homer} dataset and taps the {@code Street} field to
+ * trigger another auto-fill request, the second response could be:
+ *
+ * <pre class="prettyprint">
+ *  new FillResponse.Builder()
+ *      .add(new Dataset.Builder("Home")
+ *          .setTextFieldValue(id3, "742 Evergreen Terrace")
+ *          .setTextFieldValue(id4, "Springfield")
+ *          .build())
+ *      .add(new Dataset.Builder("Work")
+ *          .setTextFieldValue(id3, "Springfield Nuclear Power Plant")
+ *          .setTextFieldValue(id4, "Springfield")
+ *          .build())
+ *      .build();
+ * </pre>
+ *
+ * <p>Finally, the service can use the {@link FillResponse.Builder#setExtras(Bundle)} and/or
+ * {@link Dataset.Builder#setExtras(Bundle)} methods to pass
+ * a {@link Bundle} with service-specific data use to identify this response on future calls (like
+ * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) - such bundle will be
+ * available as the {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} extra in
+ * that method's {@code extras} argument.
+ */
+public final class FillResponse implements Parcelable {
+
+    private final List<Dataset> mDatasets;
+    private final AutoFillId[] mSavableIds;
+    private final Bundle mExtras;
+
+    private FillResponse(Builder builder) {
+        // TODO(b/33197203): make it immutable?
+        mDatasets = builder.mDatasets;
+        final int size = builder.mSavableIds.size();
+        mSavableIds = new AutoFillId[size];
+        int i = 0;
+        for (AutoFillId id : builder.mSavableIds) {
+            mSavableIds[i++] = id;
+        }
+        mExtras = builder.mExtras;
+    }
+
+    /** @hide */
+    public List<Dataset> getDatasets() {
+        return mDatasets;
+    }
+
+    /** @hide */
+    public AutoFillId[] getSavableIds() {
+        return mSavableIds;
+    }
+
+    /** @hide */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    /**
+     * Builder for {@link FillResponse} objects.
+     */
+    public static final class Builder {
+        private final List<Dataset> mDatasets = new ArrayList<>();
+        private final Set<AutoFillId> mSavableIds = new HashSet<>();
+        private  Bundle mExtras;
+
+        /**
+         * Adds a new {@link Dataset} to this response.
+         *
+         * @throws IllegalArgumentException if a dataset with same {@code name} already exists.
+         */
+        public Builder addDataset(Dataset dataset) {
+            Preconditions.checkNotNull(dataset, "dataset cannot be null");
+            // TODO(b/33197203): check if name already exists
+            // TODO(b/33197203): check if authId already exists (and update javadoc)
+            mDatasets.add(dataset);
+            for (DatasetField field : dataset.getFields()) {
+                mSavableIds.add(field.getId());
+            }
+            return this;
+        }
+
+        /**
+         * Adds ids of additional fields that the service would be interested to save (through
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}) but were not
+         * indirectly set through {@link #addDataset(Dataset)}.
+         *
+         * <p>See {@link FillResponse} for examples.
+         */
+        public Builder addSavableFields(AutoFillId...ids) {
+            for (AutoFillId id : ids) {
+                mSavableIds.add(id);
+            }
+            return this;
+        }
+
+        /**
+         * Sets a {@link Bundle} that will be passed to subsequent calls to {@link AutoFillService}
+         * methods such as
+         * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+         * android.os.CancellationSignal, android.service.autofill.SaveCallback)}, using
+         * {@link AutoFillService#EXTRA_RESPONSE_EXTRAS} as the key.
+         *
+         * <p>It can be used when to keep service state in between calls.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = Objects.requireNonNull(extras, "extras cannot be null");
+            return this;
+        }
+
+        /**
+         * Builds a new {@link FillResponse} instance.
+         */
+        public FillResponse build() {
+            return new FillResponse(this);
+        }
+    }
+
+    /////////////////////////////////////
+    //  Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!DEBUG) return super.toString();
+
+        final StringBuilder builder = new StringBuilder("FillResponse: [datasets=")
+                .append(mDatasets).append(", savableIds=").append(Arrays.toString(mSavableIds))
+                .append(", extras=");
+        append(builder, mExtras);
+        return builder.append(']').toString();
+    }
+
+    /////////////////////////////////////
+    //  Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeList(mDatasets);
+        parcel.writeParcelableArray(mSavableIds, 0);
+        parcel.writeBundle(mExtras);
+    }
+
+    private FillResponse(Parcel parcel) {
+        mDatasets = new ArrayList<>();
+        parcel.readList(mDatasets, null);
+        mSavableIds = parcel.readParcelableArray(null, AutoFillId.class);
+        mExtras = parcel.readBundle();
+    }
+
+    public static final Parcelable.Creator<FillResponse> CREATOR =
+            new Parcelable.Creator<FillResponse>() {
+        @Override
+        public FillResponse createFromParcel(Parcel source) {
+            return new FillResponse(source);
+        }
+
+        @Override
+        public FillResponse[] newArray(int size) {
+            return new FillResponse[size];
+        }
+    };
+}
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
new file mode 100644
index 0000000..772710e
--- /dev/null
+++ b/core/java/android/view/autofill/Helper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.os.Bundle;
+
+import java.util.Set;
+
+/** @hide */
+public final class Helper {
+
+    // TODO(b/33197203): set to false when stable
+    static final boolean DEBUG = true;
+    static final String REDACTED = "[REDACTED]";
+
+    static void append(StringBuilder builder, Bundle bundle) {
+        if (bundle == null) {
+            builder.append("N/A");
+        } else if (!DEBUG) {
+            builder.append(REDACTED);
+        } else {
+            final Set<String> keySet = bundle.keySet();
+            builder.append("[bundle with ").append(keySet.size()).append(" extras:");
+            for (String key : keySet) {
+                builder.append(' ').append(key).append('=').append(bundle.get(key)).append(',');
+            }
+            builder.append(']');
+        }
+    }
+
+    private Helper() {
+        throw new UnsupportedOperationException("contains static members only");
+    }
+}
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
new file mode 100644
index 0000000..a19b4e5
--- /dev/null
+++ b/core/java/android/view/autofill/VirtualViewDelegate.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.autofill;
+
+import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
+
+/**
+ * This class is the contract a client should implement to enable support of a
+ * virtual view hierarchy rooted at a given view for auto-fill purposes.
+ *
+ * <p>The view hierarchy is typically created through the
+ * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)} call and client
+ * add virtual children by calling {@link ViewStructure#newChild(int, int)} or
+ * {@link ViewStructure#asyncNewChild(int, int)}, where the client provides the {@code virtualId}
+ * of the children - the same {@code virtualId} is used in the methods of this class.
+ *
+ * <p>Objects of this class are typically created by overriding
+ * {@link View#getAutoFillVirtualViewDelegate(Callback)} and saving the passed callback, which must
+ * be notified upon changes on the hierarchy.
+ *
+ * <p>The main use case of these API is to enable custom views that draws its content - such as
+ * {@link android.webkit.WebView} providers - to support the AutoFill Framework:
+ *
+ * <ol>
+ *   <li>Client populates the virtual hierarchy on
+ * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}
+ *   <li>Android System generates the proper {@link AutoFillId} - encapsulating the view and the
+ * virtual node ids - and pass it to the {@link android.service.autofill.AutoFillService}.
+ *   <li>The service uses the {@link AutoFillId} to populate the auto-fill {@link Dataset}s and pass
+ *   it back to the Android System.
+ *   <li>Android System uses the {@link AutoFillId} to find the proper custom view and calls
+ *   {@link #autoFill(int, AutoFillValue)} on that view passing the virtual id.
+ *   <li>This provider than finds the node in the hierarchy and auto-fills it.
+ * </ol>
+ *
+ */
+public abstract class VirtualViewDelegate {
+
+    // TODO(b/33197203): set to false once stable
+    private static final boolean DEBUG = true;
+
+    private static final String TAG = "VirtualViewDelegate";
+
+    /**
+     * Auto-fills a virtual view with the {@code value}.
+     *
+     * @param virtualId id identifying the virtual node inside the custom view.
+     * @param value value to be auto-filled.
+     */
+    public abstract void autoFill(int virtualId, AutoFillValue value);
+
+    /**
+     * Callback used to notify the AutoFill Framework of changes made on the view hierarchy while
+     * an {@link android.app.Activity} is being auto filled.
+     */
+    public abstract static class Callback {
+
+        /**
+         * Sent when the focus inside the hierarchy changed.
+         *
+         * <p>Typically callled twice - for the nodes that lost and gained focus.
+         *
+         * <p>This method should only be called when the change was not caused by the AutoFill
+         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
+         * but by external causes (for example, when the user changed the value through the view's
+         * UI).
+         *
+         * @param virtualId id of the node whose focus changed.
+         * @param hasFocus {@code true} when focus was gained, {@code false} when it was lost.
+         */
+        public void onFocusChanged(int virtualId, boolean hasFocus) {
+            if (DEBUG) Log.d(TAG, "onFocusChanged() for " + virtualId + ": " + hasFocus);
+        }
+
+        /**
+         * Sent when the value of a node was changed.
+         *
+         * <p>This method should only be called when the change was not caused by the AutoFill
+         * Framework itselft (i.e, through {@link VirtualViewDelegate#autoFill(int, AutoFillValue)},
+         * but by external causes (for example, when the user changed the value through the view's
+         * UI).
+         *
+         * @param virtualId id of the node whose value changed.
+         */
+        public void onValueChanged(int virtualId) {
+            if (DEBUG) Log.d(TAG, "onValueChanged() for" + virtualId);
+        }
+
+        /**
+         * Sent when nodes were removed (or had their ids changed) after the hierarchy has been
+         * committed to
+         * {@link View#onProvideAutoFillVirtualStructure(android.view.ViewStructure, int)}.
+         *
+         * <p>For example, when the view is rendering an {@code HTML} page, it should call this
+         * method when:
+         * <ul>
+         * <li>User navigated to another page and some (or all) nodes are gone.
+         * <li>The page's {@code DOM} was changed by {@code JavaScript} and some nodes moved (and
+         * are now identified by different ids).
+         * </ul>
+         *
+         * @param virtualIds id of the nodes that were removed.
+         */
+        public void onNodeRemoved(int... virtualIds) {
+            if (DEBUG) Log.d(TAG, "onNodeRemoved(): " + virtualIds);
+        }
+    }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8ecc42d..f98c099 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2515,8 +2515,8 @@
     }
 
     @Override
-    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
-        mProvider.getViewDelegate().onProvideVirtualStructure(structure, flags);
+    public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
+        mProvider.getViewDelegate().onProvideAutoFillVirtualStructure(structure, flags);
     }
 
     /** @hide */
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 7b95180..dd1b0d2 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -312,7 +312,7 @@
         public void onProvideVirtualStructure(android.view.ViewStructure structure);
 
         @SuppressWarnings("unused")
-        public default void onProvideVirtualStructure(android.view.ViewStructure structure,
+        public default void onProvideAutoFillVirtualStructure(android.view.ViewStructure structure,
                 int flags) {
         }
 
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 3213a34..718070d 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -34,6 +34,8 @@
 import android.view.ViewHierarchyEncoder;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 import com.android.internal.R;
 
@@ -52,6 +54,7 @@
  * </p>
  */
 public abstract class CompoundButton extends Button implements Checkable {
+
     private boolean mChecked;
     private boolean mBroadcasting;
 
@@ -111,6 +114,7 @@
         applyButtonTint();
     }
 
+    @Override
     public void toggle() {
         setChecked(!mChecked);
     }
@@ -130,6 +134,7 @@
     }
 
     @ViewDebug.ExportedProperty
+    @Override
     public boolean isChecked() {
         return mChecked;
     }
@@ -139,6 +144,7 @@
      *
      * @param checked true to check the button, false to uncheck it
      */
+    @Override
     public void setChecked(boolean checked) {
         if (mChecked != checked) {
             mChecked = checked;
@@ -514,12 +520,15 @@
                     + " checked=" + checked + "}";
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            @Override
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
             }
 
+            @Override
             public SavedState[] newArray(int size) {
                 return new SavedState[size];
             }
@@ -551,4 +560,16 @@
         super.encodeProperties(stream);
         stream.addProperty("checked", isChecked());
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        setChecked(value.getToggleValue());
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        return AutoFillType.forToggle();
+    }
 }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 043eb34..af5c842 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -24,8 +24,10 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.accessibility.AccessibilityNodeInfo;
-
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 /*
  * This is supposed to be a *very* thin veneer over TextView.
@@ -154,4 +156,26 @@
             info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
         }
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        final CharSequence text = value.getTextValue();
+
+        if (text == null) {
+            Log.w(VIEW_LOG_TAG, "EditText.autoFill(): no text on AutoFillValue");
+            return;
+        }
+        // TODO(b/33197203): once auto-fill is triggered by the IME, we'll need a new setText()
+        // or setAutoFillText() method on TextView to avoid re-triggering it.
+        setText(text);
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        // TODO(b/33197203): ideally it should return a constant, but value returned by
+        // getInputType() can change.
+        return AutoFillType.forText(getInputType());
+    }
 }
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 54b57631..45fd9e6 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -16,12 +16,16 @@
 
 package android.widget;
 
+
 import android.annotation.IdRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
 
 import com.android.internal.R;
 
@@ -51,6 +55,7 @@
  *
  */
 public class RadioGroup extends LinearLayout {
+
     // holds the checked id; the selection is empty by default
     private int mCheckedId = -1;
     // tracks children radio buttons checked state
@@ -335,6 +340,7 @@
     }
 
     private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
+        @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
             // prevents from infinite recursion
             if (mProtectFromCheckedChange) {
@@ -364,6 +370,7 @@
         /**
          * {@inheritDoc}
          */
+        @Override
         public void onChildViewAdded(View parent, View child) {
             if (parent == RadioGroup.this && child instanceof RadioButton) {
                 int id = child.getId();
@@ -384,6 +391,7 @@
         /**
          * {@inheritDoc}
          */
+        @Override
         public void onChildViewRemoved(View parent, View child) {
             if (parent == RadioGroup.this && child instanceof RadioButton) {
                 ((RadioButton) child).setOnCheckedChangeWidgetListener(null);
@@ -394,4 +402,22 @@
             }
         }
     }
+
+    // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+
+    @Override
+    public void autoFill(AutoFillValue value) {
+        final int index = value.getListValue();
+        final View child = getChildAt(index);
+        if (child == null) {
+            Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index);
+            return;
+        }
+        check(child.getId());
+    }
+
+    @Override
+    public AutoFillType getAutoFillType() {
+        return AutoFillType.forList();
+    }
 }
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index e629df9..a9257e6 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1404,10 +1404,19 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure, int flags) {
-        super.onProvideStructure(structure, flags);
+    public void onProvideStructure(ViewStructure structure) {
+        super.onProvideStructure(structure);
+        onProvideAutoFillStructureForAssistOrAutoFill(structure);
+    }
 
-        // NOTE: current there is no difference for Assist (flags=0) or AutoFill (flags>0);
+    @Override
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.onProvideAutoFillStructure(structure, flags);
+        onProvideAutoFillStructureForAssistOrAutoFill(structure);
+    }
+
+    // NOTE: currently there is no difference for Assist or AutoFill, so it doesn't take flags
+    private void onProvideAutoFillStructureForAssistOrAutoFill(ViewStructure structure) {
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = structure.getText();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1961bf6..9335811 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9391,11 +9391,23 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure, int flags) {
-        super.onProvideStructure(structure, flags);
+    public void onProvideStructure(ViewStructure structure) {
+        super.onProvideStructure(structure);
+        onProvideAutoStructureForAssistOrAutoFill(structure, 0);
+    }
 
+    @Override
+    public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+        super.onProvideAutoFillStructure(structure, flags);
+        onProvideAutoStructureForAssistOrAutoFill(structure, flags);
+    }
+
+    private void onProvideAutoStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+        // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
+        // this method should take a boolean with the type of request.
         final boolean forAutoFillSave =
-                (flags & ASSIST_FLAG_NON_SANITIZED_TEXT) != 0;
+                (flags & AUTO_FILL_FLAG_TYPE_SAVE) != 0;
+
         final boolean isPassword = hasPasswordTransformationMethod()
                 || isPasswordInputType(getInputType());
         if (!isPassword || forAutoFillSave) {