summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/android/app/assist/AssistStructure.aidl5
-rw-r--r--core/java/android/app/assist/AssistStructure.java173
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java24
-rw-r--r--core/java/android/service/autofill/augmented/FillRequest.java17
-rw-r--r--core/java/android/view/autofill/AutofillId.java1
-rw-r--r--core/java/android/view/autofill/AutofillManager.java34
-rw-r--r--core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl6
-rw-r--r--core/tests/coretests/src/android/app/assist/AssistStructureTest.java43
10 files changed, 271 insertions, 35 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a145003b4bc6..1553214bc2eb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9212,6 +9212,7 @@ package android.service.autofill.augmented {
method @NonNull public android.content.ComponentName getActivityComponent();
method @NonNull public android.view.autofill.AutofillId getFocusedId();
method @NonNull public android.view.autofill.AutofillValue getFocusedValue();
+ method @Nullable public android.app.assist.AssistStructure.ViewNode getFocusedViewNode();
method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
method @Nullable public android.service.autofill.augmented.PresentationParams getPresentationParams();
method public int getTaskId();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4ef24ff18c48..1086577b0a39 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1714,6 +1714,7 @@ package android.service.autofill.augmented {
method @NonNull public android.content.ComponentName getActivityComponent();
method @NonNull public android.view.autofill.AutofillId getFocusedId();
method @NonNull public android.view.autofill.AutofillValue getFocusedValue();
+ method @Nullable public android.app.assist.AssistStructure.ViewNode getFocusedViewNode();
method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
method @Nullable public android.service.autofill.augmented.PresentationParams getPresentationParams();
method public int getTaskId();
@@ -2199,6 +2200,7 @@ package android.view.autofill {
ctor public AutofillId(int, int);
ctor public AutofillId(@NonNull android.view.autofill.AutofillId, long, int);
method public boolean equalsIgnoreSession(@Nullable android.view.autofill.AutofillId);
+ method public boolean isNonVirtual();
method @NonNull public static android.view.autofill.AutofillId withoutSession(@NonNull android.view.autofill.AutofillId);
}
diff --git a/core/java/android/app/assist/AssistStructure.aidl b/core/java/android/app/assist/AssistStructure.aidl
index ae0a34c92a0e..b997bbbe7d7c 100644
--- a/core/java/android/app/assist/AssistStructure.aidl
+++ b/core/java/android/app/assist/AssistStructure.aidl
@@ -17,3 +17,8 @@
package android.app.assist;
parcelable AssistStructure;
+
+/**
+ * {@hide}
+ */
+parcelable AssistStructure.ViewNodeParcelable;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index c15504cc0843..0f7fac4eefa5 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -271,7 +271,8 @@ public class AssistStructure implements Parcelable {
+ ", views=" + mNumWrittenViews
+ ", level=" + (mCurViewStackPos+levelAdj));
out.writeInt(VALIDATE_VIEW_TOKEN);
- int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
+ int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite,
+ mTmpMatrix, /*willWriteChildren=*/true);
mNumWrittenViews++;
// If the child has children, push it on the stack to write them next.
if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
@@ -724,11 +725,51 @@ public class AssistStructure implements Parcelable {
public ViewNode() {
}
+ ViewNode(@NonNull Parcel in) {
+ initializeFromParcelWithoutChildren(in, /*preader=*/null, /*tmpMatrix=*/null);
+ }
+
ViewNode(ParcelTransferReader reader, int nestingLevel) {
final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
reader.mNumReadViews++;
- final PooledStringReader preader = reader.mStringReader;
- mClassName = preader.readString();
+ initializeFromParcelWithoutChildren(in, Objects.requireNonNull(reader.mStringReader),
+ Objects.requireNonNull(reader.mTmpMatrix));
+ if ((mFlags & FLAGS_HAS_CHILDREN) != 0) {
+ final int numChildren = in.readInt();
+ if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) {
+ Log.d(TAG,
+ "Preparing to read " + numChildren
+ + " children: @ #" + reader.mNumReadViews
+ + ", level " + nestingLevel);
+ }
+ mChildren = new ViewNode[numChildren];
+ for (int i = 0; i < numChildren; i++) {
+ mChildren[i] = new ViewNode(reader, nestingLevel + 1);
+ }
+ }
+ }
+
+ private static void writeString(@NonNull Parcel out, @Nullable PooledStringWriter pwriter,
+ @Nullable String str) {
+ if (pwriter != null) {
+ pwriter.writeString(str);
+ } else {
+ out.writeString(str);
+ }
+ }
+
+ @Nullable
+ private static String readString(@NonNull Parcel in, @Nullable PooledStringReader preader) {
+ if (preader != null) {
+ return preader.readString();
+ }
+ return in.readString();
+ }
+
+ // This does not read the child nodes.
+ void initializeFromParcelWithoutChildren(Parcel in, @Nullable PooledStringReader preader,
+ @Nullable float[] tmpMatrix) {
+ mClassName = readString(in, preader);
mFlags = in.readInt();
final int flags = mFlags;
mAutofillFlags = in.readInt();
@@ -736,10 +777,10 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_ID) != 0) {
mId = in.readInt();
if (mId != View.NO_ID) {
- mIdEntry = preader.readString();
+ mIdEntry = readString(in, preader);
if (mIdEntry != null) {
- mIdType = preader.readString();
- mIdPackage = preader.readString();
+ mIdType = readString(in, preader);
+ mIdPackage = readString(in, preader);
}
}
}
@@ -784,10 +825,10 @@ public class AssistStructure implements Parcelable {
mMaxLength = in.readInt();
}
if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
- mTextIdEntry = preader.readString();
+ mTextIdEntry = readString(in, preader);
}
if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
- mHintIdEntry = preader.readString();
+ mHintIdEntry = readString(in, preader);
}
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
@@ -809,8 +850,11 @@ public class AssistStructure implements Parcelable {
}
if ((flags&FLAGS_HAS_MATRIX) != 0) {
mMatrix = new Matrix();
- in.readFloatArray(reader.mTmpMatrix);
- mMatrix.setValues(reader.mTmpMatrix);
+ if (tmpMatrix == null) {
+ tmpMatrix = new float[9];
+ }
+ in.readFloatArray(tmpMatrix);
+ mMatrix.setValues(tmpMatrix);
}
if ((flags&FLAGS_HAS_ELEVATION) != 0) {
mElevation = in.readFloat();
@@ -839,21 +883,16 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
mExtras = in.readBundle();
}
- if ((flags&FLAGS_HAS_CHILDREN) != 0) {
- final int NCHILDREN = in.readInt();
- if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
- "Preparing to read " + NCHILDREN
- + " children: @ #" + reader.mNumReadViews
- + ", level " + nestingLevel);
- mChildren = new ViewNode[NCHILDREN];
- for (int i=0; i<NCHILDREN; i++) {
- mChildren[i] = new ViewNode(reader, nestingLevel + 1);
- }
- }
}
- int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
- float[] tmpMatrix) {
+ /**
+ * This does not write the child nodes.
+ *
+ * @param willWriteChildren whether child nodes will be written to the parcel or not after
+ * calling this method.
+ */
+ int writeSelfToParcel(@NonNull Parcel out, @Nullable PooledStringWriter pwriter,
+ boolean sanitizeOnWrite, @Nullable float[] tmpMatrix, boolean willWriteChildren) {
// Guard used to skip non-sanitized data when writing for autofill.
boolean writeSensitive = true;
@@ -903,7 +942,7 @@ public class AssistStructure implements Parcelable {
if (mExtras != null) {
flags |= FLAGS_HAS_EXTRAS;
}
- if (mChildren != null) {
+ if (mChildren != null && willWriteChildren) {
flags |= FLAGS_HAS_CHILDREN;
}
if (mAutofillId != null) {
@@ -946,7 +985,7 @@ public class AssistStructure implements Parcelable {
autofillFlags |= AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY;
}
- pwriter.writeString(mClassName);
+ writeString(out, pwriter, mClassName);
int writtenFlags = flags;
if (autofillFlags != 0 && (mSanitized || !sanitizeOnWrite)) {
@@ -966,10 +1005,10 @@ public class AssistStructure implements Parcelable {
if ((flags&FLAGS_HAS_ID) != 0) {
out.writeInt(mId);
if (mId != View.NO_ID) {
- pwriter.writeString(mIdEntry);
+ writeString(out, pwriter, mIdEntry);
if (mIdEntry != null) {
- pwriter.writeString(mIdType);
- pwriter.writeString(mIdPackage);
+ writeString(out, pwriter, mIdType);
+ writeString(out, pwriter, mIdPackage);
}
}
}
@@ -1020,10 +1059,10 @@ public class AssistStructure implements Parcelable {
out.writeInt(mMaxLength);
}
if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
- pwriter.writeString(mTextIdEntry);
+ writeString(out, pwriter, mTextIdEntry);
}
if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
- pwriter.writeString(mHintIdEntry);
+ writeString(out, pwriter, mHintIdEntry);
}
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
@@ -1040,6 +1079,9 @@ public class AssistStructure implements Parcelable {
out.writeInt(mScrollY);
}
if ((flags&FLAGS_HAS_MATRIX) != 0) {
+ if (tmpMatrix == null) {
+ tmpMatrix = new float[9];
+ }
mMatrix.getValues(tmpMatrix);
out.writeFloatArray(tmpMatrix);
}
@@ -1695,6 +1737,57 @@ public class AssistStructure implements Parcelable {
}
/**
+ * A parcelable wrapper class around {@link ViewNode}.
+ *
+ * <p>This class, when parceled and unparceled, does not carry the child nodes.
+ *
+ * @hide
+ */
+ public static final class ViewNodeParcelable implements Parcelable {
+
+ @NonNull
+ private final ViewNode mViewNode;
+
+ public ViewNodeParcelable(@NonNull ViewNode viewNode) {
+ mViewNode = viewNode;
+ }
+
+ public ViewNodeParcelable(@NonNull Parcel in) {
+ mViewNode = new ViewNode(in);
+ }
+
+ @NonNull
+ public ViewNode getViewNode() {
+ return mViewNode;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ mViewNode.writeSelfToParcel(parcel, /*pwriter=*/null, /*sanitizeOnWrite=*/false,
+ /*tmpMatrix*/null, /*willWriteChildren=*/ false);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<ViewNodeParcelable> CREATOR =
+ new Parcelable.Creator<ViewNodeParcelable>() {
+ @Override
+ public ViewNodeParcelable createFromParcel(@NonNull Parcel in) {
+ return new ViewNodeParcelable(in);
+ }
+
+ @Override
+ public ViewNodeParcelable[] newArray(int size) {
+ return new ViewNodeParcelable[size];
+ }
+ };
+ }
+
+ /**
* POJO used to override some autofill-related values when the node is parcelized.
*
* @hide
@@ -1704,17 +1797,35 @@ public class AssistStructure implements Parcelable {
public AutofillValue value;
}
- static class ViewNodeBuilder extends ViewStructure {
+ /**
+ * @hide
+ */
+ public static class ViewNodeBuilder extends ViewStructure {
final AssistStructure mAssist;
final ViewNode mNode;
final boolean mAsync;
+ /**
+ * Used to instantiate a builder for a stand-alone {@link ViewNode} which is not associated
+ * to a properly created {@link AssistStructure}.
+ */
+ public ViewNodeBuilder() {
+ mAssist = new AssistStructure();
+ mNode = new ViewNode();
+ mAsync = false;
+ }
+
ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
mAssist = assist;
mNode = node;
mAsync = async;
}
+ @NonNull
+ public ViewNode getViewNode() {
+ return mNode;
+ }
+
@Override
public void setId(int id, String packageName, String typeName, String entryName) {
mNode.mId = id;
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index b34c2dceeee8..aeeaa97e2287 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -26,6 +26,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Service;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.ViewNodeParcelable;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
@@ -415,6 +417,8 @@ public abstract class AugmentedAutofillService extends Service {
@GuardedBy("mLock")
private AutofillValue mFocusedValue;
@GuardedBy("mLock")
+ private ViewNode mFocusedViewNode;
+ @GuardedBy("mLock")
private IFillCallback mCallback;
/**
@@ -532,6 +536,7 @@ public abstract class AugmentedAutofillService extends Service {
synchronized (mLock) {
mFocusedId = focusedId;
mFocusedValue = focusedValue;
+ mFocusedViewNode = null;
if (mCallback != null) {
try {
if (!mCallback.isCompleted()) {
@@ -570,6 +575,25 @@ public abstract class AugmentedAutofillService extends Service {
}
}
+ @Nullable
+ public ViewNode getFocusedViewNode() {
+ synchronized (mLock) {
+ if (mFocusedViewNode == null) {
+ try {
+ final ViewNodeParcelable viewNodeParcelable = mClient.getViewNodeParcelable(
+ mFocusedId);
+ if (viewNodeParcelable != null) {
+ mFocusedViewNode = viewNodeParcelable.getViewNode();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error getting the ViewNode of the focused view: " + e);
+ return null;
+ }
+ }
+ return mFocusedViewNode;
+ }
+ }
+
void logEvent(@ReportEvent int event) {
if (sVerbose) Log.v(TAG, "returnAndLogResult(): " + event);
long duration = -1;
diff --git a/core/java/android/service/autofill/augmented/FillRequest.java b/core/java/android/service/autofill/augmented/FillRequest.java
index 6927cf6541e0..f7f721a60aa0 100644
--- a/core/java/android/service/autofill/augmented/FillRequest.java
+++ b/core/java/android/service/autofill/augmented/FillRequest.java
@@ -19,6 +19,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.assist.AssistStructure.ViewNode;
import android.content.ComponentName;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.view.autofill.AutofillId;
@@ -81,6 +82,14 @@ public final class FillRequest {
}
/**
+ * Gets the current {@link ViewNode} information of the field that triggered the request.
+ */
+ @Nullable
+ public ViewNode getFocusedViewNode() {
+ return mProxy.getFocusedViewNode();
+ }
+
+ /**
* Gets the Smart Suggestions object used to embed the autofill UI.
*
* @return object used to embed the autofill UI, or {@code null} if not supported.
@@ -98,7 +107,7 @@ public final class FillRequest {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -151,10 +160,10 @@ public final class FillRequest {
}
@DataClass.Generated(
- time = 1577399314707L,
- codegenVersion = "1.0.14",
+ time = 1608160139217L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillRequest.java",
- inputSignatures = "private final @android.annotation.NonNull android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy mProxy\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\npublic int getTaskId()\npublic @android.annotation.NonNull android.content.ComponentName getActivityComponent()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getFocusedId()\npublic @android.annotation.NonNull android.view.autofill.AutofillValue getFocusedValue()\npublic @android.annotation.Nullable android.service.autofill.augmented.PresentationParams getPresentationParams()\n java.lang.String proxyToString()\nclass FillRequest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genBuilder=false, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.NonNull android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy mProxy\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\npublic int getTaskId()\npublic @android.annotation.NonNull android.content.ComponentName getActivityComponent()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getFocusedId()\npublic @android.annotation.NonNull android.view.autofill.AutofillValue getFocusedValue()\npublic @android.annotation.Nullable android.app.assist.AssistStructure.ViewNode getFocusedViewNode()\npublic @android.annotation.Nullable android.service.autofill.augmented.PresentationParams getPresentationParams()\n java.lang.String proxyToString()\nclass FillRequest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genBuilder=false, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 82d52b67c06a..ae145de21190 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -143,6 +143,7 @@ public final class AutofillId implements Parcelable {
*
* @hide
*/
+ @TestApi
public boolean isNonVirtual() {
return !isVirtualInt() && !isVirtualLong();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 364ae8186e54..794181e388cf 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -32,6 +32,9 @@ import android.annotation.RequiresFeature;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.ViewNodeBuilder;
+import android.app.assist.AssistStructure.ViewNodeParcelable;
import android.content.AutofillOptions;
import android.content.ClipData;
import android.content.ComponentName;
@@ -64,6 +67,8 @@ import android.view.Choreographer;
import android.view.ContentInfo;
import android.view.KeyEvent;
import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -3581,6 +3586,35 @@ public final class AutofillManager {
mAfm = new WeakReference<>(autofillManager);
}
+ @Nullable
+ @Override
+ public ViewNodeParcelable getViewNodeParcelable(@NonNull AutofillId id) {
+ final AutofillManager afm = mAfm.get();
+ if (afm == null) return null;
+
+ final View view = getView(afm, id);
+ if (view == null) {
+ Log.w(TAG, "getViewNodeParcelable(" + id + "): could not find view");
+ return null;
+ }
+ final ViewRootImpl root = view.getViewRootImpl();
+ if (root != null
+ && (root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) == 0) {
+ ViewNodeBuilder viewStructure = new ViewNodeBuilder();
+ viewStructure.setAutofillId(view.getAutofillId());
+ view.onProvideAutofillStructure(viewStructure, /* flags= */ 0);
+ // TODO(b/141703532): We don't call View#onProvideAutofillVirtualStructure for
+ // efficiency reason. But this also means we will return null for virtual views
+ // for now. We will add a new API to fetch the view node info of the virtual
+ // child view.
+ ViewNode viewNode = viewStructure.getViewNode();
+ if (viewNode != null && id.equals(viewNode.getAutofillId())) {
+ return new ViewNodeParcelable(viewNode);
+ }
+ }
+ return null;
+ }
+
@Override
public Rect getViewCoordinates(@NonNull AutofillId id) {
final AutofillManager afm = mAfm.get();
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 8526c1e443c8..7d08bcf34398 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -18,6 +18,7 @@ package android.view.autofill;
import java.util.List;
+import android.app.assist.AssistStructure;
import android.graphics.Rect;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
@@ -36,6 +37,11 @@ interface IAugmentedAutofillManagerClient {
Rect getViewCoordinates(in AutofillId id);
/**
+ * Gets the autofill view structure of the input field view.
+ */
+ AssistStructure.ViewNodeParcelable getViewNodeParcelable(in AutofillId id);
+
+ /**
* Autofills the activity with the contents of the values.
*/
void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index da386a6bac90..4609c23bbbd1 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -23,11 +23,14 @@ import static android.view.View.IMPORTANT_FOR_AUTOFILL_YES;
import static com.google.common.truth.Truth.assertThat;
import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.ViewNodeBuilder;
+import android.app.assist.AssistStructure.ViewNodeParcelable;
import android.content.Context;
import android.os.Parcel;
import android.os.SystemClock;
import android.text.InputFilter;
import android.util.Log;
+import android.view.View;
import android.view.autofill.AutofillId;
import android.widget.EditText;
import android.widget.FrameLayout;
@@ -219,6 +222,28 @@ public class AssistStructureTest {
}
}
+ @Test
+ public void testViewNodeParcelableForAutofill() {
+ Log.d(TAG, "Adding view with " + BIG_VIEW_SIZE + " chars");
+
+ View view = newBigView();
+ mActivity.addView(view);
+ waitUntilViewsAreLaidOff();
+
+ assertThat(view.getViewRootImpl()).isNotNull();
+ ViewNodeBuilder viewStructure = new ViewNodeBuilder();
+ viewStructure.setAutofillId(view.getAutofillId());
+ view.onProvideAutofillStructure(viewStructure, /* flags= */ 0);
+ ViewNodeParcelable viewNodeParcelable = new ViewNodeParcelable(viewStructure.getViewNode());
+
+ // Check properties on "original" view node.
+ assertBigView(viewNodeParcelable.getViewNode());
+
+ // Check properties on "cloned" view node.
+ ViewNodeParcelable clone = cloneThroughParcel(viewNodeParcelable);
+ assertBigView(clone.getViewNode());
+ }
+
private EditText newSmallView() {
EditText view = new EditText(mContext);
view.setText("I AM GROOT");
@@ -272,6 +297,24 @@ public class AssistStructureTest {
assertThat(hint.charAt(BIG_VIEW_SIZE - 1)).isEqualTo(BIG_VIEW_CHAR);
}
+ private ViewNodeParcelable cloneThroughParcel(ViewNodeParcelable viewNodeParcelable) {
+ Parcel parcel = Parcel.obtain();
+
+ try {
+ // Write to parcel
+ parcel.setDataPosition(0); // Validity Check
+ viewNodeParcelable.writeToParcel(parcel, NO_FLAGS);
+
+ // Read from parcel
+ parcel.setDataPosition(0);
+ ViewNodeParcelable clone = ViewNodeParcelable.CREATOR.createFromParcel(parcel);
+ assertThat(clone).isNotNull();
+ return clone;
+ } finally {
+ parcel.recycle();
+ }
+ }
+
private AssistStructure cloneThroughParcel(AssistStructure structure) {
Parcel parcel = Parcel.obtain();