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/Android.mk b/Android.mk
index ef97549..8e8b95a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -262,8 +262,9 @@
 	core/java/android/os/storage/IObbActionListener.aidl \
 	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
-	core/java/android/service/autofill/IAutoFillCallback.aidl \
+	core/java/android/service/autofill/IAutoFillAppCallback.aidl \
 	core/java/android/service/autofill/IAutoFillManagerService.aidl \
+	core/java/android/service/autofill/IAutoFillServerCallback.aidl \
 	core/java/android/service/autofill/IAutoFillService.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index a4402bb..209260c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6368,7 +6368,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -35042,26 +35043,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -43147,6 +43141,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -43198,8 +43193,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43234,6 +43229,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -43470,10 +43467,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43680,8 +43677,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44311,6 +44308,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -44319,9 +44317,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -45542,6 +45542,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
diff --git a/api/system-current.txt b/api/system-current.txt
index 2ec5643..b919717 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6571,7 +6571,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -37905,26 +37906,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -46365,6 +46359,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -46416,8 +46411,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -46452,6 +46447,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -46688,10 +46685,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -46898,8 +46895,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -47529,6 +47526,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -47537,9 +47535,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -48763,6 +48763,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
@@ -50278,8 +50352,8 @@
     method public abstract boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onMeasure(int, int);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
+    method public default void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
-    method public default void onProvideVirtualStructure(android.view.ViewStructure, int);
     method public abstract void onScrollChanged(int, int, int, int);
     method public abstract void onSizeChanged(int, int, int, int);
     method public abstract void onStartTemporaryDetach();
diff --git a/api/test-current.txt b/api/test-current.txt
index 7e05b78..fef5ecf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6390,7 +6390,8 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public int getAutoFillId();
+    method public android.view.autofill.AutoFillId getAutoFillId();
+    method public android.view.autofill.AutoFillType getAutoFillType();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
     method public java.lang.String getClassName();
@@ -35160,26 +35161,19 @@
     method public void onDisconnected();
     method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.os.CancellationSignal, android.service.autofill.SaveCallback);
+    field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
+    field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
   public final class FillCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillCallback.FillData);
-  }
-
-  public static final class FillCallback.FillData {
-  }
-
-  public static class FillCallback.FillData.Builder {
-    ctor public FillCallback.FillData.Builder();
-    method public android.service.autofill.FillCallback.FillData build();
-    method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+    method public void onSuccess(android.view.autofill.FillResponse);
   }
 
   public final class SaveCallback {
     method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(int[]);
+    method public void onSuccess(android.view.autofill.AutoFillId[]);
   }
 
 }
@@ -43436,6 +43430,7 @@
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
     method public void announceForAccessibility(java.lang.CharSequence);
+    method public void autoFill(android.view.autofill.AutoFillValue);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
@@ -43487,8 +43482,8 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchProvideStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -43523,6 +43518,8 @@
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method public android.view.autofill.AutoFillType getAutoFillType();
+    method public android.view.autofill.VirtualViewDelegate getAutoFillVirtualViewDelegate(android.view.autofill.VirtualViewDelegate.Callback);
     method public android.graphics.drawable.Drawable getBackground();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
@@ -43760,10 +43757,10 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public deprecated void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideStructure(android.view.ViewStructure, int);
-    method public deprecated void onProvideVirtualStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillStructure(android.view.ViewStructure, int);
+    method public void onProvideAutoFillVirtualStructure(android.view.ViewStructure, int);
+    method public void onProvideStructure(android.view.ViewStructure);
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43970,8 +43967,8 @@
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
     field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
-    field public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 2; // 0x2
-    field public static final int ASSIST_FLAG_SANITIZED_TEXT = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_FILL = 1; // 0x1
+    field public static final int AUTO_FILL_FLAG_TYPE_SAVE = 2; // 0x2
     field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100
     field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40
     field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80
@@ -44605,6 +44602,7 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
+    method public abstract android.view.ViewStructure asyncNewChild(int, int);
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
     method public abstract java.lang.CharSequence getHint();
@@ -44613,9 +44611,11 @@
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
+    method public abstract android.view.ViewStructure newChild(int, int);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
+    method public abstract void setAutoFillType(android.view.autofill.AutoFillType);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
@@ -45838,6 +45838,80 @@
 
 }
 
+package android.view.autofill {
+
+  public final class AutoFillId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillId> CREATOR;
+  }
+
+  public final class AutoFillType implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillType forList();
+    method public static android.view.autofill.AutoFillType forText(int);
+    method public static android.view.autofill.AutoFillType forToggle();
+    method public int getSubType();
+    method public boolean isList();
+    method public boolean isText();
+    method public boolean isToggle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillType> CREATOR;
+  }
+
+  public final class AutoFillValue implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.view.autofill.AutoFillValue forList(int);
+    method public static android.view.autofill.AutoFillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutoFillValue forToggle(boolean);
+    method public int getListValue();
+    method public java.lang.CharSequence getTextValue();
+    method public boolean getToggleValue();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.AutoFillValue> CREATOR;
+  }
+
+  public final class Dataset implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.Dataset> CREATOR;
+  }
+
+  public static final class Dataset.Builder {
+    ctor public Dataset.Builder(java.lang.CharSequence);
+    method public android.view.autofill.Dataset build();
+    method public android.view.autofill.Dataset.Builder setExtras(android.os.Bundle);
+    method public android.view.autofill.Dataset.Builder setValue(android.view.autofill.AutoFillId, android.view.autofill.AutoFillValue);
+  }
+
+  public final class FillResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.autofill.FillResponse> CREATOR;
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.view.autofill.FillResponse.Builder addDataset(android.view.autofill.Dataset);
+    method public android.view.autofill.FillResponse.Builder addSavableFields(android.view.autofill.AutoFillId...);
+    method public android.view.autofill.FillResponse build();
+    method public android.view.autofill.FillResponse.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class VirtualViewDelegate {
+    ctor public VirtualViewDelegate();
+    method public abstract void autoFill(int, android.view.autofill.AutoFillValue);
+  }
+
+  public static abstract class VirtualViewDelegate.Callback {
+    ctor public VirtualViewDelegate.Callback();
+    method public void onFocusChanged(int, boolean);
+    method public void onNodeRemoved(int...);
+    method public void onValueChanged(int);
+  }
+
+}
+
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
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 54b5763..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) {
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index 6a16131..87eaf29 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,28 +18,23 @@
 
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
-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 static com.android.server.autofill.AutoFillUI.MSG_SHOW_ALL_NOTIFICATIONS;
+import static com.android.server.autofill.AutoFillUI.SHOW_ALL_NOTIFICATIONS_DELAY_MS;
 
 import android.Manifest;
 import android.app.AppGlobals;
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -48,7 +43,6 @@
 import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.service.autofill.IAutoFillManagerService;
 import android.text.TextUtils;
@@ -65,7 +59,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.List;
 
 /**
  * Entry point service for auto-fill management.
@@ -86,6 +79,7 @@
     protected static final int MSG_UNBIND = 1;
 
     private final AutoFillManagerServiceStub mServiceStub;
+    private final AutoFillUI mUi;
     private final Context mContext;
     private final ContentResolver mResolver;
 
@@ -99,7 +93,7 @@
                     removeStaleServiceForUser(msg.arg1);
                     return;
                 case MSG_SHOW_ALL_NOTIFICATIONS:
-                    showAllNotifications();
+                    mUi.showAllNotifications();
                     return;
                 default:
                     Slog.w(TAG, "Invalid message: " + msg);
@@ -129,6 +123,7 @@
         super(context);
 
         mContext = context;
+        mUi = new AutoFillUI(context, this, mLock);
         mResolver = context.getContentResolver();
         mServiceStub = new AutoFillManagerServiceStub();
     }
@@ -176,8 +171,9 @@
             Slog.w(TAG, "no service info for " + serviceComponent);
             return null;
         }
-        return new AutoFillManagerServiceImpl(this, mContext, mLock, FgThread.getHandler(), userId,
-                serviceInfo.applicationInfo.uid, serviceComponent, SERVICE_BINDING_LIFETIME_MS);
+        return new AutoFillManagerServiceImpl(this, mUi, mContext, mLock, FgThread.getHandler(),
+                userId, serviceInfo.applicationInfo.uid, serviceComponent,
+                SERVICE_BINDING_LIFETIME_MS);
     }
 
     /**
@@ -186,7 +182,8 @@
      * <p>First it tries to return the existing instance from the cache; if it's not cached, it
      * creates a new instance and caches it.
      */
-    private AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
+    // TODO(b/33197203): make private once AutoFillUi does not uses notifications
+    AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
         AutoFillManagerServiceImpl service = mServicesCache.get(userId);
         if (service != null) {
             if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId);
@@ -251,14 +248,14 @@
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
-        public void requestAutoFill(IBinder activityToken, int userId, int flags) {
+        public void requestAutoFill(IBinder activityToken, int userId, Bundle extras, int flags) {
             if (DEBUG) Slog.d(TAG, "requestAutoFill: flags=" + flags + ", userId=" + userId);
             mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
 
             synchronized (mLock) {
                 final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
                 if (service != null) {
-                    service.requestAutoFill(activityToken, flags);
+                    service.requestAutoFill(activityToken, extras, flags);
                 }
             }
         }
@@ -310,147 +307,8 @@
             if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
             synchronized (mLock) {
                 removeCachedServiceForUserLocked(userId);
-                final ComponentName serviceComponent = getProviderForUser(userId);
-                if (serviceComponent == null) {
-                    cancelNotificationLocked(userId);
-                } else {
-                    showNotification(serviceComponent, userId);
-                }
+                mUi.updateNotification(userId);
             }
         }
     }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // TODO: temporary code using a notification to request auto-fill.        //
