Merge "AutoFill Framework refactoring."
diff --git a/api/current.txt b/api/current.txt
index 20cc4d6..0288686 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34877,7 +34877,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    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 SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -34895,6 +34896,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -42968,7 +42974,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 void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     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,8 +43241,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 void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    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 android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43437,6 +43446,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 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
diff --git a/api/system-current.txt b/api/system-current.txt
index c184196..c4b5987 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37714,7 +37714,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    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 SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -37732,6 +37733,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -46160,7 +46166,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 void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     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);
@@ -46426,8 +46433,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 void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    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 android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -46629,6 +46638,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 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
@@ -49999,6 +50010,7 @@
     method public abstract void onMeasure(int, int);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
     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 2c37f63..7ff9119 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34974,7 +34974,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+    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 SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
   }
 
@@ -34992,6 +34993,11 @@
     method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
   }
 
+  public final class SaveCallback {
+    method public void onFailure(java.lang.CharSequence);
+    method public void onSuccess(int[]);
+  }
+
 }
 
 package android.service.carrier {
@@ -43236,7 +43242,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 void dispatchProvideStructure(android.view.ViewStructure);
+    method public deprecated void dispatchProvideStructure(android.view.ViewStructure);
+    method public void dispatchProvideStructure(android.view.ViewStructure, int);
     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);
@@ -43503,8 +43510,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 void onProvideStructure(android.view.ViewStructure);
-    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    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 android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
@@ -43706,6 +43715,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 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
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 752eb14..2cdda3d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1738,8 +1738,8 @@
                                 FillableInputField autoFillField = (FillableInputField) field;
                                 final int viewId = autoFillField.getId();
                                 final View view = root.findViewByAccessibilityIdTraversal(viewId);
-                                // TODO: should handle other types of view as well, but that will
-                                // require:
+                                // 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)) {
@@ -1752,7 +1752,7 @@
                     @Override
                     public void showError(String message) {
                         runOnUiThread(() -> {
-                            // TODO: temporary show a toast until it uses the Snack bar.
+                            // 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();
                         });
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 312d3a5..f6f5472 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -450,9 +450,6 @@
     /** @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_AUTOFILL = 2;
-
     /** @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 f052bf7..9a92764 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -88,6 +88,7 @@
 import android.provider.Settings;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
+import android.service.autofill.AutoFillService;
 import android.service.autofill.IAutoFillCallback;
 import android.service.voice.VoiceInteractionSession;
 import android.util.AndroidRuntimeException;
@@ -640,6 +641,7 @@
         IBinder requestToken;
         int requestType;
         int sessionId;
+        int flags;
     }
 
     static final class ActivityConfigChangeData {
@@ -1245,12 +1247,13 @@
 
         @Override
         public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-                int requestType, int sessionId) {
+                int requestType, int sessionId, int flags) {
             RequestAssistContextExtras cmd = new RequestAssistContextExtras();
             cmd.activityToken = activityToken;
             cmd.requestToken = requestToken;
             cmd.requestType = requestType;
             cmd.sessionId = sessionId;
+            cmd.flags = flags;
             sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
         }
 
@@ -2883,6 +2886,16 @@
     }
 
     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
+        // Filling for auto-fill has a few differences:
+        // - it does not need an AssistContent
+        // - 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;
+
+        // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         if (mLastSessionId != cmd.sessionId) {
             // Clear the existing structures
             mLastSessionId = cmd.sessionId;
@@ -2894,46 +2907,45 @@
                 mLastAssistStructures.remove(i);
             }
         }
-        // Filling for auto-fill has a few differences:
-        // - it does not need an AssistContent
-        // - it does not call onProvideAssistData()
-        // - it needs an IAutoFillCallback
-        boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL;
 
         Bundle data = new Bundle();
         AssistStructure structure = null;
-        AssistContent content = forAutofill ? null : new AssistContent();
+        AssistContent content = forAutoFill ? null : new AssistContent();
         ActivityClientRecord r = mActivities.get(cmd.activityToken);
         Uri referrer = null;
         if (r != null) {
-            r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
-            if (!forAutofill) {
+            if (!forAutoFill) {
+                r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
                 r.activity.onProvideAssistData(data);
             }
             referrer = r.activity.onProvideReferrer();
-            if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) {
-                structure = new AssistStructure(r.activity);
+            if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
+                structure = new AssistStructure(r.activity, cmd.flags);
                 Intent activityIntent = r.activity.getIntent();
+                if (cmd.flags > 0) {
+                    data.putInt(VoiceInteractionSession.KEY_FLAGS, cmd.flags);
+                }
+                // 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 ||
                         (r.window.getAttributes().flags
                                 & WindowManager.LayoutParams.FLAG_SECURE) == 0)) {
-                    Intent intent = new Intent(activityIntent);
-                    intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                            | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
-                    intent.removeUnsafeExtras();
-                    if (forAutofill) {
+                    if (forAutoFill) {
                         IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback();
-                        data.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
-                                autoFillCallback.asBinder());
+                        data.putBinder(AutoFillService.KEY_CALLBACK, autoFillCallback.asBinder());
                     } else {
+                        Intent intent = new Intent(activityIntent);
+                        intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+                        intent.removeUnsafeExtras();
                         content.setDefaultIntent(intent);
                     }
                 } else {
-                    if (!forAutofill) {
+                    if (!forAutoFill) {
                         content.setDefaultIntent(new Intent());
                     }
                 }
-                if (!forAutofill) {
+                if (!forAutoFill) {
                     r.activity.onProvideAssistContent(content);
                 }
             }
@@ -2941,6 +2953,7 @@
         if (structure == null) {
             structure = new AssistStructure();
         }
+        // TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
         mLastAssistStructures.add(new WeakReference<>(structure));
         IActivityManager mgr = ActivityManager.getService();
         try {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e378f4ad..a10fffe 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -575,7 +575,7 @@
     void unregisterTaskStackListener(ITaskStackListener listener);
     void moveStackToDisplay(int stackId, int displayId);
     boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
-            in IBinder activityToken);
+            in IBinder activityToken, int flags);
     void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
 
     // WARNING: when these transactions are updated, check if they are any callers on the native
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 6b962b9..7f168c9 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -134,7 +134,7 @@
     void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
     void unstableProviderDied(IBinder provider);
     void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
-            int requestType, int sessionId);
+            int requestType, int sessionId, int flags);
     void scheduleTranslucentConversionComplete(IBinder token, boolean timeout);
     void setProcessState(int state);
     void scheduleInstallProvider(in ProviderInfo provider);
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index a6f2366..1988e42 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -400,7 +400,7 @@
         final int mDisplayId;
         final ViewNode mRoot;
 
-        WindowNode(AssistStructure assist, ViewRootImpl root) {
+        WindowNode(AssistStructure assist, ViewRootImpl root, int flags) {
             View view = root.getView();
             Rect rect = new Rect();
             view.getBoundsOnScreen(rect);
@@ -415,11 +415,22 @@
             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.
-                view.onProvideStructure(builder);
+
+                // Must explicitly set which method to calls since View subclasses might
+                // have implemented the deprecated method.
+                if (flags == 0) {
+                    view.onProvideStructure(builder);
+                } else {
+                    view.onProvideStructure(builder, flags);
+                }
                 builder.setAssistBlocked(true);
                 return;
             }
-            view.dispatchProvideStructure(builder);
+            if (flags == 0) {
+                view.dispatchProvideStructure(builder);
+            } else {
+                view.dispatchProvideStructure(builder, flags);
+            }
         }
 
         WindowNode(ParcelTransferReader reader) {
@@ -1351,14 +1362,14 @@
     }
 
     /** @hide */
-    public AssistStructure(Activity activity) {
+    public AssistStructure(Activity activity, int flags) {
         mHaveData = true;
         mActivityComponent = activity.getComponentName();
         ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
                 activity.getActivityToken());
         for (int i=0; i<views.size(); i++) {
             ViewRootImpl root = views.get(i);
-            mWindowNodes.add(new WindowNode(this, root));
+            mWindowNodes.add(new WindowNode(this, root, flags));
         }
     }
 
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index 5f27e34..a7941c7 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,6 +15,11 @@
  */
 package android.service.autofill;
 
+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 android.annotation.SdkConstant;
 import android.app.Activity;
 import android.app.Service;
@@ -26,13 +31,14 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
 
 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)
+
 /**
  * Top-level service of the current auto-fill service for a given user.
  *
@@ -52,6 +58,11 @@
     @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";
+
+    // 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;
@@ -59,14 +70,12 @@
     private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
         @Override
         public void send(int resultCode, Bundle resultData) throws RemoteException {
-            final AssistStructure structure = resultData
-                    .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
-
-            final IBinder binder = resultData
-                    .getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
+            final IBinder binder = resultData.getBinder(KEY_CALLBACK);
+            final int flags = resultData.getInt(KEY_FLAGS, 0);
 
             mHandlerCaller
-                .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, binder).sendToTarget();
+                .obtainMessageIOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, binder).sendToTarget();
         }
 
     };
@@ -100,7 +109,8 @@
                     final SomeArgs args = (SomeArgs) msg.obj;
                     final AssistStructure structure = (AssistStructure) args.arg1;
                     final IBinder binder = (IBinder) args.arg2;
-                    requestAutoFill(structure, binder);
+                    final int flags = msg.arg1;
+                    requestAutoFill(structure, flags, binder);
                     break;
                 } case MSG_DISCONNECT: {
                     onDisconnected();
@@ -145,19 +155,46 @@
     }
 
     /**
-     * Handles an auto-fill request.
+     * Called when user requests service to auto-fill an {@link Activity}.
      *
      * @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).
      * @param cancellationSignal signal for observing cancel requests.
-     * @param callback object used to fulllfill the request.
      */
     public abstract void onFillRequest(AssistStructure structure,
-            CancellationSignal cancellationSignal, FillCallback callback);
+            Bundle data, CancellationSignal cancellationSignal, FillCallback callback);
 
-    private void requestAutoFill(AssistStructure structure, IBinder binder) {
-        final FillCallback callback = new FillCallback(binder);
-        // TODO: hook up the cancelationSignal
-        onFillRequest(structure, new CancellationSignal(), callback);
+    /**
+     * Called when user requests service to save the fields of an {@link Activity}.
+     *
+     * @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 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();
+        switch (flags) {
+            case ASSIST_FLAG_SANITIZED_TEXT:
+                final FillCallback fillCallback = new FillCallback(binder);
+                // 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);
+                // TODO(b/33197203): hook up the cancelationSignal
+                onSaveRequest(structure, null, new CancellationSignal(), saveCallback);
+                break;
+            default:
+                Log.w(TAG, "invalid flag on requestAutoFill(): " + flags);
+        }
     }
 
     /**
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 2308440..3284b90 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -17,7 +17,6 @@
 package android.service.autofill;
 
 import static android.service.autofill.AutoFillService.DEBUG;
-import static android.service.autofill.AutoFillService.TAG;
 
 import android.app.Activity;
 import android.app.assist.AssistStructure.ViewNode;
@@ -38,6 +37,8 @@
  */
 public final class FillCallback {
 
+    private static final String TAG = "FillCallback";
+
     private final IAutoFillCallback mCallback;
 
     /** @hide */
@@ -62,6 +63,13 @@
         }
     }
 
+    /**
+     * Notifies the {@link Activity} that the auto-fill request failed.
+     *
+     * @param message error message to be displayed.
+     *
+     * @throws RuntimeException if an error occurred while notifying the activity.
+     */
     public void onFailure(CharSequence message) {
         if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
 
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index 76a2561..f1251c0 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -25,11 +25,5 @@
  */
 oneway interface IAutoFillManagerService {
 
-    /**
-     * Request auto-fill on the top activity of a given user.
-     *
-     * @param userId user handle.
-     * @param activityToken optional token of activity that needs to be on top.
-     */
-    void requestAutoFill(int userId, IBinder activityToken);
+    void requestAutoFill(IBinder activityToken, int userId, int flags);
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
new file mode 100644
index 0000000..4dc7392
--- /dev/null
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -0,0 +1,79 @@
+/*
+ * 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 static android.service.autofill.AutoFillService.DEBUG;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Handles save requests from the {@link AutoFillService} into the {@link Activity} being
+ * auto-filled.
+ */
+public final class SaveCallback {
+
+    private static final String TAG = "SaveCallback";
+
+    private final IAutoFillCallback mCallback;
+
+    /** @hide */
+    SaveCallback(IBinder binder) {
+        mCallback = IAutoFillCallback.Stub.asInterface(binder);
+    }
+
+    /**
+     * Notifies the {@link Activity} that the save request succeeded.
+     *
+     * @param ids ids ({@link ViewNode#getAutoFillId()}) of the fields that were saved.
+     *
+     * @throws RuntimeException if an error occurred while saving the data.
+     */
+    public void onSuccess(int[] ids) {
+        Preconditions.checkArgument(ids != null, "ids cannot be null");
+
+        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
+    }
+
+    /**
+     * Notifies the {@link Activity} that the save request failed.
+     *
+     * @param message error message to be displayed.
+     *
+     * @throws RuntimeException if an error occurred while notifying the activity.
+     */
+    public void onFailure(CharSequence message) {
+        if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
+
+        Preconditions.checkArgument(message != null, "message cannot be null");
+
+        try {
+            mCallback.showError(message.toString());
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 12aed25..48f3ac3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -120,7 +120,7 @@
     /** @hide */
     public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
     /** @hide */
-    public static final String KEY_AUTO_FILL_CALLBACK = "autoFillCallback";
+    public static final String KEY_FLAGS = "flags";
 
     final Context mContext;
     final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 316b123..3f4c49b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3964,6 +3964,21 @@
     int mLayerType = LAYER_TYPE_NONE;
     Paint mLayerPaint;
 
+
+    /**
+     * <p>When setting a {@link android.app.assist.AssistStructure}, its nodes should not contain
+     * PII (Personally Identifiable Information).
+     */
+    // TODO(b/33197203) (b/33269702): improve documentation: mention all cases, show examples, etc.
+    public static final int ASSIST_FLAG_SANITIZED_TEXT = 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.
+     */
+    public static final int ASSIST_FLAG_NON_SANITIZED_TEXT = 0x2;
+
     /**
      * Set to true when drawing cache is enabled and cannot be created.
      *
@@ -6781,8 +6796,35 @@
      * {@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);
+    }
+
+    /**
+     * 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.
+     *
+     * <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
+     * 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).
+     */
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
         final int id = mID;
         if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
                 && (id&0x0000ffff) != 0) {
@@ -6800,9 +6842,11 @@
             structure.setId(id, null, null, null);
         }
 
-        // 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());
+        if (forAutoFill) {
+            // 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.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
         if (!hasIdentityMatrix()) {
@@ -6852,20 +6896,52 @@
      * 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);
+    }
+
+    /**
+     * 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.
+     *
+     * <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
+     * 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).
+     */
+    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
+        boolean sanitize = (flags & View.ASSIST_FLAG_SANITIZED_TEXT) != 0;
+
+        if (sanitize) {
+            // TODO(b/33197203): change populateVirtualStructure so it sanitizes data in this case.
+            return;
+        }
+
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             AccessibilityNodeInfo info = createAccessibilityNodeInfo();
             structure.setChildCount(1);
             ViewStructure root = structure.newChild(0);
-            populateVirtualStructure(root, provider, info);
+            populateVirtualStructure(root, provider, info, flags);
             info.recycle();
         }
     }
 
     private void populateVirtualStructure(ViewStructure structure,
-            AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
+            AccessibilityNodeProvider provider, AccessibilityNodeInfo info, int flags) {
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
                 null, null, null);
         Rect rect = structure.getTempRect();
@@ -6914,7 +6990,7 @@
                 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
                 ViewStructure child = structure.newChild(i);
-                populateVirtualStructure(child, provider, cinfo);
+                populateVirtualStructure(child, provider, cinfo, flags);
                 cinfo.recycle();
             }
         }
@@ -6924,11 +7000,38 @@
      * 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) {
-        if (!isAssistBlocked()) {
-            onProvideStructure(structure);
-            onProvideVirtualStructure(structure);
+        dispatchProvideStructure(structure, 0);
+    }
+
+    /**
+     * Dispatch creation of {@link ViewStructure} down the hierarchy.
+     *
+     * <p>The structure must be filled according to the request type, which is set in the
+     * {@code flags} parameter - see the documentation on each flag for more details.
+     *
+     * <p>The default implementation calls {@link #onProvideStructure(ViewStructure, int)} and
+     * {@link #onProvideVirtualStructure(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).
+     */
+    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+
+        boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
+        if (!blocked) {
+            onProvideStructure(structure, flags);
+            onProvideVirtualStructure(structure, flags);
         } else {
             structure.setClassName(getAccessibilityClassName().toString());
             structure.setAssistBlocked(true);
@@ -8667,6 +8770,25 @@
 
     /**
      * @hide
+     * Indicates whether this view will participate in data collection through
+     * {@link ViewStructure} for auto-fill purposes.
+     *
+     * <p>If {@code true}, it will not provide any data for itself or its children.
+     * <p>If {@code false}, the normal data collection will be allowed.
+     *
+     * @return Returns {@code false} if assist data collection for auto-fill is not blocked,
+     * else {@code true}.
+     *
+     * TODO(b/33197203): update / remove javadoc tags below
+     * @see #setAssistBlocked(boolean)
+     * @attr ref android.R.styleable#View_assistBlocked
+     */
+    public boolean isAutoFillBlocked() {
+        return false; // TODO(b/33197203): properly implement it
+    }
+
+    /**
+     * @hide
      * Controls whether assist data collection from this view and its children is enabled
      * (that is, whether {@link #onProvideStructure} and
      * {@link #onProvideVirtualStructure} will be called).  The default value is false,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0f8200d..ff797d1 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3083,14 +3083,22 @@
     }
 
     /**
-     * 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.
+     * {@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) {
-        super.dispatchProvideStructure(structure);
-        if (!isAssistBlocked()) {
+    public void dispatchProvideStructure(ViewStructure structure, int flags) {
+        super.dispatchProvideStructure(structure, flags);
+
+        boolean forAutoFill = (flags
+                & (View.ASSIST_FLAG_SANITIZED_TEXT
+                        | View.ASSIST_FLAG_NON_SANITIZED_TEXT)) != 0;
+
+        boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
+
+        if (!blocked) {
             if (structure.getChildCount() == 0) {
                 final int childrenCount = getChildCount();
                 if (childrenCount > 0) {
@@ -3151,7 +3159,14 @@
                         final View child = getAndVerifyPreorderedView(
                                 preorderedList, children, childIndex);
                         final ViewStructure cstructure = structure.newChild(i);
-                        child.dispatchProvideStructure(cstructure);
+
+                        // 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);
+                        } else {
+                            child.dispatchProvideStructure(cstructure, flags);
+                        }
                     }
                     if (preorderedList != null) preorderedList.clear();
                 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b840f4a..8ecc42d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2504,6 +2504,7 @@
         return mProvider.getViewDelegate().shouldDelayChildPressedState();
     }
 
+    @Override
     public CharSequence getAccessibilityClassName() {
         return WebView.class.getName();
     }
@@ -2513,6 +2514,11 @@
         mProvider.getViewDelegate().onProvideVirtualStructure(structure);
     }
 
+    @Override
+    public void onProvideVirtualStructure(ViewStructure structure, int flags) {
+        mProvider.getViewDelegate().onProvideVirtualStructure(structure, flags);
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95ec179..7b95180 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -311,6 +311,11 @@
 
         public void onProvideVirtualStructure(android.view.ViewStructure structure);
 
+        @SuppressWarnings("unused")
+        public default void onProvideVirtualStructure(android.view.ViewStructure structure,
+                int flags) {
+        }
+
         public AccessibilityNodeProvider getAccessibilityNodeProvider();
 
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index fcc1667..e629df9 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1404,8 +1404,10 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure) {
-        super.onProvideStructure(structure);
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        super.onProvideStructure(structure, flags);
+
+        // NOTE: current there is no difference for Assist (flags=0) or AutoFill (flags>0);
         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 c7e4abe..0126407 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9386,11 +9386,14 @@
     }
 
     @Override
-    public void onProvideStructure(ViewStructure structure) {
-        super.onProvideStructure(structure);
+    public void onProvideStructure(ViewStructure structure, int flags) {
+        super.onProvideStructure(structure, flags);
+
+        final boolean forAutoFillSave =
+                (flags & ASSIST_FLAG_NON_SANITIZED_TEXT) != 0;
         final boolean isPassword = hasPasswordTransformationMethod()
                 || isPasswordInputType(getInputType());
-        if (!isPassword) {
+        if (!isPassword || forAutoFillSave) {
             if (mLayout == null) {
                 assumeLayout();
             }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
index d70c439..6a16131 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -18,10 +18,13 @@
 
 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 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;
@@ -248,13 +251,14 @@
     final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
 
         @Override
-        public void requestAutoFill(int userId, IBinder activityToken) {
+        public void requestAutoFill(IBinder activityToken, int userId, 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);
+                    service.requestAutoFill(activityToken, flags);
                 }
             }
         }
@@ -307,7 +311,7 @@
             synchronized (mLock) {
                 removeCachedServiceForUserLocked(userId);
                 final ComponentName serviceComponent = getProviderForUser(userId);
-                if (serviceComponent== null) {
+                if (serviceComponent == null) {
                     cancelNotificationLocked(userId);
                 } else {
                     showNotification(serviceComponent, userId);
@@ -322,9 +326,10 @@
     ////////////////////////////////////////////////////////////////////////////
 
     // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore
-    private static final String NOTIFICATION_INTENT =
+    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;
@@ -335,13 +340,14 @@
         @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);
+                    service.requestAutoFill(null, flags);
                 }
             }
         }
@@ -393,14 +399,23 @@
             if (mNotificationReceiver == null) {
                 mNotificationReceiver = new NotificationReceiver();
                 mContext.registerReceiver(mNotificationReceiver,
-                        new IntentFilter(NOTIFICATION_INTENT));
+                        new IntentFilter(NOTIFICATION_AUTO_FILL_INTENT));
             }
         }
 
-        final Intent intent = new Intent(NOTIFICATION_INTENT);
-        intent.putExtra(EXTRA_USER_ID, userId);
-        final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+        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;
@@ -413,8 +428,8 @@
         } catch (Exception e) {
             providerName = packageName;
         }
-        final String title = "AutoFill by '" + providerName + "'";
-        final String subTitle = "Tap notification to auto-fill top activity for user " + userId;
+        final String title = "AutoFill actions";
+        final String subTitle = "Provider: " + providerName + "\n" + "User: " + userId;
 
         final Notification notification = new Notification.Builder(mContext)
                 .setCategory(Notification.CATEGORY_SYSTEM)
@@ -425,7 +440,7 @@
                         com.android.internal.R.color.system_notification_accent_color))
                 .setContentTitle(title)
                 .setStyle(new Notification.BigTextStyle().bigText(subTitle))
-                .setContentIntent(pi)
+                .setActions(fillAction, saveAction)
                 .build();
         NotificationManager.from(mContext).notify(userId, notification);
     }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index e409cb0..82356c8 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -47,7 +47,6 @@
 import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -70,13 +69,13 @@
     private final AutoFillServiceInfo mInfo;
     private final AutoFillManagerService mManagerService;
 
-    // TODO: improve its usage
+    // TODO(b/33197203): improve its usage
     // - set maximum number of entries
     // - disable on low-memory devices.
     private final List<String> mRequestHistory = new LinkedList<>();
 
     @GuardedBy("mLock")
-    private final List<IBinder> mQueuedRequests = new LinkedList<>();
+    private final List<QueuedRequest> mQueuedRequests = new LinkedList<>();
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -84,7 +83,8 @@
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                 final String reason = intent.getStringExtra("reason");
                 if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
-                // TODO: close any pending UI like account selection (or remove this receiver)
+                // TODO(b/33197203): close any pending UI like account selection (or remove this
+                // receiver)
             }
         }
     };
@@ -104,8 +104,8 @@
                 if (!mQueuedRequests.isEmpty()) {
                     if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size());
                 }
-                for (IBinder activityToken : mQueuedRequests) {
-                    requestAutoFillLocked(activityToken, false);
+                for (final QueuedRequest request: mQueuedRequests) {
+                    requestAutoFillLocked(request.activityToken, request.flags, false);
                 }
             }
         }
@@ -180,7 +180,7 @@
         if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
     }
 
-    void requestAutoFill(IBinder activityToken) {
+    void requestAutoFill(IBinder activityToken, int flags) {
         synchronized (mLock) {
             if (!mBound) {
                 Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
@@ -188,14 +188,14 @@
             }
         }
 
-        // TODO: activityToken should probably not be null, but we need to wait until the UI is
-        // triggering the call (for now it's trough 'adb shell cmd autofill request'
+        // TODO(b/33197203): activityToken should probably not be null, but we need to wait until
+        // the UI is triggering the call (for now it's trough 'adb shell cmd autofill request'
         if (activityToken == null) {
             // Let's get top activities from all visible stacks.
 
-            // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return
-            // activities for different users when a work profile app is displayed in another
-            // window (in a multi-window environment).
+            // TODO(b/33197203): overload getTopVisibleActivities() to take userId, otherwise it
+            // could return activities for different users when a work profile app is displayed in
+            // another window (in a multi-window environment).
             final List<IBinder> topActivities = LocalServices
                     .getService(ActivityManagerInternal.class).getTopVisibleActivities();
             if (DEBUG)
@@ -211,32 +211,34 @@
                 DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
         synchronized (mLock) {
             mRequestHistory.add(historyItem);
-            requestAutoFillLocked(activityToken, true);
+            requestAutoFillLocked(activityToken, flags, true);
         }
     }
 
-    private void requestAutoFillLocked(IBinder activityToken, boolean queueIfNecessary) {
+    private void requestAutoFillLocked(IBinder activityToken, 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(activityToken);
+            mQueuedRequests.add(new QueuedRequest(activityToken, flags));
             return;
         }
 
         /*
-         * TODO: apply security checks below:
+         * TODO(b/33197203): apply security checks below:
          * - checks if disabled by secure settings / device policy
          * - log operation using noteOp()
          * - check flags
          * - display disclosure if needed
          */
         try {
-            // TODO: add MetricsLogger call
-            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken)) {
-                // TODO: might need a way to warn user (perhaps a new method on AutoFillService).
+            // TODO(b/33197203): add MetricsLogger call
+            if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, 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);
             }
         } catch (RemoteException e) {
@@ -322,4 +324,19 @@
         return "[AutoFillManagerServiceImpl: userId=" + mUserId + ", uid=" + mUid
                 + ", component=" + mComponent.flattenToShortString() + "]";
     }
+
+    private static final class QueuedRequest {
+        final IBinder activityToken;
+        final int flags;
+
+        QueuedRequest(IBinder activityToken, int flags) {
+            this.activityToken = activityToken;
+            this.flags = flags;
+        }
+
+        @Override
+        public String toString() {
+            return "flags: " + flags + " token: " + activityToken;
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
index 6406b8a..aa3503b 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -16,6 +16,9 @@
 
 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 android.app.ActivityManager;
 import android.os.RemoteException;
 import android.os.ShellCommand;
@@ -40,8 +43,10 @@
         final PrintWriter pw = getOutPrintWriter();
         try {
             switch (cmd) {
-                case "request":
-                    return requestAutoFill();
+                case "fill":
+                    return requestAutoFill(ASSIST_FLAG_SANITIZED_TEXT);
+                case "save":
+                    return requestAutoFill(ASSIST_FLAG_NON_SANITIZED_TEXT);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -58,15 +63,17 @@
             pw.println("  help");
             pw.println("    Prints this help text.");
             pw.println("");
-            pw.println("  request [--user USER_ID]");
-            pw.println("    Request auto-fill on the top activity. ");
+            pw.println("  fill [--user USER_ID]");
+            pw.println("    Request provider to auto-fill the top activity. ");
+            pw.println("  save [--user USER_ID]");
+            pw.println("    Request provider to save contents of the top activity. ");
             pw.println("");
         }
     }
 
-    private int requestAutoFill() throws RemoteException {
+    private int requestAutoFill(int flags) throws RemoteException {
         final int userId = getUserIdFromArgs();
-        mService.requestAutoFill(userId, null);
+        mService.requestAutoFill(null, userId, flags);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2a8ad87..f6fea3c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -202,6 +202,7 @@
 import android.os.storage.StorageManager;
 import android.provider.Downloads;
 import android.provider.Settings;
+import android.service.autofill.AutoFillService;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionSession;
@@ -507,6 +508,9 @@
     // on getting this result before starting to launch its UI).
     static final int PENDING_ASSIST_EXTRAS_LONG_TIMEOUT = 2000;
 
+    // How long to wait in getAutoFillAssistStructure() for the activity to respond with the result.
+    static final int PENDING_AUTO_FILL_ASSIST_STRUCTURE_TIMEOUT = 2000;
+
     // Maximum number of persisted Uri grants a package is allowed
     static final int MAX_PERSISTED_URI_GRANTS = 128;
 
@@ -683,15 +687,18 @@
         public AssistStructure structure = null;
         public AssistContent content = null;
         public Bundle receiverExtras;
+        public int flags;
 
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _flags,
+                int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
             receiverExtras = _receiverExtras;
+            flags = _flags;
             userHandle = _userHandle;
         }
         @Override
@@ -12178,7 +12185,7 @@
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
                 null, null, true /* focused */, true /* newSessionId */,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
         if (pae == null) {
             return null;
         }
@@ -12246,22 +12253,23 @@
             IBinder activityToken, boolean focused, boolean newSessionId) {
         return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
                 activityToken, focused, newSessionId,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0)
                 != null;
     }
 
     @Override
     public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
-            IBinder activityToken) {
-        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null, receiver,
+            IBinder activityToken, int flags) {
+        return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_FULL, null, null, receiver,
                 receiverExtras, activityToken, true, true,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
-                != null;
+                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,
-            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
+            boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
+            int flags) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
         synchronized (this) {
@@ -12300,14 +12308,14 @@
             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,
-                    userHandle);
+                    flags, userHandle);
             // Increment the sessionId if necessary
             if (newSessionId) {
                 mViSessionId++;
             }
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
-                        requestType, mViSessionId);
+                        requestType, mViSessionId, flags);
                 mPendingAssistExtras.add(pae);
                 mUiHandler.postDelayed(pae, timeout);
             } catch (RemoteException e) {
@@ -12383,10 +12391,13 @@
                 sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
                 sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
                         pae.receiverExtras);
+                if (pae.flags > 0) {
+                    sendBundle.putInt(VoiceInteractionSession.KEY_FLAGS, pae.flags);
+                }
                 IBinder autoFillCallback =
-                        extras.getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+                        extras.getBinder(AutoFillService.KEY_CALLBACK);
                 if (autoFillCallback != null) {
-                    sendBundle.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
+                    sendBundle.putBinder(AutoFillService.KEY_CALLBACK,
                             autoFillCallback);
                 }
             }
@@ -12420,7 +12431,7 @@
             Bundle args) {
         return enqueueAssistContext(requestType, intent, hint, null, null, null,
                 true /* focused */, true /* newSessionId */,
-                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {