summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorFelipe Leme <felipeal@google.com>2017-02-02 02:05:29 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-02-02 02:05:32 +0000
commit5523f9a2fcaf472e92c1d380a79776c4bf857a80 (patch)
tree037bdcc7b53d6eec28e5b73e1039e2ec5345f4d4 /core/java/android
parent82233e92036718f95c37d4ae5cb5ce9b27d39ff0 (diff)
parent0200d9ea1509089c0c03b7071aa271e3a9b35c11 (diff)
Merge "Improved AutoFill Save workflow."
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityManager.java3
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/IApplicationThread.aidl2
-rw-r--r--core/java/android/app/assist/AssistStructure.java150
-rw-r--r--core/java/android/service/autofill/AutoFillService.java85
-rw-r--r--core/java/android/service/autofill/IAutoFillManagerService.aidl9
-rw-r--r--core/java/android/service/autofill/IAutoFillServerCallback.aidl2
-rw-r--r--core/java/android/service/autofill/IAutoFillService.aidl3
-rw-r--r--core/java/android/service/autofill/SaveCallback.java15
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java2
-rw-r--r--core/java/android/view/View.java97
-rw-r--r--core/java/android/view/ViewGroup.java16
-rw-r--r--core/java/android/view/ViewStructure.java40
-rw-r--r--core/java/android/view/autofill/AutoFillId.java1
-rw-r--r--core/java/android/view/autofill/AutoFillManager.java29
-rw-r--r--core/java/android/view/autofill/AutoFillValue.java1
-rw-r--r--core/java/android/view/autofill/VirtualViewDelegate.java7
-rw-r--r--core/java/android/widget/CompoundButton.java8
-rw-r--r--core/java/android/widget/RadioGroup.java7
-rw-r--r--core/java/android/widget/TextView.java81
21 files changed, 375 insertions, 200 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b367d0cb4a1b..5b05d581c4e0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -505,9 +505,6 @@ public class ActivityManager {
/** @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 cf20b68cf200..d5371f8b7b3c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -91,7 +91,6 @@ import android.security.NetworkSecurityPolicy;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.service.autofill.AutoFillService;
import android.service.autofill.IAutoFillAppCallback;
-import android.service.voice.VoiceInteractionSession;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -641,7 +640,6 @@ public final class ActivityThread {
IBinder requestToken;
int requestType;
int sessionId;
- int flags;
}
static final class ActivityConfigChangeData {
@@ -1249,13 +1247,12 @@ public final class ActivityThread {
@Override
public void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId, int flags) {
+ int requestType, int sessionId) {
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);
}
@@ -2905,9 +2902,7 @@ public final class ActivityThread {
// - 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.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL
- || cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL_SAVE;
+ boolean forAutoFill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTO_FILL;
// TODO(b/33197203): decide if lastSessionId logic applies to auto-fill sessions
if (mLastSessionId != cmd.sessionId) {
@@ -2934,11 +2929,8 @@ public final class ActivityThread {
referrer = r.activity.onProvideReferrer();
}
if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutoFill) {
- structure = new AssistStructure(r.activity, cmd.flags);
+ structure = new AssistStructure(r.activity, forAutoFill);
Intent activityIntent = r.activity.getIntent();
- 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)
@@ -2979,6 +2971,7 @@ public final class ActivityThread {
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();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0a2f8049dc66..3cc6282d6ab3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -584,7 +584,7 @@ interface IActivityManager {
void unregisterTaskStackListener(ITaskStackListener listener);
void moveStackToDisplay(int stackId, int displayId);
boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
- int resultCode, in IBinder activityToken, int flags);
+ int resultCode, in IBinder activityToken);
void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
int restartUserInBackground(int userId);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 41d1255c0a28..4fc6fb9eee2e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -134,7 +134,7 @@ oneway interface IApplicationThread {
void dumpDbInfo(in ParcelFileDescriptor fd, in String[] args);
void unstableProviderDied(IBinder provider);
void requestAssistContextExtras(IBinder activityToken, IBinder requestToken,
- int requestType, int sessionId, int flags);
+ int requestType, int sessionId);
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 b94264e1ac5d..08aa5f2589bf 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -22,6 +22,7 @@ import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.autofill.AutoFillType;
+import android.view.autofill.AutoFillValue;
import android.view.autofill.AutoFillId;
import java.util.ArrayList;
@@ -53,6 +54,8 @@ public class AssistStructure implements Parcelable {
Rect mTmpRect = new Rect();
+ boolean mSanitizeOnWrite = false;
+
static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
static final String DESCRIPTOR = "android.app.AssistStructure";
@@ -113,8 +116,10 @@ public class AssistStructure implements Parcelable {
int mNumWrittenWindows;
int mNumWrittenViews;
final float[] mTmpMatrix = new float[9];
+ final boolean mSanitizeOnWrite;
ParcelTransferWriter(AssistStructure as, Parcel out) {
+ mSanitizeOnWrite = as.mSanitizeOnWrite;
mWriteStructure = as.waitForReady();
ComponentName.writeToParcel(as.mActivityComponent, out);
mNumWindows = as.mWindowNodes.size();
@@ -186,7 +191,7 @@ public class AssistStructure implements Parcelable {
+ ", views=" + mNumWrittenViews
+ ", level=" + (mCurViewStackPos+levelAdj));
out.writeInt(VALIDATE_VIEW_TOKEN);
- int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
+ int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
mNumWrittenViews++;
// If the child has children, push it on the stack to write them next.
if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
@@ -374,8 +379,8 @@ public class AssistStructure implements Parcelable {
}
}
- void writeToParcel(Parcel out, boolean simple) {
- TextUtils.writeToParcel(mText, out, 0);
+ void writeToParcel(Parcel out, boolean simple, boolean writeSensitive) {
+ TextUtils.writeToParcel(writeSensitive ? mText : "", out, 0);
out.writeFloat(mTextSize);
out.writeInt(mTextStyle);
out.writeInt(mTextColor);
@@ -402,7 +407,7 @@ public class AssistStructure implements Parcelable {
final int mDisplayId;
final ViewNode mRoot;
- WindowNode(AssistStructure assist, ViewRootImpl root, int flags) {
+ WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill) {
View view = root.getView();
Rect rect = new Rect();
view.getBoundsOnScreen(rect);
@@ -414,19 +419,14 @@ public class AssistStructure implements Parcelable {
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);
+ ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false, 0);
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.
if (forAutoFill) {
- view.onProvideAutoFillStructure(builder, flags);
+ // NOTE: flags are currently not supported, hence 0
+ view.onProvideAutoFillStructure(builder, 0);
} else {
view.onProvideStructure(builder);
}
@@ -434,7 +434,8 @@ public class AssistStructure implements Parcelable {
return;
}
if (forAutoFill) {
- view.dispatchProvideAutoFillStructure(builder, flags);
+ // NOTE: flags are currently not supported, hence 0
+ view.dispatchProvideAutoFillStructure(builder, 0);
} else {
view.dispatchProvideStructure(builder);
}
@@ -537,6 +538,8 @@ public class AssistStructure implements Parcelable {
// fields (viewId and childId) of the field.
AutoFillId mAutoFillId;
AutoFillType mAutoFillType;
+ AutoFillValue mAutoFillValue;
+ boolean mSanitized;
int mX;
int mY;
int mScrollX;
@@ -610,8 +613,10 @@ public class AssistStructure implements Parcelable {
}
}
if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+ mSanitized = in.readInt() == 1;
mAutoFillId = in.readParcelable(null);
mAutoFillType = in.readParcelable(null);
+ mAutoFillValue = in.readParcelable(null);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -663,7 +668,11 @@ public class AssistStructure implements Parcelable {
}
}
- int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
+ int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
+ float[] tmpMatrix) {
+ // Guard used to skip non-sanitized data when writing for auto-fill.
+ boolean writeSensitive = true;
+
int flags = mFlags & ~FLAGS_ALL_CONTROL;
if (mId != View.NO_ID) {
flags |= FLAGS_HAS_ID;
@@ -716,8 +725,12 @@ public class AssistStructure implements Parcelable {
}
}
if ((flags&FLAGS_HAS_AUTO_FILL_DATA) != 0) {
+ writeSensitive = mSanitized || !sanitizeOnWrite;
+ out.writeInt(mSanitized ? 1 : 0);
out.writeParcelable(mAutoFillId, 0);
out.writeParcelable(mAutoFillType, 0);
+ final AutoFillValue sanitizedValue = writeSensitive ? mAutoFillValue : null;
+ out.writeParcelable(sanitizedValue, 0);
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -746,7 +759,7 @@ public class AssistStructure implements Parcelable {
TextUtils.writeToParcel(mContentDescription, out, 0);
}
if ((flags&FLAGS_HAS_TEXT) != 0) {
- mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
+ mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
}
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
out.writeBundle(mExtras);
@@ -794,6 +807,7 @@ public class AssistStructure implements Parcelable {
* <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
* for assist.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public AutoFillId getAutoFillId() {
return mAutoFillId;
}
@@ -804,11 +818,47 @@ public class AssistStructure implements Parcelable {
* <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
* for assist.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public AutoFillType getAutoFillType() {
return mAutoFillType;
}
/**
+ * Gets the the value of this view.
+ *
+ * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+ * for assist.
+ */
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public AutoFillValue getAutoFillValue() {
+ return mAutoFillValue;
+ }
+
+ /** @hide */
+ public boolean isSanitized() {
+ return mSanitized;
+ }
+
+ /**
+ * Updates the {@link AutoFillValue} of this structure.
+ *
+ * <p>Should be used just before sending the structure to the
+ * {@link android.service.autofill.AutoFillService} for saving, since it will override the
+ * initial value.
+ *
+ * @hide
+ */
+ public void updateAutoFillValue(AutoFillValue value) {
+ mAutoFillValue = value;
+ // TODO(b/33197203, b/33802548): decide whether to set text as well (so it would work
+ // with "legacy" views) or just the auto-fill value
+ final CharSequence text = value.getTextValue();
+ if (text != null) {
+ mText.mText = text;
+ }
+ }
+
+ /**
* Returns the left edge of this view, in pixels, relative to the left edge of its parent.
*/
public int getLeft() {
@@ -1113,10 +1163,11 @@ public class AssistStructure implements Parcelable {
final ViewNode mNode;
final boolean mAsync;
- ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
+ ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async, int flags) {
mAssist = assist;
mNode = node;
mAsync = async;
+ mNode.mSanitized = (flags & AUTO_FILL_FLAG_SANITIZED) != 0;
}
@Override
@@ -1350,19 +1401,20 @@ public class AssistStructure implements Parcelable {
}
}
- private ViewStructure newChild(int index, boolean forAutoFill, int virtualId) {
+ private ViewStructure newChild(int index, boolean forAutoFill, int virtualId, int flags) {
ViewNode node = new ViewNode();
setAutoFillId(node, forAutoFill, virtualId);
mNode.mChildren[index] = node;
- return new ViewNodeBuilder(mAssist, node, false);
+ return new ViewNodeBuilder(mAssist, node, false, flags);
}
- private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId) {
+ private ViewStructure asyncNewChild(int index, boolean forAutoFill, int virtualId,
+ int flags) {
synchronized (mAssist) {
ViewNode node = new ViewNode();
setAutoFillId(node, forAutoFill, virtualId);
mNode.mChildren[index] = node;
- ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
+ ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true, flags);
mAssist.mPendingAsyncChildren.add(builder);
return builder;
}
@@ -1370,22 +1422,23 @@ public class AssistStructure implements Parcelable {
@Override
public ViewStructure newChild(int index) {
- return newChild(index, false, 0);
+ return newChild(index, false, 0, 0);
}
+ // TODO(b/33197203, b/33802548): add CTS/unit test
@Override
- public ViewStructure newChild(int index, int virtualId) {
- return newChild(index, true, virtualId);
+ public ViewStructure newChild(int index, int virtualId, int flags) {
+ return newChild(index, true, virtualId, flags);
}
@Override
public ViewStructure asyncNewChild(int index) {
- return asyncNewChild(index, false, 0);
+ return asyncNewChild(index, false, 0, 0);
}
@Override
- public ViewStructure asyncNewChild(int index, int virtualId) {
- return asyncNewChild(index, true, virtualId);
+ public ViewStructure asyncNewChild(int index, int virtualId, int flags) {
+ return asyncNewChild(index, true, virtualId, flags);
}
@Override
@@ -1422,17 +1475,29 @@ public class AssistStructure implements Parcelable {
mNode.mAutoFillType = type;
}
+ @Override
+ public void setAutoFillValue(AutoFillValue value) {
+ mNode.mAutoFillValue = value;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void setSanitized(boolean sanitized) {
+ mNode.mSanitized = sanitized;
+ }
}
/** @hide */
- public AssistStructure(Activity activity, int flags) {
+ public AssistStructure(Activity activity, boolean forAutoFill) {
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, flags));
+ mWindowNodes.add(new WindowNode(this, root, forAutoFill));
}
}
@@ -1446,9 +1511,24 @@ public class AssistStructure implements Parcelable {
mReceiveChannel = in.readStrongBinder();
}
+ /**
+ * Helper method used to sanitize the structure before it's written to a parcel.
+ *
+ * <p>Used just on auto-fill.
+ * @hide
+ */
+ public void sanitizeForParceling(boolean sanitize) {
+ mSanitizeOnWrite = sanitize;
+ }
+
/** @hide */
public void dump() {
+ if (mActivityComponent == null) {
+ Log.i(TAG, "dump(): calling ensureData() first");
+ ensureData();
+ }
Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+ Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
final int N = getWindowNodeCount();
for (int i=0; i<N; i++) {
WindowNode node = getWindowNodeAt(i);
@@ -1515,6 +1595,16 @@ public class AssistStructure implements Parcelable {
if (node.isAssistBlocked()) {
Log.i(TAG, prefix + " BLOCKED");
}
+ AutoFillId autoFillId = node.getAutoFillId();
+ if (autoFillId == null) {
+ Log.i(TAG, prefix + " NO AUTO-FILL ID");
+ } else {
+ Log.i(TAG, prefix + "AutoFill info: id= " + autoFillId
+ + ", type=" + node.getAutoFillType()
+ + ", value=" + node.getAutoFillValue()
+ + ", sanitized=" + node.isSanitized());
+ }
+
final int NCHILDREN = node.getChildCount();
if (NCHILDREN > 0) {
Log.i(TAG, prefix + " Children:");
@@ -1589,10 +1679,12 @@ public class AssistStructure implements Parcelable {
}
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
if (mHaveData) {
// This object holds its data. We want to write a send channel that the
@@ -1609,10 +1701,12 @@ public class AssistStructure implements Parcelable {
public static final Parcelable.Creator<AssistStructure> CREATOR
= new Parcelable.Creator<AssistStructure>() {
+ @Override
public AssistStructure createFromParcel(Parcel in) {
return new AssistStructure(in);
}
+ @Override
public AssistStructure[] newArray(int size) {
return new AssistStructure[size];
}
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index 1e4f90d1ed07..bfaf23cd5fae 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -15,9 +15,7 @@
*/
package android.service.autofill;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_FILL;
-import static android.view.View.AUTO_FILL_FLAG_TYPE_SAVE;
-
+import android.annotation.CallSuper;
import android.annotation.SdkConstant;
import android.app.Activity;
import android.app.Service;
@@ -28,8 +26,8 @@ import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.util.Log;
-import android.view.autofill.AutoFillId;
import android.view.autofill.Dataset;
import android.view.autofill.FillResponse;
@@ -127,14 +125,22 @@ public abstract class AutoFillService extends Service {
private static final int MSG_AUTO_FILL_ACTIVITY = 3;
private static final int MSG_AUTHENTICATE_FILL_RESPONSE = 4;
private static final int MSG_AUTHENTICATE_DATASET = 5;
+ private static final int MSG_SAVE = 6;
private final IAutoFillService mInterface = new IAutoFillService.Stub() {
@Override
- public void autoFill(AssistStructure structure, IAutoFillServerCallback callback,
- int flags) {
+ public void autoFill(AssistStructure structure, IAutoFillServerCallback callback) {
mHandlerCaller
- .obtainMessageIOO(MSG_AUTO_FILL_ACTIVITY, flags, structure, callback)
+ .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, callback)
+ .sendToTarget();
+ }
+
+ @Override
+ public void save(AssistStructure structure, IAutoFillServerCallback callback,
+ Bundle extras) throws RemoteException {
+ mHandlerCaller
+ .obtainMessageOOO(MSG_SAVE, structure, callback, extras)
.sendToTarget();
}
@@ -175,10 +181,26 @@ public abstract class AutoFillService extends Service {
break;
} case MSG_AUTO_FILL_ACTIVITY: {
final SomeArgs args = (SomeArgs) msg.obj;
- final int flags = msg.arg1;
- final AssistStructure structure = (AssistStructure) args.arg1;
- final IAutoFillServerCallback callback = (IAutoFillServerCallback) args.arg2;
- requestAutoFill(callback, structure, flags);
+ try {
+ final AssistStructure structure = (AssistStructure) args.arg1;
+ final IAutoFillServerCallback callback =
+ (IAutoFillServerCallback) args.arg2;
+ handleAutoFill(structure, callback);
+ } finally {
+ args.recycle();
+ }
+ break;
+ } case MSG_SAVE: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ final AssistStructure structure = (AssistStructure) args.arg1;
+ final IAutoFillServerCallback callback =
+ (IAutoFillServerCallback) args.arg2;
+ final Bundle extras = (Bundle) args.arg3;
+ handleSave(structure, callback, extras);
+ } finally {
+ args.recycle();
+ }
break;
} case MSG_AUTHENTICATE_FILL_RESPONSE: {
final int flags = msg.arg1;
@@ -258,7 +280,7 @@ public abstract class AutoFillService extends Service {
* 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)})
+ * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
* to notify the result of the request.
*
* @param structure {@link Activity}'s view structure.
@@ -313,9 +335,8 @@ public abstract class AutoFillService extends Service {
if (DEBUG) Log.d(TAG, "onDatasetAuthenticationRequest(): flags=" + flags);
}
- // TODO(b/33197203): make it final and create another method classes could extend so it's
- // guaranteed to dump the pending callbacks?
@Override
+ @CallSuper
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mPendingCallbacks != null) {
pw.print("Number of pending callbacks: "); pw.println(mPendingCallbacks.size());
@@ -331,29 +352,23 @@ public abstract class AutoFillService extends Service {
}
}
- private void requestAutoFill(IAutoFillServerCallback callback, AssistStructure structure,
- int flags) {
- if (DEBUG) Log.d(TAG, "requestAutoFill(): flags=" + flags);
-
- if ((flags & AUTO_FILL_FLAG_TYPE_FILL) != 0) {
- final FillCallback fillCallback = new FillCallback(callback);
- if (DEBUG_PENDING_CALLBACKS) {
- addPendingCallback(fillCallback);
- }
- // TODO(b/33197203): hook up the cancelationSignal
- onFillRequest(structure, null, new CancellationSignal(), fillCallback);
- return;
- }
- if ((flags & AUTO_FILL_FLAG_TYPE_SAVE) != 0) {
- final SaveCallback saveCallback = new SaveCallback(callback);
- if (DEBUG_PENDING_CALLBACKS) {
- addPendingCallback(saveCallback);
- }
- onSaveRequest(structure, null, saveCallback);
- return;
+ private void handleAutoFill(AssistStructure structure, IAutoFillServerCallback callback) {
+ final FillCallback fillCallback = new FillCallback(callback);
+ if (DEBUG_PENDING_CALLBACKS) {
+ addPendingCallback(fillCallback);
}
+ // TODO(b/33197203): hook up the cancelationSignal
+ onFillRequest(structure, null, new CancellationSignal(), fillCallback);
+ return;
+ }
- Log.w(TAG, "invalid flags on requestAutoFill(): " + flags);
+ private void handleSave(AssistStructure structure, IAutoFillServerCallback callback,
+ Bundle extras) {
+ final SaveCallback saveCallback = new SaveCallback(callback);
+ if (DEBUG_PENDING_CALLBACKS) {
+ addPendingCallback(saveCallback);
+ }
+ onSaveRequest(structure, extras, saveCallback);
}
private void addPendingCallback(CallbackHelper.Dumpable callback) {
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
index ace5411ca0d3..088e6498a0d5 100644
--- a/core/java/android/service/autofill/IAutoFillManagerService.aidl
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -19,6 +19,7 @@ package android.service.autofill;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.autofill.AutoFillId;
+import android.view.autofill.AutoFillValue;
/**
* Mediator between apps being auto-filled and auto-fill service implementations.
@@ -30,6 +31,12 @@ oneway interface IAutoFillManagerService {
// Called by AutoFillManager (app).
void requestAutoFill(in AutoFillId id, in Rect bounds, int flags);
+ // Called by AutoFillManager (app).
+ void onValueChanged(in AutoFillId id, in AutoFillValue value);
+
+ // Called by ShellCommand only.
+ void requestAutoFillForUser(int userId);
+
// Called by ShellCommand only.
- void requestAutoFillForUser(int userId, int flags);
+ void requestSaveForUser(int userId);
}
diff --git a/core/java/android/service/autofill/IAutoFillServerCallback.aidl b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
index f7d5064e9e26..480438ac44ea 100644
--- a/core/java/android/service/autofill/IAutoFillServerCallback.aidl
+++ b/core/java/android/service/autofill/IAutoFillServerCallback.aidl
@@ -33,7 +33,7 @@ oneway interface IAutoFillServerCallback {
// TODO(b/33197203): document methods
void showResponse(in FillResponse response);
void showError(CharSequence message);
- void highlightSavedFields(in AutoFillId[] ids);
+ void onSaved();
void unlockFillResponse(int flags);
void unlockDataset(in Dataset dataset, int flags);
}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 3e8087b2a5a2..a4e6ebc996d3 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -27,7 +27,8 @@ import com.android.internal.os.IResultReceiver;
// TODO(b/33197203): document class and methods
oneway interface IAutoFillService {
// TODO(b/33197203): rename method to make them more consistent
- void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback, int flags);
+ void autoFill(in AssistStructure structure, in IAutoFillServerCallback callback);
+ void save(in AssistStructure structure, in IAutoFillServerCallback callback, in Bundle extras);
void authenticateFillResponse(in Bundle extras, int flags);
void authenticateDataset(in Bundle extras, int flags);
void onConnected();
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index e2fb588db212..9dd979599f5d 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -57,23 +57,18 @@ public final class SaveCallback implements Dumpable {
/**
* Notifies the Android System that an
- * {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle,
+ * {@link AutoFillService#onSaveRequest (android.app.assist.AssistStructure, Bundle,
* 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 calling the Android System.
*/
- 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");
- Preconditions.checkArgument(ids.length > 0, "ids cannot be empty");
+ public void onSuccess() {
+ if (DEBUG) Log.d(TAG, "onSuccess()");
synchronized (mCallback) {
checkNotRepliedYetLocked();
try {
- mCallback.highlightSavedFields(ids);
+ mCallback.onSaved();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
} finally {
@@ -94,8 +89,6 @@ public final class SaveCallback implements Dumpable {
public void onFailure(CharSequence message) {
if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
- Preconditions.checkArgument(message != null, "message cannot be null");
-
synchronized (mCallback) {
checkNotRepliedYetLocked();
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 48f3ac3f06f7..e9bbc2de26cc 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -119,8 +119,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
public static final String KEY_CONTENT = "content";
/** @hide */
public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
- /** @hide */
- 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 12ba30cf3308..e2eee9516142 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -39,7 +39,6 @@ import android.annotation.Nullable;
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;
@@ -4023,39 +4022,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int mLayerType = LAYER_TYPE_NONE;
Paint mLayerPaint;
-
- /**
- * 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): cannot conflict with flags defined on AutoFillManager until they're removed
- // (when save is refactored).
- public static final int AUTO_FILL_FLAG_TYPE_FILL = 0x10000000;
-
- /**
- * 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.
- */
- // TODO(b/33197203): cannot conflict with flags defined on AutoFillManager until they're removed
- // (when save is refactored).
- public static final int AUTO_FILL_FLAG_TYPE_SAVE = 0x20000000;
-
/**
* Set to true when drawing cache is enabled and cannot be created.
*
@@ -6914,7 +6880,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* fills in all data that can be inferred from the view itself.
*/
public void onProvideStructure(ViewStructure structure) {
- onProvideStructureForAssistOrAutoFill(structure, 0);
+ onProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -6925,19 +6891,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @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 #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
- onProvideStructureForAssistOrAutoFill(structure, flags);
+ onProvideStructureForAssistOrAutoFill(structure, true);
}
- 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.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
+ private void onProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
final int id = mID;
if (id != NO_ID && !isViewIdGenerated(id)) {
String pkg, type, entry;
@@ -7011,7 +6972,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* optimal implementation providing this data.
*/
public void onProvideVirtualStructure(ViewStructure structure) {
- onProvideVirtualStructureForAssistOrAutoFill(structure, 0);
+ onProvideVirtualStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -7026,14 +6987,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@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 #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) {
- onProvideVirtualStructureForAssistOrAutoFill(structure, flags);
+ onProvideVirtualStructureForAssistOrAutoFill(structure, true);
}
- private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, int flags) {
+ private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
// 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();
@@ -7041,7 +7002,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityNodeInfo info = createAccessibilityNodeInfo();
structure.setChildCount(1);
ViewStructure root = structure.newChild(0);
- populateVirtualStructure(root, provider, info, flags);
+ populateVirtualStructure(root, provider, info, forAutoFill);
info.recycle();
}
}
@@ -7051,9 +7012,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 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}).
+ * hierachy on {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
*/
@Nullable
public VirtualViewDelegate getAutoFillVirtualViewDelegate(
@@ -7109,12 +7068,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
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;
-
+ AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutoFill) {
structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
null, null, null);
Rect rect = structure.getTempRect();
@@ -7152,7 +7106,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
CharSequence cname = info.getClassName();
structure.setClassName(cname != null ? cname.toString() : null);
structure.setContentDescription(info.getContentDescription());
- if (!sanitized && (info.getText() != null || info.getError() != null)) {
+ if (!forAutoFill && (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.
@@ -7166,7 +7120,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
ViewStructure child = structure.newChild(i);
- populateVirtualStructure(child, provider, cinfo, flags);
+ populateVirtualStructure(child, provider, cinfo, forAutoFill);
cinfo.recycle();
}
}
@@ -7178,7 +7132,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #onProvideVirtualStructure}.
*/
public void dispatchProvideStructure(ViewStructure structure) {
- dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+ dispatchProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -7191,25 +7145,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}.
*
* @param structure Fill in with structured view data.
- * @param flags optional flags (see {@link #AUTO_FILL_FLAG_TYPE_FILL} and
- * {@link #AUTO_FILL_FLAG_TYPE_SAVE} for more info).
+ * @param flags optional flags (currently {@code 0}).
*/
public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
- dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+ dispatchProvideStructureForAssistOrAutoFill(structure, true);
}
- 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.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
-
+ private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
if (!blocked) {
if (forAutoFill) {
- onProvideAutoFillStructure(structure, flags);
- onProvideAutoFillVirtualStructure(structure, flags);
+ // NOTE: flags are not currently supported, hence 0
+ onProvideAutoFillStructure(structure, 0);
+ onProvideAutoFillVirtualStructure(structure, 0);
} else {
onProvideStructure(structure);
onProvideVirtualStructure(structure);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index ee92744ea1d0..b11b3d7ef44a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3207,7 +3207,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void dispatchProvideStructure(ViewStructure structure) {
super.dispatchProvideStructure(structure);
- dispatchProvideStructureForAssistOrAutoFill(structure, 0);
+ dispatchProvideStructureForAssistOrAutoFill(structure, false);
}
/**
@@ -3219,16 +3219,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
@Override
public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) {
super.dispatchProvideAutoFillStructure(structure, flags);
- dispatchProvideStructureForAssistOrAutoFill(structure, flags);
+ dispatchProvideStructureForAssistOrAutoFill(structure, true);
}
- 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.AUTO_FILL_FLAG_TYPE_FILL
- | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
-
+ private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked();
if (!blocked) {
@@ -3295,7 +3290,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Must explicitly check which recursive method to call.
if (forAutoFill) {
- child.dispatchProvideAutoFillStructure(cstructure, flags);
+ // NOTE: flags are not currently supported, hence 0
+ child.dispatchProvideAutoFillStructure(cstructure, 0);
} else {
child.dispatchProvideStructure(cstructure);
}
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 839e11c01303..5bae594b5659 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -29,6 +29,15 @@ import android.view.autofill.VirtualViewDelegate;
* View.onProvideStructure}.
*/
public abstract class ViewStructure {
+
+ /**
+ * Flag used when adding virtual views for auto-fill, it indicates the contents of the view
+ * (such as * {@link android.app.assist.AssistStructure.ViewNode#getText()} and
+ * {@link android.app.assist.AssistStructure.ViewNode#getAutoFillValue()})
+ * can be passed to the {@link android.service.autofill.AutoFillService}.
+ */
+ public static final int AUTO_FILL_FLAG_SANITIZED = 0x1;
+
/**
* Set the identifier for this view.
*
@@ -264,8 +273,14 @@ public abstract class ViewStructure {
/**
* Like {@link #newChild(int)}, but providing a {@code virtualId} to the child so it can be
* auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+ *
+ * @param index child index
+ * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
+ * AutoFillValue)}.
+ * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
*/
- public abstract ViewStructure newChild(int index, int virtualId);
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract ViewStructure newChild(int index, int virtualId, int flags);
/**
* Like {@link #newChild}, but allows the caller to asynchronously populate the returned
@@ -280,15 +295,36 @@ public abstract class ViewStructure {
/**
* Like {@link #asyncNewChild(int)}, but providing a {@code virtualId} to the child so it can be
* auto-filled by {@link VirtualViewDelegate#autoFill(int, AutoFillValue)}.
+ *
+ * @param index child index
+ * @param virtualId child's id as defined by {@link VirtualViewDelegate#autoFill(int,
+ * AutoFillValue)}.
+ * @param flags currently either {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}.
*/
- public abstract ViewStructure asyncNewChild(int index, int virtualId);
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags);
/**
* Sets the {@link AutoFillType} that can be used to auto-fill this node.
*/
+ // TODO(b/33197203, b/33802548): add CTS/unit test
public abstract void setAutoFillType(AutoFillType info);
/**
+ * Sets the {@link AutoFillValue} representing the current value of this node.
+ */
+ // TODO(b/33197203, b/33802548): add CTS/unit test
+ public abstract void setAutoFillValue(AutoFillValue value);
+
+ /**
+ * @hide
+ *
+ * TODO(b/33197203, b/33269702): temporary set it as not sanitized until
+ * AssistStructure automaticaly sets sanitization based on text coming from resources
+ */
+ public abstract void setSanitized(boolean sensitive);
+
+ /**
* Call when done populating a {@link ViewStructure} returned by
* {@link #asyncNewChild}.
*/
diff --git a/core/java/android/view/autofill/AutoFillId.java b/core/java/android/view/autofill/AutoFillId.java
index e9c1c3bccd72..3dbf5a8b0415 100644
--- a/core/java/android/view/autofill/AutoFillId.java
+++ b/core/java/android/view/autofill/AutoFillId.java
@@ -29,6 +29,7 @@ public final class AutoFillId implements Parcelable {
private boolean mVirtual;
private int mVirtualId;
+ // TODO(b/33197203): use factory and cache values, since they're immutable
/** @hide */
public AutoFillId(int id) {
mVirtual = false;
diff --git a/core/java/android/view/autofill/AutoFillManager.java b/core/java/android/view/autofill/AutoFillManager.java
index cf56e0e95aae..f2f522daa707 100644
--- a/core/java/android/view/autofill/AutoFillManager.java
+++ b/core/java/android/view/autofill/AutoFillManager.java
@@ -36,15 +36,11 @@ public final class AutoFillManager {
/**
* Flag used to show the auto-fill UI affordance for a view.
*/
- // TODO(b/33197203): cannot conflict with flags defined on View until they're removed (when
- // save is refactored).
public static final int FLAG_UPDATE_UI_SHOW = 0x1;
/**
* Flag used to hide the auto-fill UI affordance for a view.
*/
- // TODO(b/33197203): cannot conflict with flags defined on View until they're removed (when
- // save is refactored).
public static final int FLAG_UPDATE_UI_HIDE = 0x2;
private final IAutoFillManagerService mService;
@@ -71,7 +67,7 @@ public final class AutoFillManager {
final Rect bounds = new Rect();
view.getBoundsOnScreen(bounds);
- requestAutoFill(new AutoFillId(view.getAccessibilityViewId()), bounds, flags);
+ requestAutoFill(getAutoFillId(view), bounds, flags);
}
/**
@@ -92,7 +88,30 @@ public final class AutoFillManager {
requestAutoFill(new AutoFillId(parent.getAccessibilityViewId(), childId), bounds, flags);
}
+ /**
+ * Notifies the framework that the value of a view changed.
+ * @param view view whose value was updated
+ * @param value new value.
+ */
+ public void onValueChanged(View view, AutoFillValue value) {
+ // TODO(b/33197203): optimize it by not calling service when the view does not belong to
+ // the session.
+ final AutoFillId id = getAutoFillId(view);
+ if (DEBUG) Log.v(TAG, "onValueChanged(): id=" + id + ", value=" + value);
+ try {
+ mService.onValueChanged(id, value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private AutoFillId getAutoFillId(View view) {
+ return new AutoFillId(view.getAccessibilityViewId());
+ }
+
private void requestAutoFill(AutoFillId id, Rect bounds, int flags) {
+ // TODO(b/33197203): optimize it by not calling service when the view does not belong to
+ // the session.
if (DEBUG) {
Log.v(TAG, "requestAutoFill(): id=" + id + ", bounds=" + bounds + ", flags=" + flags);
}
diff --git a/core/java/android/view/autofill/AutoFillValue.java b/core/java/android/view/autofill/AutoFillValue.java
index c39f26b9b864..57b23ef4976e 100644
--- a/core/java/android/view/autofill/AutoFillValue.java
+++ b/core/java/android/view/autofill/AutoFillValue.java
@@ -126,6 +126,7 @@ public final class AutoFillValue implements Parcelable {
*
* <p>See {@link AutoFillType#isText()} for more info.
*/
+ // TODO(b/33197203): use cache
public static AutoFillValue forText(CharSequence value) {
return new AutoFillValue(value, 0, false);
}
diff --git a/core/java/android/view/autofill/VirtualViewDelegate.java b/core/java/android/view/autofill/VirtualViewDelegate.java
index 278bf4f34c36..e465c679e5f7 100644
--- a/core/java/android/view/autofill/VirtualViewDelegate.java
+++ b/core/java/android/view/autofill/VirtualViewDelegate.java
@@ -27,9 +27,10 @@ import android.view.ViewStructure;
*
* <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.
+ * add virtual children by calling {@link ViewStructure#newChild(int, int, int)} or
+ * {@link ViewStructure#asyncNewChild(int, 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
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 718070d0d49a..500f381e6bb8 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -32,6 +32,7 @@ import android.view.Gravity;
import android.view.SoundEffectConstants;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.autofill.AutoFillType;
@@ -564,6 +565,13 @@ public abstract class CompoundButton extends Button implements Checkable {
// TODO(b/33197203): add unit/CTS tests for auto-fill methods
@Override
+ public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutoFillStructure(structure, flags);
+ structure.setAutoFillValue(AutoFillValue.forToggle(isChecked()));
+ // TODO(b/33197203): add unit/CTS tests for auto-fill methods
+ }
+
+ @Override
public void autoFill(AutoFillValue value) {
setChecked(value.getToggleValue());
}
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 45fd9e6ef5a7..72dc1cc5c63c 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -24,6 +24,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStructure;
import android.view.autofill.AutoFillType;
import android.view.autofill.AutoFillValue;
@@ -406,6 +407,12 @@ public class RadioGroup extends LinearLayout {
// TODO(b/33197203): add unit/CTS tests for auto-fill methods
@Override
+ public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutoFillStructure(structure, flags);
+ structure.setAutoFillValue(AutoFillValue.forList(getCheckedRadioButtonId()));
+ }
+
+ @Override
public void autoFill(AutoFillValue value) {
final int index = value.getListValue();
final View child = getChildAt(index);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a7a8fb45d365..4a8ec94962d1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -711,6 +711,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text.
private int[] mAutoSizeTextSizesInPx;
+ // Watcher used to notify changes to auto-fill manager.
+ private AutoFillChangeWatcher mAutoFillChangeWatcher;
+
/**
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -9699,24 +9702,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
- onProvideAutoStructureForAssistOrAutoFill(structure, 0);
+ onProvideAutoStructureForAssistOrAutoFill(structure, false);
}
@Override
public void onProvideAutoFillStructure(ViewStructure structure, int flags) {
super.onProvideAutoFillStructure(structure, flags);
- onProvideAutoStructureForAssistOrAutoFill(structure, flags);
+ onProvideAutoStructureForAssistOrAutoFill(structure, true);
}
- 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 & AUTO_FILL_FLAG_TYPE_SAVE) != 0;
-
+ private void onProvideAutoStructureForAssistOrAutoFill(ViewStructure structure,
+ boolean forAutoFill) {
final boolean isPassword = hasPasswordTransformationMethod()
|| isPasswordInputType(getInputType());
- if (!isPassword || forAutoFillSave) {
+ if (forAutoFill) {
+ // TODO(b/33197203, b/33269702): temporary set it as not sanitized until
+ // AssistStructure automaticaly sets sanitization based on text coming from resources
+ structure.setSanitized(!isPassword);
+ if (mAutoFillChangeWatcher == null && isTextEditable()) {
+ mAutoFillChangeWatcher = new AutoFillChangeWatcher();
+ addTextChangedListener(mAutoFillChangeWatcher);
+ // TODO(b/33197203): remove mAutoFillValueListener auto-fill session is finished
+ }
+ }
+
+ if (!isPassword || forAutoFill) {
if (mLayout == null) {
assumeLayout();
}
@@ -9724,7 +9734,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int lineCount = layout.getLineCount();
if (lineCount <= 1) {
// Simple case: this is a single line.
- structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+ final CharSequence text = getText();
+ structure.setText(text, getSelectionStart(), getSelectionEnd());
+ if (forAutoFill && isTextEditable()) {
+ structure.setAutoFillValue(AutoFillValue.forText(text));
+ }
} else {
// Complex case: multi-line, could be scrolled or within a scroll container
// so some lines are not visible.
@@ -9781,6 +9795,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
text = text.subSequence(expandedTopChar, expandedBottomChar);
}
structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
+ if (forAutoFill && isTextEditable()) {
+ structure.setAutoFillValue(AutoFillValue.forText(text));
+ }
final int[] lineOffsets = new int[bottomLine - topLine + 1];
final int[] lineBaselines = new int[bottomLine - topLine + 1];
final int baselineOffset = getBaselineOffset();
@@ -9828,7 +9845,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final CharSequence text = value.getTextValue();
if (text != null && isTextEditable()) {
- setText(text);
+ if (mAutoFillChangeWatcher == null || mAutoFillChangeWatcher.mOnAutoFill) {
+ setText(text, mBufferType, true, 0);
+ } else {
+ // Must disable listener first so it's not triggered.
+ mAutoFillChangeWatcher.mOnAutoFill = true;
+ try {
+ setText(text, mBufferType, true, 0);
+ } finally {
+ mAutoFillChangeWatcher.mOnAutoFill = false;
+ }
+ }
}
}
@@ -11183,6 +11210,38 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ // TODO(b/33197203): implements SpanWatcher too?
+ private final class AutoFillChangeWatcher implements TextWatcher {
+
+ private boolean mOnAutoFill;
+ private final AutoFillManager mAfm = mContext.getSystemService(AutoFillManager.class);
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (mOnAutoFill) {
+ if (DEBUG_AUTOFILL) {
+ Log.v(LOG_TAG, "AutoFillChangeWatcher.afterTextChanged() skipped during "
+ + "autoFill(): s=" + s);
+ }
+ return;
+ }
+ if (mAfm != null) {
+ if (DEBUG_AUTOFILL) {
+ Log.v(LOG_TAG, "AutoFillChangeWatcher.afterTextChanged(): s=" + s);
+ }
+ mAfm.onValueChanged(TextView.this, AutoFillValue.forText(s));
+ }
+ }
+ }
+
private class ChangeWatcher implements TextWatcher, SpanWatcher {
private CharSequence mBeforeText;