-    // Will be removed once UX decide the right way to present it to the user //
-    ////////////////////////////////////////////////////////////////////////////
-
-    // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore
-    private static final String NOTIFICATION_AUTO_FILL_INTENT =
-            "com.android.internal.autofill.action.REQUEST_AUTOFILL";
-    private static final String EXTRA_USER_ID = "user_id";
-    private static final String EXTRA_FLAGS = "flags";
-
-    private static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
-    private static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
-
-    private BroadcastReceiver mNotificationReceiver;
-
-    final class NotificationReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
-            final int flags = intent.getIntExtra(EXTRA_FLAGS, 0);
-            if (DEBUG) Slog.d(TAG, "Requesting autofill by notification for user " + userId);
-            synchronized (mLock) {
-                final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service == null) {
-                    Slog.w(TAG, "no auto-fill service for user " + userId);
-                } else {
-                    service.requestAutoFill(null, flags);
-                }
-            }
-        }
-    }
-
-    private ComponentName getProviderForUser(int userId) {
-        ComponentName serviceComponent = null;
-        ServiceInfo serviceInfo = null;
-        final String componentName = Settings.Secure.getStringForUser(
-                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
-        if (!TextUtils.isEmpty(componentName)) {
-            try {
-                serviceComponent = ComponentName.unflattenFromString(componentName);
-                serviceInfo =
-                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
-            } catch (RuntimeException | RemoteException e) {
-                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
-                return null;
-            }
-        }
-
-        if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
-                + serviceComponent + ", info: " + serviceInfo);
-        if (serviceInfo == null) {
-            Slog.w(TAG, "no service info for " + serviceComponent);
-            return null;
-        }
-        return serviceComponent;
-    }
-
-    private void showAllNotifications() {
-        final UserManager userManager =
-                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        final List<UserInfo> allUsers = userManager.getUsers(true);
-
-        for (UserInfo user : allUsers) {
-            final ComponentName serviceComponent = getProviderForUser(user.id);
-            if (serviceComponent != null) {
-                showNotification(serviceComponent, user.id);
-            }
-        }
-    }
-
-    private void showNotification(ComponentName serviceComponent, int userId) {
-        if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
-
-        synchronized (mLock) {
-            if (mNotificationReceiver == null) {
-                mNotificationReceiver = new NotificationReceiver();
-                mContext.registerReceiver(mNotificationReceiver,
-                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
-            }
-        }
-
-        final Intent fillIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        fillIntent.putExtra(EXTRA_USER_ID, userId);
-        fillIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_SANITIZED_TEXT);
-        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
-                ASSIST_FLAG_SANITIZED_TEXT, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action fillAction = new Action.Builder(null, "FILL", fillPendingIntent).build();
-
-        final Intent saveIntent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
-        saveIntent.putExtra(EXTRA_USER_ID, userId);
-        saveIntent.putExtra(EXTRA_FLAGS, ASSIST_FLAG_NON_SANITIZED_TEXT);
-        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
-                ASSIST_FLAG_NON_SANITIZED_TEXT, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action saveAction = new Action.Builder(null, "SAVE", savePendingIntent).build();
-
-        final String packageName = serviceComponent.getPackageName();
-        String providerName = null;
-        final PackageManager pm = mContext.getPackageManager();
-        try {
-            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
-            if (info != null) {
-                providerName = pm.getApplicationLabel(info).toString();
-            }
-        } catch (Exception e) {
-            providerName = packageName;
-        }
-        final String title = "AutoFill actions";
-        final String subTitle = "Provider: " + providerName + "\n" + "User: " + userId;
-
-        final Notification notification = new Notification.Builder(mContext)
-                .setCategory(Notification.CATEGORY_SYSTEM)
-                .setOngoing(true)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                .setLocalOnly(true)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setContentTitle(title)
-                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .setActions(fillAction, saveAction)
-                .build();
-        NotificationManager.from(mContext).notify(userId, notification);
-    }
-
-    private void cancelNotificationLocked(int userId) {
-        if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
-        NotificationManager.from(mContext).cancel(userId);
-    }
-
-    /////////////////////////////////////////
-    // End of temporary notification code. //
-    /////////////////////////////////////////
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 82356c8..3de8a8b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -18,9 +18,12 @@
 
 import static com.android.server.autofill.AutoFillManagerService.DEBUG;
 
+import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IActivityManager;
+import android.app.assist.AssistStructure;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,6 +32,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.icu.text.DateFormat;
+import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,16 +41,24 @@
 import android.os.UserHandle;
 import android.service.autofill.AutoFillService;
 import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.IAutoFillAppCallback;
+import android.service.autofill.IAutoFillServerCallback;
 import android.service.autofill.IAutoFillService;
-import android.util.Log;
+import android.service.voice.VoiceInteractionSession;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.Dataset;
+import android.view.autofill.FillResponse;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -60,6 +72,9 @@
 
     private static final String TAG = "AutoFillManagerServiceImpl";
 
+    /** Used do assign ids to new ServerCallback instances. */
+    private static int sServerCallbackCounter = 0;
+
     private final int mUserId;
     private final int mUid;
     private final ComponentName mComponent;
@@ -68,6 +83,7 @@
     private final Object mLock;
     private final AutoFillServiceInfo mInfo;
     private final AutoFillManagerService mManagerService;
+    private final AutoFillUI mUi;
 
     // TODO(b/33197203): improve its usage
     // - set maximum number of entries
@@ -89,10 +105,19 @@
         }
     };
 
+    /**
+     * Cache of pending ServerCallbacks, keyed by {@link ServerCallback#id}.
+     *
+     * <p>They're kept until the AutoFillService handles a request, or an error occurs.
+     */
+    // TODO(b/33197203): need to make sure service is bound while callback is pending
+    @GuardedBy("mLock")
+    private static final SparseArray<ServerCallback> mServerCallbacks = new SparseArray<>();
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Log.d(TAG, "onServiceConnected():" + name);
+            if (DEBUG) Slog.d(TAG, "onServiceConnected():" + name);
             synchronized (mLock) {
                 mService = IAutoFillService.Stub.asInterface(service);
                 try {
@@ -102,17 +127,18 @@
                     return;
                 }
                 if (!mQueuedRequests.isEmpty()) {
-                    if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size());
+                    if (DEBUG) Slog.d(TAG, "queued requests:" + mQueuedRequests.size());
                 }
                 for (final QueuedRequest request: mQueuedRequests) {
-                    requestAutoFillLocked(request.activityToken, request.flags, false);
+                    requestAutoFillLocked(request.activityToken, request.extras, request.flags,
+                            false);
                 }
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Log.d(TAG, name + " disconnected");
+            if (DEBUG) Slog.d(TAG, name + " disconnected");
             synchronized (mLock) {
                 mService = null;
                 mManagerService.removeCachedServiceForUserLocked(mUserId);
@@ -120,6 +146,39 @@
         }
     };
 
+
+    /**
+     * Receiver of assist data from the app's {@link Activity}, uses the {@code resultData} as
+     * the {@link ServerCallback#id}.
+     */
+    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            if (DEBUG) Slog.d(TAG, "resultCode on mAssistReceiver: " + resultCode);
+
+            final IBinder appBinder = resultData.getBinder(AutoFillService.KEY_CALLBACK);
+            if (appBinder == null) {
+                Slog.w(TAG, "no app callback on mAssistReceiver's resultData");
+                return;
+            }
+            final AssistStructure structure = resultData
+                    .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
+            final Bundle data = resultData.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
+            final int flags = resultData.getInt(VoiceInteractionSession.KEY_FLAGS, 0);
+
+            final ServerCallback serverCallback;
+            synchronized (mLock) {
+                serverCallback = mServerCallbacks.get(resultCode);
+                if (serverCallback == null) {
+                    Slog.w(TAG, "no server callback for id " + resultCode);
+                    return;
+                }
+                serverCallback.appCallback = IAutoFillAppCallback.Stub.asInterface(appBinder);
+            }
+            mService.autoFill(structure, serverCallback, serverCallback.extras, flags);
+        }
+    };
+
     @GuardedBy("mLock")
     private IAutoFillService mService;
     private boolean mBound;
@@ -128,9 +187,11 @@
     // Estimated time when the service will be evicted from the cache.
     long mEstimateTimeOfDeath;
 
-    AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock,
-            Handler handler, int userId, int uid,ComponentName component, long ttl) {
+    AutoFillManagerServiceImpl(AutoFillManagerService managerService, AutoFillUI ui,
+            Context context, Object lock, Handler handler, int userId, int uid,
+            ComponentName component, long ttl) {
         mManagerService = managerService;
+        mUi = ui;
         mContext = context;
         mLock = lock;
         mUserId = userId;
@@ -180,7 +241,14 @@
         if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
     }
 
-    void requestAutoFill(IBinder activityToken, int flags) {
+    /**
+     * Asks service to auto-fill an activity.
+     *
+     * @param activityToken activity token
+     * @param extras bundle to be passed to the {@link AutoFillService} method.
+     * @param flags optional flags.
+     */
+    void requestAutoFill(@Nullable IBinder activityToken, @Nullable Bundle extras, int flags) {
         synchronized (mLock) {
             if (!mBound) {
                 Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
@@ -211,21 +279,26 @@
                 DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
         synchronized (mLock) {
             mRequestHistory.add(historyItem);
-            requestAutoFillLocked(activityToken, flags, true);
+            requestAutoFillLocked(activityToken, extras, flags, true);
         }
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, int flags, boolean queueIfNecessary) {
+    private void requestAutoFillLocked(IBinder activityToken, @Nullable Bundle extras, int flags,
+            boolean queueIfNecessary) {
         if (mService == null) {
             if (!queueIfNecessary) {
                 Slog.w(TAG, "requestAutoFillLocked(): service is null");
                 return;
             }
             if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it");
-            mQueuedRequests.add(new QueuedRequest(activityToken, flags));
+            mQueuedRequests.add(new QueuedRequest(activityToken, extras, flags));
             return;
         }
 
+        final int callbackId = ++sServerCallbackCounter;
+        final ServerCallback serverCallback = new ServerCallback(callbackId, extras);
+        mServerCallbacks.put(callbackId, serverCallback);
+
         /*
          * TODO(b/33197203): apply security checks below:
          * - checks if disabled by secure settings / device policy
@@ -235,8 +308,7 @@
          */
         try {
             // TODO(b/33197203): add MetricsLogger call
-            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken,
-                    flags)) {
+            if (!mAm.requestAutoFillData(mAssistReceiver, null, callbackId, activityToken, flags)) {
                 // TODO(b/33197203): might need a way to warn user (perhaps a new method on
                 // AutoFillService).
                 Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
@@ -251,7 +323,7 @@
 
         // Sanity check.
         if (mService == null) {
-            Log.w(TAG, "service already null on shutdown");
+            Slog.w(TAG, "service already null on shutdown");
             return;
         }
         try {
@@ -273,6 +345,44 @@
         }
     }
 
+    /**
+     * Called by {@link AutoFillUI} to fill an activity after the user selected a dataset.
+     */
+    void autoFillApp(int callbackId, Dataset dataset) {
+        // TODO(b/33197203): add MetricsLogger call
+
+        if (dataset == null) {
+            Slog.w(TAG, "autoFillApp(): no dataset for callback id " + callbackId);
+            return;
+        }
+
+        final ServerCallback serverCallback;
+        synchronized (mLock) {
+            serverCallback = mServerCallbacks.get(callbackId);
+            if (serverCallback == null) {
+                Slog.w(TAG, "autoFillApp(): no server callback with id " + callbackId);
+                return;
+            }
+            if (serverCallback.appCallback == null) {
+                Slog.w(TAG, "autoFillApp(): no app callback for server callback " + callbackId);
+                return;
+            }
+            // TODO(b/33197203): use a handler?
+            try {
+                if (DEBUG) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+                serverCallback.appCallback.autoFill(dataset);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Error auto-filling activity: " + e);
+            }
+            removeServerCallbackLocked(callbackId);
+        }
+    }
+
+    void removeServerCallbackLocked(int id) {
+        if (DEBUG) Slog.d(TAG, "Removing " + id + " from server callbacks");
+        mServerCallbacks.remove(id);
+    }
+
     void dumpLocked(String prefix, PrintWriter pw) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -284,6 +394,8 @@
             return;
         }
 
+        final String prefix2 = prefix + "  ";
+
         pw.print(prefix); pw.print("mUserId="); pw.println(mUserId);
         pw.print(prefix); pw.print("mUid="); pw.println(mUid);
         pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
@@ -303,7 +415,6 @@
             pw.print(prefix); pw.println("No history");
         } else {
             pw.print(prefix); pw.println("History:");
-            final String prefix2 = prefix + prefix;
             for (int i = 0; i < mRequestHistory.size(); i++) {
                 pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mRequestHistory.get(i));
             }
@@ -312,11 +423,28 @@
             pw.print(prefix); pw.println("No queued requests");
         } else {
             pw.print(prefix); pw.println("Queued requests:");
-            final String prefix2 = prefix + prefix;
             for (int i = 0; i < mQueuedRequests.size(); i++) {
                 pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i));
             }
         }
+
+        pw.print(prefix); pw.print("sServerCallbackCounter="); pw.println(sServerCallbackCounter);
+        final int size = mServerCallbacks.size();
+        if (size == 0) {
+            pw.print(prefix); pw.println("No server callbacks");
+        } else {
+            pw.print(prefix); pw.print(size); pw.println(" server callbacks:");
+            for (int i = 0; i < size; i++) {
+                pw.print(prefix2); pw.print(mServerCallbacks.keyAt(i));
+                final ServerCallback callback = mServerCallbacks.valueAt(i);
+                if (callback.appCallback == null) {
+                    pw.println("(no appCallback)");
+                } else {
+                    pw.print(" (app callback: "); pw.print(callback.appCallback) ; pw.println(")");
+                }
+            }
+            pw.println();
+        }
     }
 
     @Override
@@ -327,10 +455,12 @@
 
     private static final class QueuedRequest {
         final IBinder activityToken;
+        final Bundle extras;
         final int flags;
 
-        QueuedRequest(IBinder activityToken, int flags) {
+        QueuedRequest(IBinder activityToken, Bundle extras, int flags) {
             this.activityToken = activityToken;
+            this.extras = extras;
             this.flags = flags;
         }
 
@@ -339,4 +469,54 @@
             return "flags: " + flags + " token: " + activityToken;
         }
     }
+
+    /**
+     * A bridge between the {@link AutoFillService} implementation and the activity being
+     * auto-filled (represented through the {@link IAutoFillAppCallback}).
+     */
+    private final class ServerCallback extends IAutoFillServerCallback.Stub {
+
+        private final int id;
+        private final Bundle extras;
+        private IAutoFillAppCallback appCallback;
+
+        private ServerCallback(int id, Bundle extras) {
+            this.id = id;
+            this.extras = extras;
+        }
+
+        @Override
+        public void showResponse(FillResponse response) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showResponse(): " + response);
+
+            mUi.showOptions(mUserId, id, response);
+        }
+
+        @Override
+        public void showError(String message) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showError(): " + message);
+
+            mUi.showError(message);
+
+            removeSelf();
+        }
+
+        @Override
+        public void highlightSavedFields(AutoFillId[] ids) {
+            // TODO(b/33197203): add MetricsLogger call
+            if (DEBUG) Slog.d(TAG, "showSaved(): " + Arrays.toString(ids));
+
+            mUi.highlightSavedFields(ids);
+
+            removeSelf();
+        }
+
+        private void removeSelf() {
+            synchronized (mLock) {
+                removeServerCallbackLocked(id);
+            }
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index aa3503b..26f2451 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -16,10 +16,11 @@
 
 package com.android.server.autofill;
 
-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.app.ActivityManager;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -44,9 +45,9 @@
         try {
             switch (cmd) {
                 case "fill":
-                    return requestAutoFill(ASSIST_FLAG_SANITIZED_TEXT);
+                    return requestAutoFill(AUTO_FILL_FLAG_TYPE_FILL);
                 case "save":
-                    return requestAutoFill(ASSIST_FLAG_NON_SANITIZED_TEXT);
+                    return requestAutoFill(AUTO_FILL_FLAG_TYPE_SAVE);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -73,7 +74,7 @@
 
     private int requestAutoFill(int flags) throws RemoteException {
         final int userId = getUserIdFromArgs();
-        mService.requestAutoFill(null, userId, flags);
+        mService.requestAutoFill(null, userId, null, flags);
         return 0;
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
new file mode 100644
index 0000000..08e81d3
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillUI.java
@@ -0,0 +1,471 @@
+/*
+ * 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 com.android.server.autofill;
+
+import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
+import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
+
+import static com.android.server.autofill.AutoFillManagerService.DEBUG;
+
+import android.app.Activity;
+import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.Notification.Action;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.autofill.AutoFillService;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.autofill.Dataset;
+import android.view.autofill.AutoFillId;
+import android.view.autofill.FillResponse;
+import android.widget.Toast;
+
+import com.android.server.UiThread;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Handles all auto-fill related UI tasks.
+ */
+// TODO(b/33197203): document exactly what once the auto-fill bar is implemented
+final class AutoFillUI {
+
+    private static final String TAG = "AutoFillUI";
+
+    private final Context mContext;
+
+    AutoFillUI(Context context, AutoFillManagerService service, Object lock) {
+        mContext = context;
+        mResolver = context.getContentResolver();
+        mService = service;
+        mLock = lock;
+    }
+
+    /**
+     * Displays an error message to the user.
+     */
+    void showError(String message) {
+        // TODO(b/33197203): proper implementation
+        UiThread.getHandler().runWithScissors(() -> {
+            Toast.makeText(mContext, "AutoFill error: " + message, Toast.LENGTH_LONG).show();
+        }, 0);
+    }
+
+    /**
+     * Highlights in the {@link Activity} the fields saved by the service.
+     */
+    void highlightSavedFields(AutoFillId[] ids) {
+        // TODO(b/33197203): proper implementation (must be handled by activity)
+        UiThread.getHandler().runWithScissors(() -> {
+            Toast.makeText(mContext, "AutoFill: service saved ids " + Arrays.toString(ids),
+                    Toast.LENGTH_LONG).show();
+        }, 0);
+    }
+
+    /**
+     * Shows the options from a {@link FillResponse} so the user can pick up the proper
+     * {@link Dataset} (when the response has one).
+     */
+    void showOptions(int userId, int callbackId, FillResponse response) {
+        // TODO(b/33197203): proper implementation
+        // TODO(b/33197203): make sure if removes the callback from cache
+        showOptionsNotification(userId, callbackId, response);
+    }
+
+    /////////////////////////////////////////////////////////////////////////////////
+    // TODO(b/33197203): temporary code using a notification to request auto-fill. //
+    // Will be removed once UX decide the right way to present it to the user.     //
+    /////////////////////////////////////////////////////////////////////////////////
+
+    // TODO(b/33197203): remove from frameworks/base/core/res/AndroidManifest.xml once not used
+    private static final String NOTIFICATION_AUTO_FILL_INTENT =
+            "com.android.internal.autofill.action.REQUEST_AUTOFILL";
+
+    // Extras used in the notification intents
+    private static final String EXTRA_USER_ID = "user_id";
+    private static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
+    private static final String EXTRA_CALLBACK_ID = "callback_id";
+    private static final String EXTRA_FILL_RESPONSE = "fill_response";
+    private static final String EXTRA_DATASET = "dataset";
+
+    private static final String TYPE_EMULATE = "emulate";
+    private static final String TYPE_OPTIONS = "options";
+    private static final String TYPE_DELETE_CALLBACK = "delete_callback";
+    private static final String TYPE_PICK_DATASET = "pick_dataset";
+    private static final String TYPE_SAVE = "save";
+
+    static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
+    static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
+
+    private BroadcastReceiver mNotificationReceiver;
+    private final ContentResolver mResolver;
+    private final AutoFillManagerService mService;
+    private final Object mLock;
+
+    // Hack used to generate unique pending intents
+    static int sResultCode = 0;
+
+    final class NotificationReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
+
+            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
+            if (service == null) {
+                Slog.w(TAG, "no auto-fill service for user " + userId);
+                return;
+            }
+
+            final int callbackId = intent.getIntExtra(EXTRA_CALLBACK_ID, -1);
+            final String type = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
+            if (type == null) {
+                Slog.wtf(TAG, "No extra " + EXTRA_NOTIFICATION_TYPE + " on intent " + intent);
+                return;
+            }
+            final FillResponse fillData = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
+            final Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET);
+            final Bundle datasetArgs = dataset == null ? null : dataset.getExtras();
+            final Bundle fillDataArgs = fillData == null ? null : fillData.getExtras();
+
+            // Bundle sent on AutoFillService methods - only set if service provided a bundle
+            final Bundle extras = (datasetArgs == null && fillDataArgs == null)
+                    ? null : new Bundle();
+
+            if (DEBUG) Slog.d(TAG, "Notification received: type=" + type + ", userId=" + userId
+                    + ", callbackId=" + callbackId);
+            synchronized (mLock) {
+                switch (type) {
+                    case TYPE_EMULATE:
+                        service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_FILL);
+                        break;
+                    case TYPE_SAVE:
+                        if (datasetArgs != null) {
+                            if (DEBUG) Log.d(TAG, "filldata args on save notificataion: " +
+                                    bundleToString(fillDataArgs));
+                            extras.putBundle(AutoFillService.EXTRA_RESPONSE_EXTRAS, fillDataArgs);
+                        }
+                        if (dataset != null) {
+                            if (DEBUG) Log.d(TAG, "dataset args on save notificataion: " +
+                                    bundleToString(datasetArgs));
+                            extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
+                        }
+                        service.requestAutoFill(null, extras, AUTO_FILL_FLAG_TYPE_SAVE);
+                        break;
+                    case TYPE_DELETE_CALLBACK:
+                        service.removeServerCallbackLocked(callbackId);
+                        break;
+                    case TYPE_PICK_DATASET:
+                        service.autoFillApp(callbackId, dataset);
+                        // Must cancel notification because it might be comming from action
+                        if (DEBUG) Log.d(TAG, "Cancelling notification");
+                        NotificationManager.from(mContext).cancel(TYPE_OPTIONS, userId);
+
+                        if (datasetArgs != null) {
+                            if (DEBUG) Log.d(TAG, "adding dataset's extra_data on save intent: "
+                                    + bundleToString(datasetArgs));
+                            extras.putBundle(AutoFillService.EXTRA_DATASET_EXTRAS, datasetArgs);
+                        }
+
+                        // Also show notification with option to save the data
+                        showSaveNotification(userId, fillData, dataset);
+                        break;
+                    default: {
+                        Slog.w(TAG, "Unknown notification type: " + type);
+                    }
+                }
+            }
+        }
+    }
+
+    private ComponentName getProviderForUser(int userId) {
+        ComponentName serviceComponent = null;
+        ServiceInfo serviceInfo = null;
+        final String componentName = Settings.Secure.getStringForUser(
+                mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+        if (!TextUtils.isEmpty(componentName)) {
+            try {
+                serviceComponent = ComponentName.unflattenFromString(componentName);
+                serviceInfo =
+                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
+            } catch (RuntimeException | RemoteException e) {
+                Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+                return null;
+            }
+        }
+
+        if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
+                + serviceComponent + ", info: " + serviceInfo);
+        if (serviceInfo == null) {
+            Slog.w(TAG, "no service info for " + serviceComponent);
+            return null;
+        }
+        return serviceComponent;
+    }
+
+    void showAllNotifications() {
+        final UserManager userManager =
+                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        final List<UserInfo> allUsers = userManager.getUsers(true);
+
+        for (UserInfo user : allUsers) {
+            final ComponentName serviceComponent = getProviderForUser(user.id);
+            if (serviceComponent != null) {
+                showMainNotification(serviceComponent, user.id);
+            }
+        }
+    }
+
+    void updateNotification(int userId) {
+        final ComponentName serviceComponent = getProviderForUser(userId);
+        if (serviceComponent == null) {
+            cancelMainNotification(userId);
+        } else {
+            showMainNotification(serviceComponent, userId);
+        }
+    }
+
+    private static Intent newNotificationIntent(int userId, String type) {
+        final Intent intent = new Intent(NOTIFICATION_AUTO_FILL_INTENT);
+        intent.putExtra(EXTRA_USER_ID, userId);
+        intent.putExtra(EXTRA_NOTIFICATION_TYPE, type);
+        return intent;
+    }
+
+    private PendingIntent newPickDatasetPI(int userId, int callbackId, FillResponse response,
+            Dataset dataset) {
+        final int resultCode = ++ sResultCode;
+        if (DEBUG) Log.d(TAG, "newPickDatasetPI: userId=" + userId + ", callback=" + callbackId
+                + ", resultCode=" + resultCode);
+
+        final Intent intent = newNotificationIntent(userId, TYPE_PICK_DATASET);
+        intent.putExtra(EXTRA_CALLBACK_ID, callbackId);
+        intent.putExtra(EXTRA_FILL_RESPONSE, response);
+        intent.putExtra(EXTRA_DATASET, dataset);
+        return PendingIntent.getBroadcast(mContext, resultCode, intent,
+                PendingIntent.FLAG_ONE_SHOT);
+    }
+
+    private static String bundleToString(Bundle bundle) {
+        if (bundle == null) {
+            return "null";
+        }
+        final Set<String> keySet = bundle.keySet();
+        final StringBuilder builder = new StringBuilder("[Bundle with ").append(keySet.size())
+                .append(" keys:");
+        for (String key : keySet) {
+            final Object value = bundle.get(key);
+            builder.append(' ').append(key).append('=');
+            builder.append((value instanceof Object[])
+                    ? Arrays.toString((Objects[]) value) : value);
+        }
+        return builder.append(']').toString();
+    }
+
+    /**
+     * Shows a permanent notification that triggers the auto-fill workflow for the given user.
+     *
+     * <p>It emulates calling the auto-fill service when the IME is shown.
+     */
+    private void showMainNotification(ComponentName serviceComponent, int userId) {
+        if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
+
+        synchronized (mLock) {
+            if (mNotificationReceiver == null) {
+                mNotificationReceiver = new NotificationReceiver();
+                mContext.registerReceiver(mNotificationReceiver,
+                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
+            }
+        }
+
+        final Intent fillIntent = newNotificationIntent(userId, TYPE_EMULATE);
+        final PendingIntent fillPendingIntent = PendingIntent.getBroadcast(mContext,
+                -1, fillIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        final String packageName = serviceComponent.getPackageName();
+        String providerName = null;
+        final PackageManager pm = mContext.getPackageManager();
+        try {
+            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
+            if (info != null) {
+                providerName = pm.getApplicationLabel(info).toString();
+            }
+        } catch (Exception e) {
+            providerName = packageName;
+        }
+        final String title = "AutoFill IME Emulation";
+        final String subTitle = "Tap notification to start auto-fill workflow (by '" + providerName
+                + "' on top activity on user " + userId + ".\n"
+                + "Once provider replies, a new notification will show your options.";
+
+        final Notification notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setOngoing(true)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
+                .setContentIntent(fillPendingIntent)
+                .build();
+        NotificationManager.from(mContext).notify(TYPE_EMULATE, userId, notification);
+    }
+
+    /**
+     * Cancels the permament notification created by
+     * {@link #showMainNotification(ComponentName, int)}.
+     */
+    private void cancelMainNotification(int userId) {
+        if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
+        NotificationManager.from(mContext).cancel(TYPE_EMULATE, userId);
+    }
+
+    /**
+     * Shows a notification with the results of an auto-fill request, using notications actions
+     * to emulate the auto-fill bar buttons displaying the dataset names.
+     */
+    private void showOptionsNotification(int userId, int callbackId, FillResponse response) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            showOptionsNotificationAsSystem(userId, callbackId, response);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private void showOptionsNotificationAsSystem(int userId, int callbackId,
+            FillResponse response) {
+        // Make sure server callback is removed from cache if user cancels the notification.
+        final Intent deleteIntent = newNotificationIntent(userId, TYPE_DELETE_CALLBACK);
+        deleteIntent.putExtra(EXTRA_CALLBACK_ID, callbackId);
+        final PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext,
+                ++sResultCode, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
+
+        final String title = "AutoFill Options";
+
+        final Notification.Builder notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setOngoing(false)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setDeleteIntent(deletePendingIntent)
+                .setContentTitle(title);
+
+        boolean autoCancel = true;
+        final String subTitle;
+        final List<Dataset> datasets;
+        final AutoFillId[] savableIds;
+        if (response != null) {
+            datasets = response.getDatasets();
+            savableIds = response.getSavableIds();
+        } else {
+            datasets = null;
+            savableIds = null;
+        }
+        boolean showSave = false;
+        if (datasets == null ) {
+            subTitle = "No options to auto-fill this activity.";
+        } else if (datasets.isEmpty()) {
+            if (savableIds.length == 0) {
+                subTitle = "No options to auto-fill this activity.";
+            } else {
+                subTitle = "No options to auto-fill this activity, but provider can save ids:\n"
+                        + Arrays.toString(savableIds);
+                showSave = true;
+            }
+        } else {
+            final AutoFillManagerServiceImpl service = mService.getServiceForUserLocked(userId);
+            if (service == null) {
+                subTitle = "No auto-fill service for user " + userId;
+                Slog.w(TAG, subTitle);
+            } else {
+                autoCancel = false;
+                final int size = datasets.size();
+                subTitle = "There are " + size + " option(s).\n"
+                        + "Use the notification action(s) to select the proper one.";
+                for (Dataset dataset : datasets) {
+                    final CharSequence name = dataset.getName();
+                    final PendingIntent pi = newPickDatasetPI(userId, callbackId, response, dataset);
+                    notification.addAction(new Action.Builder(null, name, pi).build());
+                }
+            }
+        }
+
+        notification.setAutoCancel(autoCancel);
+        notification.setStyle(new Notification.BigTextStyle().bigText(subTitle));
+
+        NotificationManager.from(mContext).notify(TYPE_OPTIONS, userId, notification.build());
+
+        if (showSave) {
+            showSaveNotification(userId, response, null);
+        }
+    }
+
+    private void showSaveNotification(int userId, FillResponse response, Dataset dataset) {
+        final Intent saveIntent = newNotificationIntent(userId, TYPE_SAVE);
+        saveIntent.putExtra(EXTRA_FILL_RESPONSE, response);
+        if (dataset != null) {
+            saveIntent.putExtra(EXTRA_DATASET, dataset);
+        }
+        final PendingIntent savePendingIntent = PendingIntent.getBroadcast(mContext,
+                ++sResultCode, saveIntent, PendingIntent.FLAG_ONE_SHOT);
+
+        final String title = "AutoFill Save";
+        final String subTitle = "Tap notification to ask provider to save fields: \n"
+                + Arrays.toString(response.getSavableIds());
+
+        final Notification notification = new Notification.Builder(mContext)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setAutoCancel(true)
+                .setOngoing(false)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentIntent(savePendingIntent)
+                .setStyle(new Notification.BigTextStyle().bigText(subTitle))
+                .build();
+        NotificationManager.from(mContext).notify(TYPE_SAVE, userId, notification);
+    }
+
+    /////////////////////////////////////////
+    // End of temporary notification code. //
+    /////////////////////////////////////////
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 49c4995..3b850e4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -690,19 +690,21 @@
         public AssistStructure structure = null;
         public AssistContent content = null;
         public Bundle receiverExtras;
+        public int resultCode;
         public int flags;
 
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _flags,
-                int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _resultCode,
+                int _userHandle, int _flags) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
             receiverExtras = _receiverExtras;
-            flags = _flags;
+            resultCode = _resultCode;
             userHandle = _userHandle;
+            flags = _flags;
         }
         @Override
         public void run() {
@@ -12190,7 +12192,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, null, true /* focused */, true /* newSessionId */,
+                null, 0, null, true /* focused */, true /* newSessionId */,
                 UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
         if (pae == null) {
             return null;
@@ -12258,22 +12260,37 @@
             Bundle receiverExtras,
             IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
-                activityToken, focused, newSessionId,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0)
-                != null;
+                0, activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
+                PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
     }
 
     @Override
     public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
-            IBinder activityToken, int flags) {
-        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_FULL, null, null, receiver,
-                receiverExtras, activityToken, true, true,
-                UserHandle.getCallingUserId(), null, PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT,
-                flags) != null;
+            int resultCode, IBinder activityToken, int flags) {
+        final boolean forFill = (flags & View.AUTO_FILL_FLAG_TYPE_FILL) != 0;
+        final boolean forSave = (flags & View.AUTO_FILL_FLAG_TYPE_SAVE) != 0;
+        if ((forFill && forSave) || (!forFill) && !(forSave)) {
+            // There can be only one!
+            Slog.w(TAG,  "requestAutoFillData(): invalid flags (" + flags + ")");
+            return false;
+        }
+
+        // NOTE: we could always use ActivityManager.ASSIST_CONTEXT_FULL and let ActivityThread
+        // rely on the flags to decide whether the handleRequestAssistContextExtras() is for
+        // auto-fill, but it's safer to explicitly use new AutoFill types, in case the Assist
+        // requests use flags in the future as well (since their flags value might collide with the
+        // auto-fill flag values).
+        final int type = forFill?
+                ActivityManager.ASSIST_CONTEXT_AUTO_FILL :
+                    ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
+
+        return enqueueAssistContext(type, null, null, receiver, receiverExtras, resultCode,
+                activityToken, true, true, UserHandle.getCallingUserId(), null,
+                PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
+            IResultReceiver receiver, Bundle receiverExtras, int resultCode, IBinder activityToken,
             boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
             int flags) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
@@ -12314,7 +12331,7 @@
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
-                    flags, userHandle);
+                    resultCode, userHandle, flags);
             // Increment the sessionId if necessary
             if (newSessionId) {
                 mViSessionId++;
@@ -12400,17 +12417,15 @@
                 if (pae.flags > 0) {
                     sendBundle.putInt(VoiceInteractionSession.KEY_FLAGS, pae.flags);
                 }
-                IBinder autoFillCallback =
-                        extras.getBinder(AutoFillService.KEY_CALLBACK);
-                if (autoFillCallback != null) {
-                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK,
-                            autoFillCallback);
+                IBinder cb = extras.getBinder(AutoFillService.KEY_CALLBACK);
+                if (cb != null) {
+                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK, cb);
                 }
             }
         }
         if (sendReceiver != null) {
             try {
-                sendReceiver.send(0, sendBundle);
+                sendReceiver.send(pae.resultCode, sendBundle);
             } catch (RemoteException e) {
             }
             return;
@@ -12435,9 +12450,9 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, null,
-                true /* focused */, true /* newSessionId */,
-                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
+        return enqueueAssistContext(requestType, intent, hint, null, null, 0, null,
+                true /* focused */, true /* newSessionId */, userHandle, args,
+                PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {