blob: dd61f286c88ef68f28fa495bbbe7a88134f53a4d [file] [log] [blame]
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001package android.app.assist;
2
Felipe Lemef8a81742017-03-17 18:05:01 -07003import android.annotation.NonNull;
Philip P. Moltmann495cadd2017-03-10 16:45:02 -08004import android.annotation.Nullable;
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07005import android.app.Activity;
Dianne Hackborn16036f22015-06-22 14:05:51 -07006import android.content.ComponentName;
Svetoslav Ganov24c90452017-12-27 15:17:14 -08007import android.content.Context;
Dianne Hackborn70d8be72015-06-23 19:33:02 +00008import android.graphics.Matrix;
Dianne Hackborn16036f22015-06-22 14:05:51 -07009import android.graphics.Rect;
Felipe Leme4711ed92017-04-21 16:47:18 -070010import android.net.Uri;
Dianne Hackborn3e8125b2015-07-22 17:02:10 -070011import android.os.BadParcelableException;
Dianne Hackborn16036f22015-06-22 14:05:51 -070012import android.os.Binder;
13import android.os.Bundle;
14import android.os.IBinder;
Felipe Lemeb4ca7012017-03-22 18:30:07 -070015import android.os.LocaleList;
Dianne Hackborn69c6adc2015-06-02 10:52:59 -070016import android.os.Parcel;
17import android.os.Parcelable;
Dianne Hackborn16036f22015-06-22 14:05:51 -070018import android.os.PooledStringReader;
19import android.os.PooledStringWriter;
20import android.os.RemoteException;
21import android.os.SystemClock;
Felipe Leme73fedac2017-05-12 09:52:07 -070022import android.service.autofill.FillRequest;
Dianne Hackborn16036f22015-06-22 14:05:51 -070023import android.text.TextUtils;
24import android.util.Log;
Felipe Leme25bf7872017-03-28 15:32:29 -070025import android.util.Pair;
Dianne Hackborn16036f22015-06-22 14:05:51 -070026import android.view.View;
felipeal53308c12018-02-07 14:43:30 +010027import android.view.View.AutofillImportance;
Dianne Hackborn16036f22015-06-22 14:05:51 -070028import android.view.ViewRootImpl;
Felipe Lemec3241002017-02-15 12:55:11 -080029import android.view.ViewStructure;
Felipe Leme25bf7872017-03-28 15:32:29 -070030import android.view.ViewStructure.HtmlInfo;
31import android.view.ViewStructure.HtmlInfo.Builder;
Dianne Hackborn16036f22015-06-22 14:05:51 -070032import android.view.WindowManager;
33import android.view.WindowManagerGlobal;
Felipe Leme640f30a2017-03-06 15:44:06 -080034import android.view.autofill.AutofillId;
35import android.view.autofill.AutofillValue;
Dianne Hackborn16036f22015-06-22 14:05:51 -070036
Felipe Leme5dc45ca2018-01-03 09:02:27 -080037import com.android.internal.util.Preconditions;
38
Dianne Hackborn16036f22015-06-22 14:05:51 -070039import java.util.ArrayList;
Felipe Leme16aafc32017-02-27 13:41:37 -080040import java.util.Arrays;
Felipe Leme09a70622017-04-27 15:24:19 -070041import java.util.List;
Dianne Hackborn69c6adc2015-06-02 10:52:59 -070042
43/**
Laura Davis43e75d92018-08-10 15:46:06 -070044 * <p>This API automatically creates assist data from the platform's
45 * implementation of assist and autofill.
Felipe Leme30e9b262017-04-21 11:29:30 -070046 *
Felipe Leme2f6fc722017-05-31 11:57:46 -070047 * <p>The structure is used for assist purposes when created by
Felipe Leme30e9b262017-04-21 11:29:30 -070048 * {@link android.app.Activity#onProvideAssistData}, {@link View#onProvideStructure(ViewStructure)},
49 * or {@link View#onProvideVirtualStructure(ViewStructure)}.
50 *
Laura Davis43e75d92018-08-10 15:46:06 -070051 * <p>The structure is also used for autofill purposes when created by
Felipe Leme30e9b262017-04-21 11:29:30 -070052 * {@link View#onProvideAutofillStructure(ViewStructure, int)},
53 * or {@link View#onProvideAutofillVirtualStructure(ViewStructure, int)}.
54 *
Laura Davis43e75d92018-08-10 15:46:06 -070055 * <p>For performance reasons, some properties of the assist data might only be available for
56 * assist or autofill purposes. In those cases, a property's availability will be documented
57 * in its javadoc.
58 *
59 * <p>To learn about using Autofill in your app, read the
60 * <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
Dianne Hackborn69c6adc2015-06-02 10:52:59 -070061 */
Dianne Hackborn16036f22015-06-22 14:05:51 -070062public class AssistStructure implements Parcelable {
63 static final String TAG = "AssistStructure";
Dianne Hackborn69c6adc2015-06-02 10:52:59 -070064
Dianne Hackborn782d4982015-07-08 17:36:37 -070065 static final boolean DEBUG_PARCEL = false;
Dianne Hackborn3e8125b2015-07-22 17:02:10 -070066 static final boolean DEBUG_PARCEL_CHILDREN = false;
Dianne Hackborn782d4982015-07-08 17:36:37 -070067 static final boolean DEBUG_PARCEL_TREE = false;
68
Dianne Hackborn3e8125b2015-07-22 17:02:10 -070069 static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
70 static final int VALIDATE_VIEW_TOKEN = 0x22222222;
71
Dianne Hackborn16036f22015-06-22 14:05:51 -070072 boolean mHaveData;
73
74 ComponentName mActivityComponent;
Amith Yamasani858f98d2017-02-22 12:59:53 -080075 private boolean mIsHomeActivity;
Felipe Leme0aa4c502017-04-26 12:36:01 -070076 private int mFlags;
Dianne Hackborn16036f22015-06-22 14:05:51 -070077
78 final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
79
80 final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
81
82 SendChannel mSendChannel;
83 IBinder mReceiveChannel;
84
85 Rect mTmpRect = new Rect();
86
Felipe Leme0200d9e2017-01-24 15:10:26 -080087 boolean mSanitizeOnWrite = false;
Amith Yamasani858f98d2017-02-22 12:59:53 -080088 private long mAcquisitionStartTime;
89 private long mAcquisitionEndTime;
Felipe Leme0200d9e2017-01-24 15:10:26 -080090
Dianne Hackborn16036f22015-06-22 14:05:51 -070091 static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
92 static final String DESCRIPTOR = "android.app.AssistStructure";
93
Amith Yamasani858f98d2017-02-22 12:59:53 -080094 /** @hide */
95 public void setAcquisitionStartTime(long acquisitionStartTime) {
96 mAcquisitionStartTime = acquisitionStartTime;
97 }
98
99 /** @hide */
100 public void setAcquisitionEndTime(long acquisitionEndTime) {
101 mAcquisitionEndTime = acquisitionEndTime;
102 }
103
104 /**
105 * @hide
106 * Set the home activity flag.
107 */
108 public void setHomeActivity(boolean isHomeActivity) {
109 mIsHomeActivity = isHomeActivity;
110 }
111
112 /**
113 * Returns the time when the activity started generating assist data to build the
114 * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
115 *
116 * @see #getAcquisitionEndTime()
117 * @return Returns the acquisition start time of the assist data, in milliseconds.
118 */
119 public long getAcquisitionStartTime() {
120 ensureData();
121 return mAcquisitionStartTime;
122 }
123
124 /**
125 * Returns the time when the activity finished generating assist data to build the
126 * AssistStructure. The time is as specified by {@link SystemClock#uptimeMillis()}.
127 *
128 * @see #getAcquisitionStartTime()
129 * @return Returns the acquisition end time of the assist data, in milliseconds.
130 */
131 public long getAcquisitionEndTime() {
132 ensureData();
133 return mAcquisitionEndTime;
134 }
135
Dianne Hackborn782d4982015-07-08 17:36:37 -0700136 final static class SendChannel extends Binder {
137 volatile AssistStructure mAssistStructure;
138
139 SendChannel(AssistStructure as) {
140 mAssistStructure = as;
141 }
142
Dianne Hackborn16036f22015-06-22 14:05:51 -0700143 @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
144 throws RemoteException {
145 if (code == TRANSACTION_XFER) {
Dianne Hackborn782d4982015-07-08 17:36:37 -0700146 AssistStructure as = mAssistStructure;
147 if (as == null) {
148 return true;
149 }
150
Dianne Hackborn16036f22015-06-22 14:05:51 -0700151 data.enforceInterface(DESCRIPTOR);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700152 IBinder token = data.readStrongBinder();
153 if (DEBUG_PARCEL) Log.d(TAG, "Request for data on " + as
154 + " using token " + token);
155 if (token != null) {
156 if (DEBUG_PARCEL) Log.d(TAG, "Resuming partial write of " + token);
157 if (token instanceof ParcelTransferWriter) {
158 ParcelTransferWriter xfer = (ParcelTransferWriter)token;
159 xfer.writeToParcel(as, reply);
160 return true;
161 }
162 Log.w(TAG, "Caller supplied bad token type: " + token);
163 // Don't write anything; this is the end of the data.
164 return true;
165 }
166 //long start = SystemClock.uptimeMillis();
167 ParcelTransferWriter xfer = new ParcelTransferWriter(as, reply);
168 xfer.writeToParcel(as, reply);
169 //Log.i(TAG, "Time to parcel: " + (SystemClock.uptimeMillis()-start) + "ms");
Dianne Hackborn16036f22015-06-22 14:05:51 -0700170 return true;
171 } else {
172 return super.onTransact(code, data, reply, flags);
173 }
174 }
175 }
176
Dianne Hackborn782d4982015-07-08 17:36:37 -0700177 final static class ViewStackEntry {
178 ViewNode node;
179 int curChild;
180 int numChildren;
181 }
182
183 final static class ParcelTransferWriter extends Binder {
184 final boolean mWriteStructure;
185 int mCurWindow;
186 int mNumWindows;
187 final ArrayList<ViewStackEntry> mViewStack = new ArrayList<>();
188 ViewStackEntry mCurViewStackEntry;
189 int mCurViewStackPos;
190 int mNumWrittenWindows;
191 int mNumWrittenViews;
192 final float[] mTmpMatrix = new float[9];
Felipe Leme0200d9e2017-01-24 15:10:26 -0800193 final boolean mSanitizeOnWrite;
Dianne Hackborn782d4982015-07-08 17:36:37 -0700194
195 ParcelTransferWriter(AssistStructure as, Parcel out) {
Felipe Leme0200d9e2017-01-24 15:10:26 -0800196 mSanitizeOnWrite = as.mSanitizeOnWrite;
Dianne Hackborn782d4982015-07-08 17:36:37 -0700197 mWriteStructure = as.waitForReady();
198 ComponentName.writeToParcel(as.mActivityComponent, out);
Felipe Leme0aa4c502017-04-26 12:36:01 -0700199 out.writeInt(as.mFlags);
Amith Yamasani858f98d2017-02-22 12:59:53 -0800200 out.writeLong(as.mAcquisitionStartTime);
201 out.writeLong(as.mAcquisitionEndTime);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700202 mNumWindows = as.mWindowNodes.size();
203 if (mWriteStructure && mNumWindows > 0) {
204 out.writeInt(mNumWindows);
205 } else {
206 out.writeInt(0);
207 }
208 }
209
210 void writeToParcel(AssistStructure as, Parcel out) {
211 int start = out.dataPosition();
212 mNumWrittenWindows = 0;
213 mNumWrittenViews = 0;
214 boolean more = writeToParcelInner(as, out);
215 Log.i(TAG, "Flattened " + (more ? "partial" : "final") + " assist data: "
216 + (out.dataPosition() - start)
217 + " bytes, containing " + mNumWrittenWindows + " windows, "
218 + mNumWrittenViews + " views");
219 }
220
221 boolean writeToParcelInner(AssistStructure as, Parcel out) {
222 if (mNumWindows == 0) {
223 return false;
224 }
225 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringWriter @ " + out.dataPosition());
226 PooledStringWriter pwriter = new PooledStringWriter(out);
227 while (writeNextEntryToParcel(as, out, pwriter)) {
Dianne Hackborn86cbc2b2015-07-28 18:07:13 -0700228 // If the parcel is above the IPC limit, then we are getting too
Dianne Hackborn782d4982015-07-08 17:36:37 -0700229 // large for a single IPC so stop here and let the caller come back when it
230 // is ready for more.
Dianne Hackborn86cbc2b2015-07-28 18:07:13 -0700231 if (out.dataSize() > IBinder.MAX_IPC_SIZE) {
Dianne Hackborn782d4982015-07-08 17:36:37 -0700232 if (DEBUG_PARCEL) Log.d(TAG, "Assist data size is " + out.dataSize()
233 + " @ pos " + out.dataPosition() + "; returning partial result");
234 out.writeInt(0);
235 out.writeStrongBinder(this);
236 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
237 + out.dataPosition() + ", size " + pwriter.getStringCount());
238 pwriter.finish();
239 return true;
240 }
241 }
242 if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
243 + out.dataPosition() + ", size " + pwriter.getStringCount());
244 pwriter.finish();
245 mViewStack.clear();
246 return false;
247 }
248
249 void pushViewStackEntry(ViewNode node, int pos) {
250 ViewStackEntry entry;
251 if (pos >= mViewStack.size()) {
252 entry = new ViewStackEntry();
253 mViewStack.add(entry);
254 if (DEBUG_PARCEL_TREE) Log.d(TAG, "New stack entry at " + pos + ": " + entry);
255 } else {
256 entry = mViewStack.get(pos);
257 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry);
258 }
259 entry.node = node;
260 entry.numChildren = node.getChildCount();
261 entry.curChild = 0;
262 mCurViewStackEntry = entry;
263 }
264
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700265 void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
266 if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
267 + ", windows=" + mNumWrittenWindows
268 + ", views=" + mNumWrittenViews
269 + ", level=" + (mCurViewStackPos+levelAdj));
270 out.writeInt(VALIDATE_VIEW_TOKEN);
Felipe Leme0200d9e2017-01-24 15:10:26 -0800271 int flags = child.writeSelfToParcel(out, pwriter, mSanitizeOnWrite, mTmpMatrix);
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700272 mNumWrittenViews++;
273 // If the child has children, push it on the stack to write them next.
274 if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
275 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
276 "Preparing to write " + child.mChildren.length
277 + " children: @ #" + mNumWrittenViews
278 + ", level " + (mCurViewStackPos+levelAdj));
279 out.writeInt(child.mChildren.length);
280 int pos = ++mCurViewStackPos;
281 pushViewStackEntry(child, pos);
282 }
283 }
284
Dianne Hackborn782d4982015-07-08 17:36:37 -0700285 boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
286 // Write next view node if appropriate.
287 if (mCurViewStackEntry != null) {
288 if (mCurViewStackEntry.curChild < mCurViewStackEntry.numChildren) {
289 // Write the next child in the current view.
290 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing child #"
291 + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
292 ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
293 mCurViewStackEntry.curChild++;
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700294 writeView(child, out, pwriter, 1);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700295 return true;
296 }
297
298 // We are done writing children of the current view; pop off the stack.
299 do {
300 int pos = --mCurViewStackPos;
301 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node
302 + "; popping up to " + pos);
303 if (pos < 0) {
304 // Reached the last view; step to next window.
305 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!");
306 mCurViewStackEntry = null;
307 break;
308 }
309 mCurViewStackEntry = mViewStack.get(pos);
310 } while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren);
311 return true;
312 }
313
314 // Write the next window if appropriate.
315 int pos = mCurWindow;
316 if (pos < mNumWindows) {
317 WindowNode win = as.mWindowNodes.get(pos);
318 mCurWindow++;
319 if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
320 + ", windows=" + mNumWrittenWindows
321 + ", views=" + mNumWrittenViews);
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700322 out.writeInt(VALIDATE_WINDOW_TOKEN);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700323 win.writeSelfToParcel(out, pwriter, mTmpMatrix);
324 mNumWrittenWindows++;
325 ViewNode root = win.mRoot;
326 mCurViewStackPos = 0;
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700327 if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
328 writeView(root, out, pwriter, 0);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700329 return true;
330 }
331
332 return false;
333 }
334 }
335
336 final class ParcelTransferReader {
337 final float[] mTmpMatrix = new float[9];
338 PooledStringReader mStringReader;
339
340 int mNumReadWindows;
341 int mNumReadViews;
342
343 private final IBinder mChannel;
344 private IBinder mTransferToken;
345 private Parcel mCurParcel;
346
347 ParcelTransferReader(IBinder channel) {
348 mChannel = channel;
349 }
350
351 void go() {
352 fetchData();
353 mActivityComponent = ComponentName.readFromParcel(mCurParcel);
Felipe Leme0aa4c502017-04-26 12:36:01 -0700354 mFlags = mCurParcel.readInt();
Amith Yamasani858f98d2017-02-22 12:59:53 -0800355 mAcquisitionStartTime = mCurParcel.readLong();
356 mAcquisitionEndTime = mCurParcel.readLong();
Dianne Hackborn782d4982015-07-08 17:36:37 -0700357 final int N = mCurParcel.readInt();
358 if (N > 0) {
359 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
360 + mCurParcel.dataPosition());
361 mStringReader = new PooledStringReader(mCurParcel);
362 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
363 + mStringReader.getStringCount());
364 for (int i=0; i<N; i++) {
365 mWindowNodes.add(new WindowNode(this));
366 }
367 }
368 if (DEBUG_PARCEL) Log.d(TAG, "Finished reading: at " + mCurParcel.dataPosition()
369 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
370 + ", views=" + mNumReadViews);
Felipe Lemec52b6ea2017-11-17 08:42:00 -0800371 mCurParcel.recycle();
372 mCurParcel = null; // Parcel cannot be used after recycled.
Dianne Hackborn782d4982015-07-08 17:36:37 -0700373 }
374
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700375 Parcel readParcel(int validateToken, int level) {
Dianne Hackborn782d4982015-07-08 17:36:37 -0700376 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
377 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700378 + ", views=" + mNumReadViews + ", level=" + level);
379 int token = mCurParcel.readInt();
380 if (token != 0) {
381 if (token != validateToken) {
382 throw new BadParcelableException("Got token " + Integer.toHexString(token)
383 + ", expected token " + Integer.toHexString(validateToken));
384 }
Dianne Hackborn782d4982015-07-08 17:36:37 -0700385 return mCurParcel;
386 }
387 // We have run out of partial data, need to read another batch.
388 mTransferToken = mCurParcel.readStrongBinder();
389 if (mTransferToken == null) {
390 throw new IllegalStateException(
391 "Reached end of partial data without transfer token");
392 }
393 if (DEBUG_PARCEL) Log.d(TAG, "Ran out of partial data at "
394 + mCurParcel.dataPosition() + ", token " + mTransferToken);
395 fetchData();
396 if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
397 + mCurParcel.dataPosition());
398 mStringReader = new PooledStringReader(mCurParcel);
399 if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
400 + mStringReader.getStringCount());
401 if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
402 + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
403 + ", views=" + mNumReadViews);
404 mCurParcel.readInt();
405 return mCurParcel;
406 }
407
408 private void fetchData() {
409 Parcel data = Parcel.obtain();
Dianne Hackborn782d4982015-07-08 17:36:37 -0700410 try {
Felipe Lemec52b6ea2017-11-17 08:42:00 -0800411 data.writeInterfaceToken(DESCRIPTOR);
412 data.writeStrongBinder(mTransferToken);
413 if (DEBUG_PARCEL) Log.d(TAG, "Requesting data with token " + mTransferToken);
414 if (mCurParcel != null) {
415 mCurParcel.recycle();
416 }
417 mCurParcel = Parcel.obtain();
418 try {
419 mChannel.transact(TRANSACTION_XFER, data, mCurParcel, 0);
420 } catch (RemoteException e) {
421 Log.w(TAG, "Failure reading AssistStructure data", e);
422 throw new IllegalStateException("Failure reading AssistStructure data: " + e);
423 }
424 } finally {
425 data.recycle();
Dianne Hackborn782d4982015-07-08 17:36:37 -0700426 }
Dianne Hackborn782d4982015-07-08 17:36:37 -0700427 mNumReadWindows = mNumReadViews = 0;
428 }
429 }
430
Dianne Hackborn16036f22015-06-22 14:05:51 -0700431 final static class ViewNodeText {
432 CharSequence mText;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700433 float mTextSize;
434 int mTextStyle;
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700435 int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
436 int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
437 int mTextSelectionStart;
438 int mTextSelectionEnd;
439 int[] mLineCharOffsets;
440 int[] mLineBaselines;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700441 String mHint;
442
443 ViewNodeText() {
444 }
445
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700446 boolean isSimple() {
447 return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
448 && mTextSelectionStart == 0 && mTextSelectionEnd == 0
449 && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700450 }
451
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700452 ViewNodeText(Parcel in, boolean simple) {
453 mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
454 mTextSize = in.readFloat();
455 mTextStyle = in.readInt();
456 mTextColor = in.readInt();
457 if (!simple) {
458 mTextBackgroundColor = in.readInt();
459 mTextSelectionStart = in.readInt();
460 mTextSelectionEnd = in.readInt();
461 mLineCharOffsets = in.createIntArray();
462 mLineBaselines = in.createIntArray();
463 mHint = in.readString();
464 }
465 }
466
Felipe Leme0200d9e2017-01-24 15:10:26 -0800467 void writeToParcel(Parcel out, boolean simple, boolean writeSensitive) {
468 TextUtils.writeToParcel(writeSensitive ? mText : "", out, 0);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700469 out.writeFloat(mTextSize);
470 out.writeInt(mTextStyle);
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700471 out.writeInt(mTextColor);
472 if (!simple) {
473 out.writeInt(mTextBackgroundColor);
474 out.writeInt(mTextSelectionStart);
475 out.writeInt(mTextSelectionEnd);
476 out.writeIntArray(mLineCharOffsets);
477 out.writeIntArray(mLineBaselines);
478 out.writeString(mHint);
479 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700480 }
481 }
482
483 /**
484 * Describes a window in the assist data.
485 */
486 static public class WindowNode {
487 final int mX;
488 final int mY;
489 final int mWidth;
490 final int mHeight;
491 final CharSequence mTitle;
492 final int mDisplayId;
493 final ViewNode mRoot;
494
Svet Ganovfd31f852017-04-26 15:54:27 -0700495 WindowNode(AssistStructure assist, ViewRootImpl root, boolean forAutoFill, int flags) {
Dianne Hackborn16036f22015-06-22 14:05:51 -0700496 View view = root.getView();
497 Rect rect = new Rect();
498 view.getBoundsOnScreen(rect);
499 mX = rect.left - view.getLeft();
500 mY = rect.top - view.getTop();
501 mWidth = rect.width();
502 mHeight = rect.height();
503 mTitle = root.getTitle();
504 mDisplayId = root.getDisplayId();
505 mRoot = new ViewNode();
Felipe Leme6d553872016-12-08 17:13:25 -0800506
Felipe Leme33791fd2017-02-16 08:07:56 -0800507 ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
Felipe Leme71377a42017-02-14 18:16:11 -0800508 if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
Felipe Leme6d553872016-12-08 17:13:25 -0800509 if (forAutoFill) {
Svetoslav Ganov24c90452017-12-27 15:17:14 -0800510 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
511 view.onProvideAutofillStructure(builder, viewFlags);
Felipe Leme1ca634a2016-11-28 17:21:21 -0800512 } else {
Felipe Leme71377a42017-02-14 18:16:11 -0800513 // This is a secure window, so it doesn't want a screenshot, and that
514 // means we should also not copy out its view hierarchy for Assist
Felipe Leme6d553872016-12-08 17:13:25 -0800515 view.onProvideStructure(builder);
Felipe Leme71377a42017-02-14 18:16:11 -0800516 builder.setAssistBlocked(true);
517 return;
Felipe Leme1ca634a2016-11-28 17:21:21 -0800518 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700519 }
Felipe Leme6d553872016-12-08 17:13:25 -0800520 if (forAutoFill) {
Svetoslav Ganov24c90452017-12-27 15:17:14 -0800521 final int viewFlags = resolveViewAutofillFlags(view.getContext(), flags);
522 view.dispatchProvideAutofillStructure(builder, viewFlags);
Felipe Leme1ca634a2016-11-28 17:21:21 -0800523 } else {
Felipe Leme6d553872016-12-08 17:13:25 -0800524 view.dispatchProvideStructure(builder);
Felipe Leme1ca634a2016-11-28 17:21:21 -0800525 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700526 }
527
Dianne Hackborn782d4982015-07-08 17:36:37 -0700528 WindowNode(ParcelTransferReader reader) {
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700529 Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700530 reader.mNumReadWindows++;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700531 mX = in.readInt();
532 mY = in.readInt();
533 mWidth = in.readInt();
534 mHeight = in.readInt();
535 mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
536 mDisplayId = in.readInt();
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700537 mRoot = new ViewNode(reader, 0);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700538 }
539
Svetoslav Ganov24c90452017-12-27 15:17:14 -0800540 int resolveViewAutofillFlags(Context context, int fillRequestFlags) {
541 return (fillRequestFlags & FillRequest.FLAG_MANUAL_REQUEST) != 0
542 || context.isAutofillCompatibilityEnabled()
543 ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
544 }
545
Dianne Hackborn782d4982015-07-08 17:36:37 -0700546 void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
Dianne Hackborn16036f22015-06-22 14:05:51 -0700547 out.writeInt(mX);
548 out.writeInt(mY);
549 out.writeInt(mWidth);
550 out.writeInt(mHeight);
551 TextUtils.writeToParcel(mTitle, out, 0);
552 out.writeInt(mDisplayId);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700553 }
554
555 /**
556 * Returns the left edge of the window, in pixels, relative to the left
557 * edge of the screen.
558 */
559 public int getLeft() {
560 return mX;
561 }
562
563 /**
564 * Returns the top edge of the window, in pixels, relative to the top
565 * edge of the screen.
566 */
567 public int getTop() {
568 return mY;
569 }
570
571 /**
572 * Returns the total width of the window in pixels.
573 */
574 public int getWidth() {
575 return mWidth;
576 }
577
578 /**
579 * Returns the total height of the window in pixels.
580 */
581 public int getHeight() {
582 return mHeight;
583 }
584
585 /**
586 * Returns the title associated with the window, if it has one.
587 */
588 public CharSequence getTitle() {
589 return mTitle;
590 }
591
592 /**
593 * Returns the ID of the display this window is on, for use with
594 * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
595 */
596 public int getDisplayId() {
597 return mDisplayId;
598 }
599
600 /**
601 * Returns the {@link ViewNode} containing the root content of the window.
602 */
603 public ViewNode getRootViewNode() {
604 return mRoot;
605 }
606 }
607
608 /**
609 * Describes a single view in the assist data.
610 */
611 static public class ViewNode {
612 /**
613 * Magic value for text color that has not been defined, which is very unlikely
614 * to be confused with a real text color.
615 */
616 public static final int TEXT_COLOR_UNDEFINED = 1;
617
618 public static final int TEXT_STYLE_BOLD = 1<<0;
619 public static final int TEXT_STYLE_ITALIC = 1<<1;
620 public static final int TEXT_STYLE_UNDERLINE = 1<<2;
621 public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
622
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000623 int mId = View.NO_ID;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700624 String mIdPackage;
625 String mIdType;
626 String mIdEntry;
Felipe Leme16aafc32017-02-27 13:41:37 -0800627
Felipe Leme85d1c2d2017-04-21 08:56:04 -0700628 // TODO: once we have more flags, it might be better to store the individual
Felipe Leme6d553872016-12-08 17:13:25 -0800629 // fields (viewId and childId) of the field.
Felipe Leme640f30a2017-03-06 15:44:06 -0800630 AutofillId mAutofillId;
Felipe Leme30e9b262017-04-21 11:29:30 -0700631 @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
Philip P. Moltmann81192b42017-03-29 13:58:59 -0700632 @Nullable String[] mAutofillHints;
Felipe Leme640f30a2017-03-06 15:44:06 -0800633 AutofillValue mAutofillValue;
Felipe Leme7e4c2052017-04-18 09:45:58 -0700634 CharSequence[] mAutofillOptions;
Felipe Leme0200d9e2017-01-24 15:10:26 -0800635 boolean mSanitized;
Felipe Leme25bf7872017-03-28 15:32:29 -0700636 HtmlInfo mHtmlInfo;
Felipe Lemeaa7e2292017-10-05 18:19:48 -0700637 int mMinEms = -1;
638 int mMaxEms = -1;
639 int mMaxLength = -1;
Felipe Leme5dc45ca2018-01-03 09:02:27 -0800640 @Nullable String mTextIdEntry;
felipeal53308c12018-02-07 14:43:30 +0100641 @AutofillImportance int mImportantForAutofill;
Felipe Leme16aafc32017-02-27 13:41:37 -0800642
Felipe Lemecde040a2017-03-31 17:26:34 -0700643 // POJO used to override some autofill-related values when the node is parcelized.
644 // Not written to parcel.
645 AutofillOverlay mAutofillOverlay;
646
Dianne Hackborn16036f22015-06-22 14:05:51 -0700647 int mX;
648 int mY;
649 int mScrollX;
650 int mScrollY;
651 int mWidth;
652 int mHeight;
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000653 Matrix mMatrix;
654 float mElevation;
655 float mAlpha = 1.0f;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700656
657 static final int FLAGS_DISABLED = 0x00000001;
658 static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
659 static final int FLAGS_FOCUSABLE = 0x00000010;
660 static final int FLAGS_FOCUSED = 0x00000020;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700661 static final int FLAGS_SELECTED = 0x00000040;
662 static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700663 static final int FLAGS_CHECKABLE = 0x00000100;
664 static final int FLAGS_CHECKED = 0x00000200;
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000665 static final int FLAGS_CLICKABLE = 0x00000400;
666 static final int FLAGS_LONG_CLICKABLE = 0x00000800;
667 static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x00001000;
668 static final int FLAGS_ACTIVATED = 0x00002000;
669 static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
Amith Yamasani858f98d2017-02-22 12:59:53 -0800670 static final int FLAGS_OPAQUE = 0x00008000;
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000671
Felipe Leme85d1c2d2017-04-21 08:56:04 -0700672 // TODO: autofill data is made of many fields and ideally we should verify
Felipe Leme6d553872016-12-08 17:13:25 -0800673 // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
674 // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
675 // So, to keep thinkg simpler for now, let's just use on flag for all of them...
Felipe Leme640f30a2017-03-06 15:44:06 -0800676 static final int FLAGS_HAS_AUTOFILL_DATA = 0x80000000;
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000677 static final int FLAGS_HAS_MATRIX = 0x40000000;
678 static final int FLAGS_HAS_ALPHA = 0x20000000;
679 static final int FLAGS_HAS_ELEVATION = 0x10000000;
680 static final int FLAGS_HAS_SCROLL = 0x08000000;
681 static final int FLAGS_HAS_LARGE_COORDS = 0x04000000;
682 static final int FLAGS_HAS_CONTENT_DESCRIPTION = 0x02000000;
683 static final int FLAGS_HAS_TEXT = 0x01000000;
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700684 static final int FLAGS_HAS_COMPLEX_TEXT = 0x00800000;
685 static final int FLAGS_HAS_EXTRAS = 0x00400000;
686 static final int FLAGS_HAS_ID = 0x00200000;
687 static final int FLAGS_HAS_CHILDREN = 0x00100000;
Felipe Lemec3241002017-02-15 12:55:11 -0800688 static final int FLAGS_HAS_URL = 0x00080000;
Felipe Leme16aafc32017-02-27 13:41:37 -0800689 static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
Felipe Lemeb4ca7012017-03-22 18:30:07 -0700690 static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000691 static final int FLAGS_ALL_CONTROL = 0xfff00000;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700692
693 int mFlags;
694
695 String mClassName;
696 CharSequence mContentDescription;
697
698 ViewNodeText mText;
Felipe Leme16aafc32017-02-27 13:41:37 -0800699 int mInputType;
Felipe Leme114a4412017-09-26 13:02:11 -0700700 String mWebScheme;
Felipe Leme4711ed92017-04-21 16:47:18 -0700701 String mWebDomain;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700702 Bundle mExtras;
Felipe Lemeb4ca7012017-03-22 18:30:07 -0700703 LocaleList mLocaleList;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700704
705 ViewNode[] mChildren;
706
707 ViewNode() {
708 }
709
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700710 ViewNode(ParcelTransferReader reader, int nestingLevel) {
711 final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700712 reader.mNumReadViews++;
713 final PooledStringReader preader = reader.mStringReader;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700714 mClassName = preader.readString();
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000715 mFlags = in.readInt();
716 final int flags = mFlags;
717 if ((flags&FLAGS_HAS_ID) != 0) {
718 mId = in.readInt();
Felipe Leme5dc45ca2018-01-03 09:02:27 -0800719 if (mId != View.NO_ID) {
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000720 mIdEntry = preader.readString();
721 if (mIdEntry != null) {
722 mIdType = preader.readString();
723 mIdPackage = preader.readString();
724 }
725 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700726 }
Felipe Leme1a1e4682017-03-13 16:34:03 -0700727
Felipe Leme640f30a2017-03-06 15:44:06 -0800728 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
Felipe Leme0200d9e2017-01-24 15:10:26 -0800729 mSanitized = in.readInt() == 1;
Felipe Leme640f30a2017-03-06 15:44:06 -0800730 mAutofillId = in.readParcelable(null);
Felipe Leme8931e302017-03-06 13:44:35 -0800731 mAutofillType = in.readInt();
Philip P. Moltmann81192b42017-03-29 13:58:59 -0700732 mAutofillHints = in.readStringArray();
Felipe Leme640f30a2017-03-06 15:44:06 -0800733 mAutofillValue = in.readParcelable(null);
Felipe Leme7e4c2052017-04-18 09:45:58 -0700734 mAutofillOptions = in.readCharSequenceArray();
Felipe Leme25bf7872017-03-28 15:32:29 -0700735 final Parcelable p = in.readParcelable(null);
736 if (p instanceof HtmlInfo) {
737 mHtmlInfo = (HtmlInfo) p;
738 }
Felipe Lemeaa7e2292017-10-05 18:19:48 -0700739 mMinEms = in.readInt();
740 mMaxEms = in.readInt();
741 mMaxLength = in.readInt();
Felipe Leme5dc45ca2018-01-03 09:02:27 -0800742 mTextIdEntry = preader.readString();
felipeal53308c12018-02-07 14:43:30 +0100743 mImportantForAutofill = in.readInt();
Felipe Leme29a5b0d2016-10-25 14:57:11 -0700744 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000745 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
746 mX = in.readInt();
747 mY = in.readInt();
748 mWidth = in.readInt();
749 mHeight = in.readInt();
750 } else {
751 int val = in.readInt();
752 mX = val&0x7fff;
753 mY = (val>>16)&0x7fff;
754 val = in.readInt();
755 mWidth = val&0x7fff;
756 mHeight = (val>>16)&0x7fff;
757 }
758 if ((flags&FLAGS_HAS_SCROLL) != 0) {
759 mScrollX = in.readInt();
760 mScrollY = in.readInt();
761 }
762 if ((flags&FLAGS_HAS_MATRIX) != 0) {
763 mMatrix = new Matrix();
Dianne Hackborn782d4982015-07-08 17:36:37 -0700764 in.readFloatArray(reader.mTmpMatrix);
765 mMatrix.setValues(reader.mTmpMatrix);
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000766 }
767 if ((flags&FLAGS_HAS_ELEVATION) != 0) {
768 mElevation = in.readFloat();
769 }
770 if ((flags&FLAGS_HAS_ALPHA) != 0) {
771 mAlpha = in.readFloat();
772 }
773 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
774 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
775 }
776 if ((flags&FLAGS_HAS_TEXT) != 0) {
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700777 mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000778 }
Felipe Leme16aafc32017-02-27 13:41:37 -0800779 if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
780 mInputType = in.readInt();
781 }
Felipe Lemec3241002017-02-15 12:55:11 -0800782 if ((flags&FLAGS_HAS_URL) != 0) {
Felipe Leme114a4412017-09-26 13:02:11 -0700783 mWebScheme = in.readString();
Felipe Leme4711ed92017-04-21 16:47:18 -0700784 mWebDomain = in.readString();
Felipe Lemec3241002017-02-15 12:55:11 -0800785 }
Felipe Lemeb4ca7012017-03-22 18:30:07 -0700786 if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
787 mLocaleList = in.readParcelable(null);
788 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000789 if ((flags&FLAGS_HAS_EXTRAS) != 0) {
790 mExtras = in.readBundle();
791 }
792 if ((flags&FLAGS_HAS_CHILDREN) != 0) {
793 final int NCHILDREN = in.readInt();
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700794 if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
795 "Preparing to read " + NCHILDREN
796 + " children: @ #" + reader.mNumReadViews
797 + ", level " + nestingLevel);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700798 mChildren = new ViewNode[NCHILDREN];
799 for (int i=0; i<NCHILDREN; i++) {
Dianne Hackborn3e8125b2015-07-22 17:02:10 -0700800 mChildren[i] = new ViewNode(reader, nestingLevel + 1);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700801 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700802 }
803 }
804
Felipe Leme0200d9e2017-01-24 15:10:26 -0800805 int writeSelfToParcel(Parcel out, PooledStringWriter pwriter, boolean sanitizeOnWrite,
806 float[] tmpMatrix) {
Felipe Leme640f30a2017-03-06 15:44:06 -0800807 // Guard used to skip non-sanitized data when writing for autofill.
Felipe Leme0200d9e2017-01-24 15:10:26 -0800808 boolean writeSensitive = true;
809
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000810 int flags = mFlags & ~FLAGS_ALL_CONTROL;
Felipe Lemecde040a2017-03-31 17:26:34 -0700811
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000812 if (mId != View.NO_ID) {
813 flags |= FLAGS_HAS_ID;
814 }
Felipe Leme640f30a2017-03-06 15:44:06 -0800815 if (mAutofillId != null) {
816 flags |= FLAGS_HAS_AUTOFILL_DATA;
Felipe Leme29a5b0d2016-10-25 14:57:11 -0700817 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000818 if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
819 || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
820 flags |= FLAGS_HAS_LARGE_COORDS;
821 }
822 if (mScrollX != 0 || mScrollY != 0) {
823 flags |= FLAGS_HAS_SCROLL;
824 }
825 if (mMatrix != null) {
826 flags |= FLAGS_HAS_MATRIX;
827 }
828 if (mElevation != 0) {
829 flags |= FLAGS_HAS_ELEVATION;
830 }
831 if (mAlpha != 1.0f) {
832 flags |= FLAGS_HAS_ALPHA;
833 }
834 if (mContentDescription != null) {
835 flags |= FLAGS_HAS_CONTENT_DESCRIPTION;
836 }
837 if (mText != null) {
838 flags |= FLAGS_HAS_TEXT;
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -0700839 if (!mText.isSimple()) {
840 flags |= FLAGS_HAS_COMPLEX_TEXT;
841 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000842 }
Felipe Leme16aafc32017-02-27 13:41:37 -0800843 if (mInputType != 0) {
844 flags |= FLAGS_HAS_INPUT_TYPE;
845 }
Felipe Leme114a4412017-09-26 13:02:11 -0700846 if (mWebScheme != null || mWebDomain != null) {
Felipe Lemec3241002017-02-15 12:55:11 -0800847 flags |= FLAGS_HAS_URL;
848 }
Felipe Lemeb4ca7012017-03-22 18:30:07 -0700849 if (mLocaleList != null) {
850 flags |= FLAGS_HAS_LOCALE_LIST;
851 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000852 if (mExtras != null) {
853 flags |= FLAGS_HAS_EXTRAS;
854 }
855 if (mChildren != null) {
856 flags |= FLAGS_HAS_CHILDREN;
857 }
858
859 pwriter.writeString(mClassName);
Felipe Lemec01a8732017-02-22 17:26:06 -0800860
861 int writtenFlags = flags;
Felipe Leme640f30a2017-03-06 15:44:06 -0800862 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
863 // Remove 'checked' from sanitized autofill request.
Felipe Lemec01a8732017-02-22 17:26:06 -0800864 writtenFlags = flags & ~FLAGS_CHECKED;
865 }
Felipe Lemecde040a2017-03-31 17:26:34 -0700866 if (mAutofillOverlay != null) {
867 if (mAutofillOverlay.focused) {
868 writtenFlags |= ViewNode.FLAGS_FOCUSED;
869 } else {
870 writtenFlags &= ~ViewNode.FLAGS_FOCUSED;
871 }
872 }
Felipe Lemec01a8732017-02-22 17:26:06 -0800873
874 out.writeInt(writtenFlags);
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000875 if ((flags&FLAGS_HAS_ID) != 0) {
876 out.writeInt(mId);
Felipe Leme5dc45ca2018-01-03 09:02:27 -0800877 if (mId != View.NO_ID) {
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000878 pwriter.writeString(mIdEntry);
879 if (mIdEntry != null) {
880 pwriter.writeString(mIdType);
881 pwriter.writeString(mIdPackage);
882 }
Dianne Hackborn16036f22015-06-22 14:05:51 -0700883 }
884 }
Felipe Leme1a1e4682017-03-13 16:34:03 -0700885
Felipe Leme640f30a2017-03-06 15:44:06 -0800886 if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
Felipe Leme0200d9e2017-01-24 15:10:26 -0800887 writeSensitive = mSanitized || !sanitizeOnWrite;
888 out.writeInt(mSanitized ? 1 : 0);
Felipe Leme640f30a2017-03-06 15:44:06 -0800889 out.writeParcelable(mAutofillId, 0);
Felipe Leme8931e302017-03-06 13:44:35 -0800890 out.writeInt(mAutofillType);
Philip P. Moltmann81192b42017-03-29 13:58:59 -0700891 out.writeStringArray(mAutofillHints);
Felipe Lemecde040a2017-03-31 17:26:34 -0700892 final AutofillValue sanitizedValue;
Felipe Leme7f33cd32017-05-11 10:10:49 -0700893 if (writeSensitive) {
Felipe Lemecde040a2017-03-31 17:26:34 -0700894 sanitizedValue = mAutofillValue;
Felipe Leme7f33cd32017-05-11 10:10:49 -0700895 } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
896 sanitizedValue = mAutofillOverlay.value;
Felipe Lemecde040a2017-03-31 17:26:34 -0700897 } else {
898 sanitizedValue = null;
899 }
Felipe Leme0200d9e2017-01-24 15:10:26 -0800900 out.writeParcelable(sanitizedValue, 0);
Felipe Leme7e4c2052017-04-18 09:45:58 -0700901 out.writeCharSequenceArray(mAutofillOptions);
Felipe Leme25bf7872017-03-28 15:32:29 -0700902 if (mHtmlInfo instanceof Parcelable) {
903 out.writeParcelable((Parcelable) mHtmlInfo, 0);
904 } else {
905 out.writeParcelable(null, 0);
906 }
Felipe Lemeaa7e2292017-10-05 18:19:48 -0700907 out.writeInt(mMinEms);
908 out.writeInt(mMaxEms);
909 out.writeInt(mMaxLength);
Felipe Leme5dc45ca2018-01-03 09:02:27 -0800910 pwriter.writeString(mTextIdEntry);
felipeal53308c12018-02-07 14:43:30 +0100911 out.writeInt(mImportantForAutofill);
Felipe Leme29a5b0d2016-10-25 14:57:11 -0700912 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000913 if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
914 out.writeInt(mX);
915 out.writeInt(mY);
916 out.writeInt(mWidth);
917 out.writeInt(mHeight);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700918 } else {
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000919 out.writeInt((mY<<16) | mX);
920 out.writeInt((mHeight<<16) | mWidth);
Dianne Hackborn16036f22015-06-22 14:05:51 -0700921 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000922 if ((flags&FLAGS_HAS_SCROLL) != 0) {
923 out.writeInt(mScrollX);
924 out.writeInt(mScrollY);
925 }
926 if ((flags&FLAGS_HAS_MATRIX) != 0) {
927 mMatrix.getValues(tmpMatrix);
928 out.writeFloatArray(tmpMatrix);
929 }
930 if ((flags&FLAGS_HAS_ELEVATION) != 0) {
931 out.writeFloat(mElevation);
932 }
933 if ((flags&FLAGS_HAS_ALPHA) != 0) {
934 out.writeFloat(mAlpha);
935 }
936 if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
937 TextUtils.writeToParcel(mContentDescription, out, 0);
938 }
939 if ((flags&FLAGS_HAS_TEXT) != 0) {
Felipe Leme0200d9e2017-01-24 15:10:26 -0800940 mText.writeToParcel(out, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0, writeSensitive);
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000941 }
Felipe Leme16aafc32017-02-27 13:41:37 -0800942 if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
943 out.writeInt(mInputType);
944 }
Felipe Lemec3241002017-02-15 12:55:11 -0800945 if ((flags&FLAGS_HAS_URL) != 0) {
Felipe Leme114a4412017-09-26 13:02:11 -0700946 out.writeString(mWebScheme);
Felipe Leme4711ed92017-04-21 16:47:18 -0700947 out.writeString(mWebDomain);
Felipe Lemec3241002017-02-15 12:55:11 -0800948 }
Felipe Lemeb4ca7012017-03-22 18:30:07 -0700949 if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
950 out.writeParcelable(mLocaleList, 0);
951 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +0000952 if ((flags&FLAGS_HAS_EXTRAS) != 0) {
953 out.writeBundle(mExtras);
954 }
Dianne Hackborn782d4982015-07-08 17:36:37 -0700955 return flags;
Dianne Hackborn16036f22015-06-22 14:05:51 -0700956 }
957
958 /**
959 * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
960 */
961 public int getId() {
962 return mId;
963 }
964
965 /**
966 * If {@link #getId()} is a resource identifier, this is the package name of that
967 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
968 * for more information.
969 */
970 public String getIdPackage() {
971 return mIdPackage;
972 }
973
974 /**
975 * If {@link #getId()} is a resource identifier, this is the type name of that
976 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
977 * for more information.
978 */
979 public String getIdType() {
980 return mIdType;
981 }
982
983 /**
984 * If {@link #getId()} is a resource identifier, this is the entry name of that
985 * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
986 * for more information.
987 */
988 public String getIdEntry() {
989 return mIdEntry;
990 }
991
992 /**
Felipe Leme640f30a2017-03-06 15:44:06 -0800993 * Gets the id that can be used to autofill the view contents.
994 *
Felipe Leme2f6fc722017-05-31 11:57:46 -0700995 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
Felipe Leme30e9b262017-04-21 11:29:30 -0700996 *
997 * @return id that can be used to autofill the view contents, or {@code null} if the
Felipe Leme2f6fc722017-05-31 11:57:46 -0700998 * structure was created for assist purposes.
Felipe Leme640f30a2017-03-06 15:44:06 -0800999 */
Felipe Leme30e9b262017-04-21 11:29:30 -07001000 @Nullable public AutofillId getAutofillId() {
Felipe Leme640f30a2017-03-06 15:44:06 -08001001 return mAutofillId;
1002 }
1003
1004 /**
Felipe Leme640f30a2017-03-06 15:44:06 -08001005 * Gets the the type of value that can be used to autofill the view contents.
Felipe Leme6d553872016-12-08 17:13:25 -08001006 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001007 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
Felipe Leme30e9b262017-04-21 11:29:30 -07001008 *
1009 * @return autofill type as defined by {@link View#getAutofillType()},
Felipe Leme2f6fc722017-05-31 11:57:46 -07001010 * or {@link View#AUTOFILL_TYPE_NONE} if the structure was created for assist purposes.
Felipe Leme6d553872016-12-08 17:13:25 -08001011 */
Felipe Leme8931e302017-03-06 13:44:35 -08001012 public @View.AutofillType int getAutofillType() {
1013 return mAutofillType;
Felipe Leme6d553872016-12-08 17:13:25 -08001014 }
1015
1016 /**
Felipe Leme640f30a2017-03-06 15:44:06 -08001017 * Describes the content of a view so that a autofill service can fill in the appropriate
Philip P. Moltmannba6f4622017-02-22 11:03:53 -08001018 * data.
1019 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001020 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
Felipe Leme30e9b262017-04-21 11:29:30 -07001021 * not for Assist - see {@link View#getAutofillHints()} for more info.
Philip P. Moltmannba6f4622017-02-22 11:03:53 -08001022 *
Felipe Leme30e9b262017-04-21 11:29:30 -07001023 * @return The autofill hints for this view, or {@code null} if the structure was created
Felipe Leme2f6fc722017-05-31 11:57:46 -07001024 * for assist purposes.
Philip P. Moltmannba6f4622017-02-22 11:03:53 -08001025 */
Felipe Lemeb1180212017-04-17 18:50:14 -07001026 @Nullable public String[] getAutofillHints() {
1027 return mAutofillHints;
1028 }
1029
1030 /**
Felipe Leme0200d9e2017-01-24 15:10:26 -08001031 * Gets the the value of this view.
1032 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001033 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1034 * not for assist purposes.
Felipe Leme30e9b262017-04-21 11:29:30 -07001035 *
1036 * @return the autofill value of this view, or {@code null} if the structure was created
Felipe Leme2f6fc722017-05-31 11:57:46 -07001037 * for assist purposes.
Felipe Leme0200d9e2017-01-24 15:10:26 -08001038 */
Felipe Leme30e9b262017-04-21 11:29:30 -07001039 @Nullable public AutofillValue getAutofillValue() {
Felipe Leme640f30a2017-03-06 15:44:06 -08001040 return mAutofillValue;
Felipe Leme0200d9e2017-01-24 15:10:26 -08001041 }
1042
Felipe Lemecde040a2017-03-31 17:26:34 -07001043 /** @hide **/
1044 public void setAutofillOverlay(AutofillOverlay overlay) {
1045 mAutofillOverlay = overlay;
1046 }
1047
Felipe Lemed09ccb82017-02-22 15:02:03 -08001048 /**
Felipe Leme30e9b262017-04-21 11:29:30 -07001049 * Gets the options that can be used to autofill this view.
Felipe Lemed09ccb82017-02-22 15:02:03 -08001050 *
Felipe Leme640f30a2017-03-06 15:44:06 -08001051 * <p>Typically used by nodes whose {@link View#getAutofillType()} is a list to indicate
1052 * the meaning of each possible value in the list.
Felipe Lemed09ccb82017-02-22 15:02:03 -08001053 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001054 * <p>It's relevant when the {@link AssistStructure} is used for autofill purposes, not
1055 * for assist purposes.
Felipe Leme30e9b262017-04-21 11:29:30 -07001056 *
1057 * @return the options that can be used to autofill this view, or {@code null} if the
Felipe Leme2f6fc722017-05-31 11:57:46 -07001058 * structure was created for assist purposes.
Felipe Lemed09ccb82017-02-22 15:02:03 -08001059 */
Felipe Leme30e9b262017-04-21 11:29:30 -07001060 @Nullable public CharSequence[] getAutofillOptions() {
Felipe Leme640f30a2017-03-06 15:44:06 -08001061 return mAutofillOptions;
Felipe Lemed09ccb82017-02-22 15:02:03 -08001062 }
1063
Felipe Leme16aafc32017-02-27 13:41:37 -08001064 /**
1065 * Gets the {@link android.text.InputType} bits of this structure.
1066 *
1067 * @return bits as defined by {@link android.text.InputType}.
1068 */
1069 public int getInputType() {
1070 return mInputType;
1071 }
1072
Felipe Leme0200d9e2017-01-24 15:10:26 -08001073 /** @hide */
1074 public boolean isSanitized() {
1075 return mSanitized;
1076 }
1077
1078 /**
Felipe Leme640f30a2017-03-06 15:44:06 -08001079 * Updates the {@link AutofillValue} of this structure.
Felipe Leme0200d9e2017-01-24 15:10:26 -08001080 *
1081 * <p>Should be used just before sending the structure to the
Felipe Leme640f30a2017-03-06 15:44:06 -08001082 * {@link android.service.autofill.AutofillService} for saving, since it will override the
Felipe Leme0200d9e2017-01-24 15:10:26 -08001083 * initial value.
1084 *
1085 * @hide
1086 */
Felipe Leme640f30a2017-03-06 15:44:06 -08001087 public void updateAutofillValue(AutofillValue value) {
1088 mAutofillValue = value;
Philip P. Moltmann96689032017-03-09 13:19:55 -08001089 if (value.isText()) {
Felipe Leme26675232017-06-19 09:45:48 -07001090 if (mText == null) {
1091 mText = new ViewNodeText();
1092 }
Philip P. Moltmann96689032017-03-09 13:19:55 -08001093 mText.mText = value.getTextValue();
Felipe Leme0200d9e2017-01-24 15:10:26 -08001094 }
1095 }
1096
1097 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07001098 * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
1099 */
1100 public int getLeft() {
1101 return mX;
1102 }
1103
1104 /**
1105 * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
1106 */
1107 public int getTop() {
1108 return mY;
1109 }
1110
1111 /**
1112 * Returns the current X scroll offset of this view, as per
1113 * {@link android.view.View#getScrollX() View.getScrollX()}.
1114 */
1115 public int getScrollX() {
1116 return mScrollX;
1117 }
1118
1119 /**
1120 * Returns the current Y scroll offset of this view, as per
1121 * {@link android.view.View#getScrollX() View.getScrollY()}.
1122 */
1123 public int getScrollY() {
1124 return mScrollY;
1125 }
1126
1127 /**
1128 * Returns the width of this view, in pixels.
1129 */
1130 public int getWidth() {
1131 return mWidth;
1132 }
1133
1134 /**
1135 * Returns the height of this view, in pixels.
1136 */
1137 public int getHeight() {
1138 return mHeight;
1139 }
1140
1141 /**
Dianne Hackborn70d8be72015-06-23 19:33:02 +00001142 * Returns the transformation that has been applied to this view, such as a translation
1143 * or scaling. The returned Matrix object is owned by ViewNode; do not modify it.
1144 * Returns null if there is no transformation applied to the view.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001145 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001146 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1147 * not for autofill purposes.
Dianne Hackborn70d8be72015-06-23 19:33:02 +00001148 */
1149 public Matrix getTransformation() {
1150 return mMatrix;
1151 }
1152
1153 /**
1154 * Returns the visual elevation of the view, used for shadowing and other visual
1155 * characterstics, as set by {@link ViewStructure#setElevation
1156 * ViewStructure.setElevation(float)}.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001157 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001158 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1159 * not for autofill purposes.
Dianne Hackborn70d8be72015-06-23 19:33:02 +00001160 */
1161 public float getElevation() {
1162 return mElevation;
1163 }
1164
1165 /**
1166 * Returns the alpha transformation of the view, used to reduce the overall opacity
1167 * of the view's contents, as set by {@link ViewStructure#setAlpha
1168 * ViewStructure.setAlpha(float)}.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001169 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001170 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1171 * not for autofill purposes.
Dianne Hackborn70d8be72015-06-23 19:33:02 +00001172 */
1173 public float getAlpha() {
1174 return mAlpha;
1175 }
1176
1177 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07001178 * Returns the visibility mode of this view, as per
1179 * {@link android.view.View#getVisibility() View.getVisibility()}.
1180 */
1181 public int getVisibility() {
1182 return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
1183 }
1184
1185 /**
1186 * Returns true if assist data has been blocked starting at this node in the hierarchy.
1187 */
1188 public boolean isAssistBlocked() {
Dianne Hackbornfcbfeaf2015-07-15 11:25:55 -07001189 return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
Dianne Hackborn16036f22015-06-22 14:05:51 -07001190 }
1191
1192 /**
1193 * Returns true if this node is in an enabled state.
1194 */
1195 public boolean isEnabled() {
1196 return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
1197 }
1198
1199 /**
1200 * Returns true if this node is clickable by the user.
1201 */
1202 public boolean isClickable() {
1203 return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
1204 }
1205
1206 /**
1207 * Returns true if this node can take input focus.
1208 */
1209 public boolean isFocusable() {
1210 return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
1211 }
1212
1213 /**
1214 * Returns true if this node currently had input focus at the time that the
1215 * structure was collected.
1216 */
1217 public boolean isFocused() {
1218 return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
1219 }
1220
1221 /**
1222 * Returns true if this node currently had accessibility focus at the time that the
1223 * structure was collected.
1224 */
1225 public boolean isAccessibilityFocused() {
1226 return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
1227 }
1228
1229 /**
1230 * Returns true if this node represents something that is checkable by the user.
1231 */
1232 public boolean isCheckable() {
1233 return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
1234 }
1235
1236 /**
1237 * Returns true if this node is currently in a checked state.
1238 */
1239 public boolean isChecked() {
1240 return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
1241 }
1242
1243 /**
1244 * Returns true if this node has currently been selected by the user.
1245 */
1246 public boolean isSelected() {
1247 return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
1248 }
1249
1250 /**
1251 * Returns true if this node has currently been activated by the user.
1252 */
1253 public boolean isActivated() {
1254 return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
1255 }
1256
1257 /**
Amith Yamasani858f98d2017-02-22 12:59:53 -08001258 * Returns true if this node is opaque.
1259 */
1260 public boolean isOpaque() { return (mFlags&ViewNode.FLAGS_OPAQUE) != 0; }
1261
1262 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07001263 * Returns true if this node is something the user can perform a long click/press on.
1264 */
1265 public boolean isLongClickable() {
1266 return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
1267 }
1268
1269 /**
1270 * Returns true if this node is something the user can perform a context click on.
1271 */
1272 public boolean isContextClickable() {
1273 return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
1274 }
1275
1276 /**
1277 * Returns the class name of the node's implementation, indicating its behavior.
1278 * For example, a button will report "android.widget.Button" meaning it behaves
1279 * like a {@link android.widget.Button}.
1280 */
1281 public String getClassName() {
1282 return mClassName;
1283 }
1284
1285 /**
1286 * Returns any content description associated with the node, which semantically describes
1287 * its purpose for accessibility and other uses.
1288 */
1289 public CharSequence getContentDescription() {
1290 return mContentDescription;
1291 }
1292
1293 /**
Felipe Leme4711ed92017-04-21 16:47:18 -07001294 * Returns the domain of the HTML document represented by this view.
Felipe Lemec3241002017-02-15 12:55:11 -08001295 *
Felipe Leme30e9b262017-04-21 11:29:30 -07001296 * <p>Typically used when the view associated with the view is a container for an HTML
Felipe Leme25bf7872017-03-28 15:32:29 -07001297 * document.
Felipe Lemebd271212017-02-22 09:05:07 -08001298 *
Felipe Leme62219032017-09-26 14:20:30 -07001299 * <p><b>Warning:</b> an autofill service cannot trust the value reported by this method
1300 * without verifing its authenticity&mdash;see the "Web security" section of
1301 * {@link android.service.autofill.AutofillService} for more details.
Felipe Leme4711ed92017-04-21 16:47:18 -07001302 *
1303 * @return domain-only part of the document. For example, if the full URL is
Felipe Leme114a4412017-09-26 13:02:11 -07001304 * {@code https://example.com/login?user=my_user}, it returns {@code example.com}.
Felipe Lemec3241002017-02-15 12:55:11 -08001305 */
Felipe Leme4711ed92017-04-21 16:47:18 -07001306 @Nullable public String getWebDomain() {
1307 return mWebDomain;
Felipe Lemec3241002017-02-15 12:55:11 -08001308 }
1309
1310 /**
Felipe Leme185de722018-02-13 17:25:44 -08001311 * @hide
1312 */
1313 public void setWebDomain(@Nullable String domain) {
1314 if (domain == null) return;
1315
1316 final Uri uri = Uri.parse(domain);
Felipe Leme98f4c692018-02-28 17:37:52 -08001317 if (uri == null) {
1318 // Cannot log domain because it could contain PII;
1319 Log.w(TAG, "Failed to parse web domain");
1320 return;
1321 }
Felipe Leme185de722018-02-13 17:25:44 -08001322 mWebScheme = uri.getScheme();
1323 mWebDomain = uri.getHost();
1324 }
1325
1326 /**
Felipe Leme114a4412017-09-26 13:02:11 -07001327 * Returns the scheme of the HTML document represented by this view.
1328 *
1329 * <p>Typically used when the view associated with the view is a container for an HTML
1330 * document.
1331 *
1332 * @return scheme-only part of the document. For example, if the full URL is
1333 * {@code https://example.com/login?user=my_user}, it returns {@code https}.
1334 */
1335 @Nullable public String getWebScheme() {
1336 return mWebScheme;
1337 }
1338
1339 /**
Felipe Leme30e9b262017-04-21 11:29:30 -07001340 * Returns the HTML properties associated with this view.
Felipe Leme25bf7872017-03-28 15:32:29 -07001341 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001342 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1343 * not for assist purposes.
Felipe Leme30e9b262017-04-21 11:29:30 -07001344 *
1345 * @return the HTML properties associated with this view, or {@code null} if the
Felipe Leme2f6fc722017-05-31 11:57:46 -07001346 * structure was created for assist purposes.
Felipe Leme25bf7872017-03-28 15:32:29 -07001347 */
Felipe Leme30e9b262017-04-21 11:29:30 -07001348 @Nullable public HtmlInfo getHtmlInfo() {
Felipe Leme25bf7872017-03-28 15:32:29 -07001349 return mHtmlInfo;
1350 }
1351
1352 /**
Felipe Leme30e9b262017-04-21 11:29:30 -07001353 * Returns the the list of locales associated with this view.
Felipe Lemeb4ca7012017-03-22 18:30:07 -07001354 */
Felipe Leme30e9b262017-04-21 11:29:30 -07001355 @Nullable public LocaleList getLocaleList() {
Felipe Lemeb4ca7012017-03-22 18:30:07 -07001356 return mLocaleList;
1357 }
1358
1359 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07001360 * Returns any text associated with the node that is displayed to the user, or null
1361 * if there is none.
1362 */
1363 public CharSequence getText() {
1364 return mText != null ? mText.mText : null;
1365 }
1366
1367 /**
1368 * If {@link #getText()} is non-null, this is where the current selection starts.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001369 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001370 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1371 * not for autofill purposes.
Dianne Hackborn16036f22015-06-22 14:05:51 -07001372 */
1373 public int getTextSelectionStart() {
1374 return mText != null ? mText.mTextSelectionStart : -1;
1375 }
1376
1377 /**
1378 * If {@link #getText()} is non-null, this is where the current selection starts.
1379 * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
1380 * indicating the cursor position.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001381 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001382 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1383 * not for autofill purposes.
Dianne Hackborn16036f22015-06-22 14:05:51 -07001384 */
1385 public int getTextSelectionEnd() {
1386 return mText != null ? mText.mTextSelectionEnd : -1;
1387 }
1388
1389 /**
1390 * If {@link #getText()} is non-null, this is the main text color associated with it.
1391 * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1392 * Note that the text may also contain style spans that modify the color of specific
1393 * parts of the text.
1394 */
1395 public int getTextColor() {
1396 return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
1397 }
1398
1399 /**
1400 * If {@link #getText()} is non-null, this is the main text background color associated
1401 * with it.
1402 * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
1403 * Note that the text may also contain style spans that modify the color of specific
1404 * parts of the text.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001405 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001406 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1407 * not for autofill purposes.
Dianne Hackborn16036f22015-06-22 14:05:51 -07001408 */
1409 public int getTextBackgroundColor() {
1410 return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
1411 }
1412
1413 /**
1414 * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
1415 * with it.
1416 * Note that the text may also contain style spans that modify the size of specific
1417 * parts of the text.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001418 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001419 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1420 * not for autofill purposes.
Dianne Hackborn16036f22015-06-22 14:05:51 -07001421 */
1422 public float getTextSize() {
1423 return mText != null ? mText.mTextSize : 0;
1424 }
1425
1426 /**
1427 * If {@link #getText()} is non-null, this is the main text style associated
1428 * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
1429 * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
1430 * {@link #TEXT_STYLE_UNDERLINE}.
1431 * Note that the text may also contain style spans that modify the style of specific
1432 * parts of the text.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001433 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001434 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1435 * not for autofill purposes.
Dianne Hackborn16036f22015-06-22 14:05:51 -07001436 */
1437 public int getTextStyle() {
1438 return mText != null ? mText.mTextStyle : 0;
1439 }
1440
1441 /**
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -07001442 * Return per-line offsets into the text returned by {@link #getText()}. Each entry
1443 * in the array is a formatted line of text, and the value it contains is the offset
1444 * into the text string where that line starts. May return null if there is no line
1445 * information.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001446 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001447 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1448 * not for autofill purposes.
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -07001449 */
1450 public int[] getTextLineCharOffsets() {
1451 return mText != null ? mText.mLineCharOffsets : null;
1452 }
1453
1454 /**
1455 * Return per-line baselines into the text returned by {@link #getText()}. Each entry
1456 * in the array is a formatted line of text, and the value it contains is the baseline
1457 * where that text appears in the view. May return null if there is no line
1458 * information.
Philip P. Moltmannc368a242017-05-04 12:29:59 -07001459 *
Felipe Leme2f6fc722017-05-31 11:57:46 -07001460 * <p>It's only relevant when the {@link AssistStructure} is used for assist purposes,
1461 * not for autofill purposes.
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -07001462 */
1463 public int[] getTextLineBaselines() {
1464 return mText != null ? mText.mLineBaselines : null;
1465 }
1466
1467 /**
Felipe Leme5dc45ca2018-01-03 09:02:27 -08001468 * Gets the identifier used to set the text associated with this view.
1469 *
1470 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1471 * not for assist purposes.
1472 */
1473 @Nullable
1474 public String getTextIdEntry() {
1475 return mTextIdEntry;
1476 }
1477
1478 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07001479 * Return additional hint text associated with the node; this is typically used with
1480 * a node that takes user input, describing to the user what the input means.
1481 */
1482 public String getHint() {
1483 return mText != null ? mText.mHint : null;
1484 }
1485
1486 /**
1487 * Return a Bundle containing optional vendor-specific extension information.
1488 */
1489 public Bundle getExtras() {
1490 return mExtras;
1491 }
1492
1493 /**
1494 * Return the number of children this node has.
1495 */
1496 public int getChildCount() {
1497 return mChildren != null ? mChildren.length : 0;
1498 }
1499
1500 /**
1501 * Return a child of this node, given an index value from 0 to
1502 * {@link #getChildCount()}-1.
1503 */
1504 public ViewNode getChildAt(int index) {
1505 return mChildren[index];
1506 }
Felipe Lemeaa7e2292017-10-05 18:19:48 -07001507
1508 /**
1509 * Returns the minimum width in ems of the text associated with this node, or {@code -1}
1510 * if not supported by the node.
1511 *
1512 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1513 * not for assist purposes.
1514 */
1515 public int getMinTextEms() {
1516 return mMinEms;
1517 }
1518
1519 /**
1520 * Returns the maximum width in ems of the text associated with this node, or {@code -1}
1521 * if not supported by the node.
1522 *
1523 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1524 * not for assist purposes.
1525 */
1526 public int getMaxTextEms() {
1527 return mMaxEms;
1528 }
1529
1530 /**
1531 * Returns the maximum length of the text associated with this node node, or {@code -1}
1532 * if not supported by the node or not set.
1533 *
1534 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
1535 * not for assist purposes.
1536 */
1537 public int getMaxTextLength() {
1538 return mMaxLength;
1539 }
felipeal53308c12018-02-07 14:43:30 +01001540
1541 /**
1542 * Gets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of
1543 * the view associated with this node.
1544 *
1545 * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
1546 */
1547 public @AutofillImportance int getImportantForAutofill() {
1548 return mImportantForAutofill;
1549 }
Dianne Hackborn16036f22015-06-22 14:05:51 -07001550 }
1551
Felipe Lemecde040a2017-03-31 17:26:34 -07001552 /**
1553 * POJO used to override some autofill-related values when the node is parcelized.
1554 *
1555 * @hide
1556 */
1557 static public class AutofillOverlay {
1558 public boolean focused;
1559 public AutofillValue value;
1560 }
1561
Dianne Hackborn8ecf16d2015-06-23 13:09:21 -07001562 static class ViewNodeBuilder extends ViewStructure {
Dianne Hackborn16036f22015-06-22 14:05:51 -07001563 final AssistStructure mAssist;
1564 final ViewNode mNode;
1565 final boolean mAsync;
1566
Felipe Leme33791fd2017-02-16 08:07:56 -08001567 ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07001568 mAssist = assist;
1569 mNode = node;
1570 mAsync = async;
1571 }
1572
1573 @Override
1574 public void setId(int id, String packageName, String typeName, String entryName) {
1575 mNode.mId = id;
1576 mNode.mIdPackage = packageName;
1577 mNode.mIdType = typeName;
1578 mNode.mIdEntry = entryName;
1579 }
1580
1581 @Override
1582 public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
1583 mNode.mX = left;
1584 mNode.mY = top;
1585 mNode.mScrollX = scrollX;
1586 mNode.mScrollY = scrollY;
1587 mNode.mWidth = width;
1588 mNode.mHeight = height;
1589 }
1590
1591 @Override
Dianne Hackborn70d8be72015-06-23 19:33:02 +00001592 public void setTransformation(Matrix matrix) {
1593 if (matrix == null) {
1594 mNode.mMatrix = null;
1595 } else {
1596 mNode.mMatrix = new Matrix(matrix);
1597 }
1598 }
1599
1600 @Override
1601 public void setElevation(float elevation) {
1602 mNode.mElevation = elevation;
1603 }
1604
1605 @Override
1606 public void setAlpha(float alpha) {
1607 mNode.mAlpha = alpha;
1608 }
1609
1610 @Override
Dianne Hackborn16036f22015-06-22 14:05:51 -07001611 public void setVisibility(int visibility) {
1612 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
1613 }
1614
1615 @Override
1616 public void setAssistBlocked(boolean state) {
1617 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
Dianne Hackbornafb308d2015-07-31 13:10:55 -07001618 | (state ? ViewNode.FLAGS_ASSIST_BLOCKED : 0);
Dianne Hackborn16036f22015-06-22 14:05:51 -07001619 }
1620
1621 @Override
1622 public void setEnabled(boolean state) {
1623 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
1624 | (state ? 0 : ViewNode.FLAGS_DISABLED);
1625 }
1626
1627 @Override
1628 public void setClickable(boolean state) {
1629 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
1630 | (state ? ViewNode.FLAGS_CLICKABLE : 0);
1631 }
1632
1633 @Override
1634 public void setLongClickable(boolean state) {
1635 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
1636 | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
1637 }
1638
1639 @Override
1640 public void setContextClickable(boolean state) {
1641 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
1642 | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
1643 }
1644
1645 @Override
1646 public void setFocusable(boolean state) {
1647 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
1648 | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
1649 }
1650
1651 @Override
1652 public void setFocused(boolean state) {
1653 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
1654 | (state ? ViewNode.FLAGS_FOCUSED : 0);
1655 }
1656
1657 @Override
1658 public void setAccessibilityFocused(boolean state) {
1659 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
1660 | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
1661 }
1662
1663 @Override
1664 public void setCheckable(boolean state) {
1665 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
1666 | (state ? ViewNode.FLAGS_CHECKABLE : 0);
1667 }
1668
1669 @Override
1670 public void setChecked(boolean state) {
1671 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
1672 | (state ? ViewNode.FLAGS_CHECKED : 0);
1673 }
1674
1675 @Override
1676 public void setSelected(boolean state) {
1677 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
1678 | (state ? ViewNode.FLAGS_SELECTED : 0);
1679 }
1680
1681 @Override
1682 public void setActivated(boolean state) {
1683 mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
1684 | (state ? ViewNode.FLAGS_ACTIVATED : 0);
1685 }
1686
1687 @Override
Amith Yamasani858f98d2017-02-22 12:59:53 -08001688 public void setOpaque(boolean opaque) {
1689 mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_OPAQUE)
1690 | (opaque ? ViewNode.FLAGS_OPAQUE : 0);
1691 }
1692
1693 @Override
Dianne Hackborn16036f22015-06-22 14:05:51 -07001694 public void setClassName(String className) {
1695 mNode.mClassName = className;
1696 }
1697
1698 @Override
1699 public void setContentDescription(CharSequence contentDescription) {
1700 mNode.mContentDescription = contentDescription;
1701 }
1702
1703 private final ViewNodeText getNodeText() {
1704 if (mNode.mText != null) {
1705 return mNode.mText;
1706 }
1707 mNode.mText = new ViewNodeText();
1708 return mNode.mText;
1709 }
1710
1711 @Override
1712 public void setText(CharSequence text) {
1713 ViewNodeText t = getNodeText();
Felipe Lemea8fce3b2017-04-04 14:22:12 -07001714 t.mText = TextUtils.trimNoCopySpans(text);
Dianne Hackborn16036f22015-06-22 14:05:51 -07001715 t.mTextSelectionStart = t.mTextSelectionEnd = -1;
1716 }
1717
1718 @Override
1719 public void setText(CharSequence text, int selectionStart, int selectionEnd) {
1720 ViewNodeText t = getNodeText();
Felipe Lemea8fce3b2017-04-04 14:22:12 -07001721 t.mText = TextUtils.trimNoCopySpans(text);
Dianne Hackborn16036f22015-06-22 14:05:51 -07001722 t.mTextSelectionStart = selectionStart;
1723 t.mTextSelectionEnd = selectionEnd;
1724 }
1725
1726 @Override
1727 public void setTextStyle(float size, int fgColor, int bgColor, int style) {
1728 ViewNodeText t = getNodeText();
1729 t.mTextColor = fgColor;
1730 t.mTextBackgroundColor = bgColor;
1731 t.mTextSize = size;
1732 t.mTextStyle = style;
1733 }
1734
1735 @Override
Dianne Hackborn6f0fdc42015-07-07 14:29:36 -07001736 public void setTextLines(int[] charOffsets, int[] baselines) {
1737 ViewNodeText t = getNodeText();
1738 t.mLineCharOffsets = charOffsets;
1739 t.mLineBaselines = baselines;
1740 }
1741
1742 @Override
Felipe Leme5dc45ca2018-01-03 09:02:27 -08001743 public void setTextIdEntry(@NonNull String entryName) {
1744 mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
1745 }
1746
1747 @Override
Dianne Hackborn16036f22015-06-22 14:05:51 -07001748 public void setHint(CharSequence hint) {
1749 getNodeText().mHint = hint != null ? hint.toString() : null;
1750 }
1751
1752 @Override
1753 public CharSequence getText() {
1754 return mNode.mText != null ? mNode.mText.mText : null;
1755 }
1756
1757 @Override
1758 public int getTextSelectionStart() {
1759 return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
1760 }
1761
1762 @Override
1763 public int getTextSelectionEnd() {
1764 return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
1765 }
1766
1767 @Override
1768 public CharSequence getHint() {
1769 return mNode.mText != null ? mNode.mText.mHint : null;
1770 }
1771
1772 @Override
1773 public Bundle getExtras() {
1774 if (mNode.mExtras != null) {
1775 return mNode.mExtras;
1776 }
1777 mNode.mExtras = new Bundle();
1778 return mNode.mExtras;
1779 }
1780
1781 @Override
1782 public boolean hasExtras() {
1783 return mNode.mExtras != null;
1784 }
1785
1786 @Override
1787 public void setChildCount(int num) {
1788 mNode.mChildren = new ViewNode[num];
1789 }
1790
1791 @Override
1792 public int addChildCount(int num) {
1793 if (mNode.mChildren == null) {
1794 setChildCount(num);
1795 return 0;
1796 }
1797 final int start = mNode.mChildren.length;
1798 ViewNode[] newArray = new ViewNode[start + num];
1799 System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
1800 mNode.mChildren = newArray;
1801 return start;
1802 }
1803
1804 @Override
1805 public int getChildCount() {
1806 return mNode.mChildren != null ? mNode.mChildren.length : 0;
1807 }
1808
Felipe Lemef8a81742017-03-17 18:05:01 -07001809 @Override
Felipe Lemef8a81742017-03-17 18:05:01 -07001810 public ViewStructure newChild(int index) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07001811 ViewNode node = new ViewNode();
1812 mNode.mChildren[index] = node;
Felipe Leme33791fd2017-02-16 08:07:56 -08001813 return new ViewNodeBuilder(mAssist, node, false);
Dianne Hackborn16036f22015-06-22 14:05:51 -07001814 }
1815
Felipe Lemef8a81742017-03-17 18:05:01 -07001816 @Override
1817 public ViewStructure asyncNewChild(int index) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07001818 synchronized (mAssist) {
1819 ViewNode node = new ViewNode();
1820 mNode.mChildren[index] = node;
Felipe Leme33791fd2017-02-16 08:07:56 -08001821 ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
Dianne Hackborn16036f22015-06-22 14:05:51 -07001822 mAssist.mPendingAsyncChildren.add(builder);
1823 return builder;
1824 }
1825 }
1826
1827 @Override
1828 public void asyncCommit() {
1829 synchronized (mAssist) {
1830 if (!mAsync) {
1831 throw new IllegalStateException("Child " + this
Dianne Hackborn8ecf16d2015-06-23 13:09:21 -07001832 + " was not created with ViewStructure.asyncNewChild");
Dianne Hackborn16036f22015-06-22 14:05:51 -07001833 }
1834 if (!mAssist.mPendingAsyncChildren.remove(this)) {
1835 throw new IllegalStateException("Child " + this + " already committed");
1836 }
1837 mAssist.notifyAll();
1838 }
1839 }
1840
1841 @Override
1842 public Rect getTempRect() {
1843 return mAssist.mTmpRect;
1844 }
Felipe Leme29a5b0d2016-10-25 14:57:11 -07001845
1846 @Override
Felipe Lemee4f30652017-04-25 10:21:45 -07001847 public void setAutofillId(@NonNull AutofillId id) {
1848 mNode.mAutofillId = id;
1849 }
1850
1851 @Override
1852 public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
1853 mNode.mAutofillId = new AutofillId(parentId, virtualId);
Felipe Leme29a5b0d2016-10-25 14:57:11 -07001854 }
Felipe Leme6d553872016-12-08 17:13:25 -08001855
1856 @Override
Felipe Leme640f30a2017-03-06 15:44:06 -08001857 public AutofillId getAutofillId() {
1858 return mNode.mAutofillId;
Felipe Leme8931e302017-03-06 13:44:35 -08001859 }
1860
1861 @Override
1862 public void setAutofillType(@View.AutofillType int type) {
1863 mNode.mAutofillType = type;
Felipe Leme6d553872016-12-08 17:13:25 -08001864 }
1865
Felipe Leme0200d9e2017-01-24 15:10:26 -08001866 @Override
Philip P. Moltmann81192b42017-03-29 13:58:59 -07001867 public void setAutofillHints(@Nullable String[] hints) {
1868 mNode.mAutofillHints = hints;
Philip P. Moltmannba6f4622017-02-22 11:03:53 -08001869 }
1870
1871 @Override
Felipe Leme640f30a2017-03-06 15:44:06 -08001872 public void setAutofillValue(AutofillValue value) {
1873 mNode.mAutofillValue = value;
Felipe Leme0200d9e2017-01-24 15:10:26 -08001874 }
1875
Felipe Lemed09ccb82017-02-22 15:02:03 -08001876 @Override
Felipe Leme7e4c2052017-04-18 09:45:58 -07001877 public void setAutofillOptions(CharSequence[] options) {
Felipe Leme640f30a2017-03-06 15:44:06 -08001878 mNode.mAutofillOptions = options;
Felipe Lemed09ccb82017-02-22 15:02:03 -08001879 }
1880
Felipe Leme16aafc32017-02-27 13:41:37 -08001881 @Override
felipeal53308c12018-02-07 14:43:30 +01001882 public void setImportantForAutofill(@AutofillImportance int mode) {
1883 mNode.mImportantForAutofill = mode;
1884 }
1885
1886 @Override
Felipe Leme16aafc32017-02-27 13:41:37 -08001887 public void setInputType(int inputType) {
1888 mNode.mInputType = inputType;
1889 }
1890
Felipe Leme0200d9e2017-01-24 15:10:26 -08001891 @Override
Felipe Lemeaa7e2292017-10-05 18:19:48 -07001892 public void setMinTextEms(int minEms) {
1893 mNode.mMinEms = minEms;
1894 }
1895
1896 @Override
1897 public void setMaxTextEms(int maxEms) {
1898 mNode.mMaxEms = maxEms;
1899 }
1900
1901 @Override
1902 public void setMaxTextLength(int maxLength) {
1903 mNode.mMaxLength = maxLength;
1904 }
1905
1906 @Override
Felipe Lemec9a19b12017-03-13 18:05:22 -07001907 public void setDataIsSensitive(boolean sensitive) {
1908 mNode.mSanitized = !sensitive;
Felipe Leme0200d9e2017-01-24 15:10:26 -08001909 }
Felipe Lemec3241002017-02-15 12:55:11 -08001910
1911 @Override
Felipe Leme4711ed92017-04-21 16:47:18 -07001912 public void setWebDomain(@Nullable String domain) {
Felipe Leme185de722018-02-13 17:25:44 -08001913 mNode.setWebDomain(domain);
Felipe Lemec3241002017-02-15 12:55:11 -08001914 }
Felipe Lemeb4ca7012017-03-22 18:30:07 -07001915
1916 @Override
1917 public void setLocaleList(LocaleList localeList) {
1918 mNode.mLocaleList = localeList;
1919 }
Felipe Leme25bf7872017-03-28 15:32:29 -07001920
1921 @Override
1922 public HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String tagName) {
1923 return new HtmlInfoNodeBuilder(tagName);
1924 }
1925
1926 @Override
1927 public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
1928 mNode.mHtmlInfo = htmlInfo;
1929 }
1930 }
1931
1932 private static final class HtmlInfoNode extends HtmlInfo implements Parcelable {
1933 private final String mTag;
1934 private final String[] mNames;
1935 private final String[] mValues;
1936
1937 // Not parcelable
1938 private ArrayList<Pair<String, String>> mAttributes;
1939
1940 private HtmlInfoNode(HtmlInfoNodeBuilder builder) {
1941 mTag = builder.mTag;
1942 if (builder.mNames == null) {
1943 mNames = null;
1944 mValues = null;
1945 } else {
1946 mNames = new String[builder.mNames.size()];
1947 mValues = new String[builder.mValues.size()];
1948 builder.mNames.toArray(mNames);
1949 builder.mValues.toArray(mValues);
1950 }
1951 }
1952
1953 @Override
1954 public String getTag() {
1955 return mTag;
1956 }
1957
1958 @Override
Felipe Leme09a70622017-04-27 15:24:19 -07001959 public List<Pair<String, String>> getAttributes() {
Felipe Leme25bf7872017-03-28 15:32:29 -07001960 if (mAttributes == null && mNames != null) {
1961 mAttributes = new ArrayList<>(mNames.length);
1962 for (int i = 0; i < mNames.length; i++) {
1963 final Pair<String, String> pair = new Pair<>(mNames[i], mValues[i]);
1964 mAttributes.add(i, pair);
1965 }
1966 }
1967 return mAttributes;
1968 }
1969
1970 @Override
1971 public int describeContents() {
1972 return 0;
1973 }
1974
1975 @Override
1976 public void writeToParcel(Parcel parcel, int flags) {
1977 parcel.writeString(mTag);
1978 parcel.writeStringArray(mNames);
1979 parcel.writeStringArray(mValues);
1980 }
1981
1982 @SuppressWarnings("hiding")
1983 public static final Creator<HtmlInfoNode> CREATOR = new Creator<HtmlInfoNode>() {
1984 @Override
1985 public HtmlInfoNode createFromParcel(Parcel parcel) {
1986 // Always go through the builder to ensure the data ingested by
1987 // the system obeys the contract of the builder to avoid attacks
1988 // using specially crafted parcels.
1989 final String tag = parcel.readString();
1990 final HtmlInfoNodeBuilder builder = new HtmlInfoNodeBuilder(tag);
1991 final String[] names = parcel.readStringArray();
1992 final String[] values = parcel.readStringArray();
1993 if (names != null && values != null) {
1994 if (names.length != values.length) {
1995 Log.w(TAG, "HtmlInfo attributes mismatch: names=" + names.length
1996 + ", values=" + values.length);
1997 } else {
1998 for (int i = 0; i < names.length; i++) {
1999 builder.addAttribute(names[i], values[i]);
2000 }
2001 }
2002 }
2003 return builder.build();
2004 }
2005
2006 @Override
2007 public HtmlInfoNode[] newArray(int size) {
2008 return new HtmlInfoNode[size];
2009 }
2010 };
2011 }
2012
2013 private static final class HtmlInfoNodeBuilder extends HtmlInfo.Builder {
2014 private final String mTag;
2015 private ArrayList<String> mNames;
2016 private ArrayList<String> mValues;
2017
2018 HtmlInfoNodeBuilder(String tag) {
2019 mTag = tag;
2020 }
2021
2022 @Override
2023 public Builder addAttribute(String name, String value) {
2024 if (mNames == null) {
2025 mNames = new ArrayList<>();
2026 mValues = new ArrayList<>();
2027 }
2028 mNames.add(name);
2029 mValues.add(value);
2030 return this;
2031 }
2032
2033 @Override
2034 public HtmlInfoNode build() {
2035 return new HtmlInfoNode(this);
2036 }
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002037 }
2038
2039 /** @hide */
Svet Ganovfd31f852017-04-26 15:54:27 -07002040 public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07002041 mHaveData = true;
2042 mActivityComponent = activity.getComponentName();
Felipe Leme0aa4c502017-04-26 12:36:01 -07002043 mFlags = flags;
Dianne Hackborn16036f22015-06-22 14:05:51 -07002044 ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
2045 activity.getActivityToken());
2046 for (int i=0; i<views.size(); i++) {
2047 ViewRootImpl root = views.get(i);
Felipe Leme5cfcb5c2017-07-20 15:05:57 -07002048 if (root.getView() == null) {
2049 Log.w(TAG, "Skipping window with dettached view: " + root.getTitle());
2050 continue;
2051 }
Svet Ganovfd31f852017-04-26 15:54:27 -07002052 mWindowNodes.add(new WindowNode(this, root, forAutoFill, flags));
Dianne Hackborn16036f22015-06-22 14:05:51 -07002053 }
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002054 }
2055
Dianne Hackborn16036f22015-06-22 14:05:51 -07002056 public AssistStructure() {
2057 mHaveData = true;
2058 mActivityComponent = null;
Felipe Leme0aa4c502017-04-26 12:36:01 -07002059 mFlags = 0;
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002060 }
2061
Dianne Hackborn16036f22015-06-22 14:05:51 -07002062 /** @hide */
2063 public AssistStructure(Parcel in) {
Amith Yamasani858f98d2017-02-22 12:59:53 -08002064 mIsHomeActivity = in.readInt() == 1;
Dianne Hackborn16036f22015-06-22 14:05:51 -07002065 mReceiveChannel = in.readStrongBinder();
2066 }
2067
Felipe Leme0200d9e2017-01-24 15:10:26 -08002068 /**
2069 * Helper method used to sanitize the structure before it's written to a parcel.
2070 *
Felipe Leme640f30a2017-03-06 15:44:06 -08002071 * <p>Used just on autofill.
Felipe Leme0200d9e2017-01-24 15:10:26 -08002072 * @hide
2073 */
2074 public void sanitizeForParceling(boolean sanitize) {
2075 mSanitizeOnWrite = sanitize;
2076 }
2077
Dianne Hackborn16036f22015-06-22 14:05:51 -07002078 /** @hide */
Felipe Lemebc561eb2017-05-11 17:46:36 -07002079 public void dump(boolean showSensitive) {
Felipe Leme0200d9e2017-01-24 15:10:26 -08002080 if (mActivityComponent == null) {
2081 Log.i(TAG, "dump(): calling ensureData() first");
2082 ensureData();
2083 }
Dianne Hackborn16036f22015-06-22 14:05:51 -07002084 Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
Felipe Leme0200d9e2017-01-24 15:10:26 -08002085 Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
Felipe Leme0aa4c502017-04-26 12:36:01 -07002086 Log.i(TAG, "Flags: " + mFlags);
Dianne Hackborn16036f22015-06-22 14:05:51 -07002087 final int N = getWindowNodeCount();
2088 for (int i=0; i<N; i++) {
2089 WindowNode node = getWindowNodeAt(i);
2090 Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
2091 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
Felipe Lemebc561eb2017-05-11 17:46:36 -07002092 dump(" ", node.getRootViewNode(), showSensitive);
Dianne Hackborn16036f22015-06-22 14:05:51 -07002093 }
2094 }
2095
Felipe Lemebc561eb2017-05-11 17:46:36 -07002096 void dump(String prefix, ViewNode node, boolean showSensitive) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07002097 Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
2098 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
2099 int id = node.getId();
2100 if (id != 0) {
2101 StringBuilder sb = new StringBuilder();
2102 sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id));
2103 String entry = node.getIdEntry();
2104 if (entry != null) {
2105 String type = node.getIdType();
2106 String pkg = node.getIdPackage();
2107 sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
2108 sb.append("/"); sb.append(entry);
2109 }
2110 Log.i(TAG, sb.toString());
2111 }
2112 int scrollX = node.getScrollX();
2113 int scrollY = node.getScrollY();
2114 if (scrollX != 0 || scrollY != 0) {
2115 Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
2116 }
Dianne Hackborn70d8be72015-06-23 19:33:02 +00002117 Matrix matrix = node.getTransformation();
2118 if (matrix != null) {
2119 Log.i(TAG, prefix + " Transformation: " + matrix);
2120 }
2121 float elevation = node.getElevation();
2122 if (elevation != 0) {
2123 Log.i(TAG, prefix + " Elevation: " + elevation);
2124 }
2125 float alpha = node.getAlpha();
2126 if (alpha != 0) {
2127 Log.i(TAG, prefix + " Alpha: " + elevation);
2128 }
Dianne Hackborn16036f22015-06-22 14:05:51 -07002129 CharSequence contentDescription = node.getContentDescription();
2130 if (contentDescription != null) {
2131 Log.i(TAG, prefix + " Content description: " + contentDescription);
2132 }
2133 CharSequence text = node.getText();
2134 if (text != null) {
Felipe Lemebc561eb2017-05-11 17:46:36 -07002135 final String safeText = node.isSanitized() || showSensitive ? text.toString()
2136 : "REDACTED[" + text.length() + " chars]";
Dianne Hackborn16036f22015-06-22 14:05:51 -07002137 Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
Felipe Lemebc561eb2017-05-11 17:46:36 -07002138 + node.getTextSelectionEnd() + "): " + safeText);
Dianne Hackborn16036f22015-06-22 14:05:51 -07002139 Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
2140 + node.getTextStyle());
2141 Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
2142 + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
Felipe Lemebc561eb2017-05-11 17:46:36 -07002143 Log.i(TAG, prefix + " Input type: " + node.getInputType());
Felipe Leme5dc45ca2018-01-03 09:02:27 -08002144 Log.i(TAG, prefix + " Resource id: " + node.getTextIdEntry());
Dianne Hackborn16036f22015-06-22 14:05:51 -07002145 }
Felipe Leme4711ed92017-04-21 16:47:18 -07002146 String webDomain = node.getWebDomain();
2147 if (webDomain != null) {
2148 Log.i(TAG, prefix + " Web domain: " + webDomain);
Felipe Lemec3241002017-02-15 12:55:11 -08002149 }
Felipe Leme25bf7872017-03-28 15:32:29 -07002150 HtmlInfo htmlInfo = node.getHtmlInfo();
2151 if (htmlInfo != null) {
2152 Log.i(TAG, prefix + " HtmlInfo: tag=" + htmlInfo.getTag()
2153 + ", attr="+ htmlInfo.getAttributes());
2154 }
2155
Felipe Lemeb4ca7012017-03-22 18:30:07 -07002156 LocaleList localeList = node.getLocaleList();
2157 if (localeList != null) {
2158 Log.i(TAG, prefix + " LocaleList: " + localeList);
2159 }
Dianne Hackborn16036f22015-06-22 14:05:51 -07002160 String hint = node.getHint();
2161 if (hint != null) {
2162 Log.i(TAG, prefix + " Hint: " + hint);
2163 }
2164 Bundle extras = node.getExtras();
2165 if (extras != null) {
2166 Log.i(TAG, prefix + " Extras: " + extras);
2167 }
Dianne Hackbornafb308d2015-07-31 13:10:55 -07002168 if (node.isAssistBlocked()) {
2169 Log.i(TAG, prefix + " BLOCKED");
2170 }
Felipe Leme640f30a2017-03-06 15:44:06 -08002171 AutofillId autofillId = node.getAutofillId();
2172 if (autofillId == null) {
2173 Log.i(TAG, prefix + " NO autofill ID");
Felipe Leme0200d9e2017-01-24 15:10:26 -08002174 } else {
Felipe Leme640f30a2017-03-06 15:44:06 -08002175 Log.i(TAG, prefix + "Autofill info: id= " + autofillId
Felipe Leme8931e302017-03-06 13:44:35 -08002176 + ", type=" + node.getAutofillType()
Felipe Leme640f30a2017-03-06 15:44:06 -08002177 + ", options=" + Arrays.toString(node.getAutofillOptions())
Felipe Leme30e9b262017-04-21 11:29:30 -07002178 + ", hints=" + Arrays.toString(node.getAutofillHints())
Felipe Leme640f30a2017-03-06 15:44:06 -08002179 + ", value=" + node.getAutofillValue()
felipeal53308c12018-02-07 14:43:30 +01002180 + ", sanitized=" + node.isSanitized()
2181 + ", importantFor=" + node.getImportantForAutofill());
Felipe Leme0200d9e2017-01-24 15:10:26 -08002182 }
2183
Dianne Hackborn16036f22015-06-22 14:05:51 -07002184 final int NCHILDREN = node.getChildCount();
2185 if (NCHILDREN > 0) {
2186 Log.i(TAG, prefix + " Children:");
2187 String cprefix = prefix + " ";
2188 for (int i=0; i<NCHILDREN; i++) {
2189 ViewNode cnode = node.getChildAt(i);
Felipe Lemebc561eb2017-05-11 17:46:36 -07002190 dump(cprefix, cnode, showSensitive);
Dianne Hackborn16036f22015-06-22 14:05:51 -07002191 }
2192 }
2193 }
2194
2195 /**
2196 * Return the activity this AssistStructure came from.
2197 */
2198 public ComponentName getActivityComponent() {
2199 ensureData();
2200 return mActivityComponent;
2201 }
2202
Felipe Leme3f3fa1b2017-11-30 17:41:57 -08002203 /**
2204 * Called by Autofill server when app forged a different value.
2205 *
2206 * @hide
2207 */
2208 public void setActivityComponent(ComponentName componentName) {
2209 ensureData();
2210 mActivityComponent = componentName;
2211 }
2212
Felipe Leme0aa4c502017-04-26 12:36:01 -07002213 /** @hide */
2214 public int getFlags() {
2215 return mFlags;
2216 }
2217
Dianne Hackborn16036f22015-06-22 14:05:51 -07002218 /**
Amith Yamasani858f98d2017-02-22 12:59:53 -08002219 * Returns whether the activity associated with this AssistStructure was the home activity
Amith Yamasani86687822017-04-26 11:35:15 -07002220 * (Launcher) at the time the assist data was acquired.
Amith Yamasani858f98d2017-02-22 12:59:53 -08002221 * @return Whether the activity was the home activity.
Amith Yamasani86687822017-04-26 11:35:15 -07002222 * @see android.content.Intent#CATEGORY_HOME
Amith Yamasani858f98d2017-02-22 12:59:53 -08002223 */
2224 public boolean isHomeActivity() {
2225 return mIsHomeActivity;
2226 }
2227
2228 /**
Dianne Hackborn16036f22015-06-22 14:05:51 -07002229 * Return the number of window contents that have been collected in this assist data.
2230 */
2231 public int getWindowNodeCount() {
2232 ensureData();
2233 return mWindowNodes.size();
2234 }
2235
2236 /**
2237 * Return one of the windows in the assist data.
2238 * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
2239 */
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002240 public WindowNode getWindowNodeAt(int index) {
Dianne Hackborn16036f22015-06-22 14:05:51 -07002241 ensureData();
2242 return mWindowNodes.get(index);
2243 }
2244
Felipe Leme385ee532018-03-07 09:56:41 -08002245 // TODO(b/35708678): temporary method that disable one-way warning flag on binder.
2246 /** @hide */
2247 public void ensureDataForAutofill() {
2248 if (mHaveData) {
2249 return;
2250 }
2251 mHaveData = true;
2252 Binder.allowBlocking(mReceiveChannel);
2253 try {
2254 ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2255 reader.go();
2256 } finally {
2257 Binder.defaultBlocking(mReceiveChannel);
2258 }
2259 }
2260
Dianne Hackborn16036f22015-06-22 14:05:51 -07002261 /** @hide */
2262 public void ensureData() {
2263 if (mHaveData) {
2264 return;
2265 }
2266 mHaveData = true;
Dianne Hackborn782d4982015-07-08 17:36:37 -07002267 ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
2268 reader.go();
Dianne Hackborn16036f22015-06-22 14:05:51 -07002269 }
2270
Dianne Hackborn782d4982015-07-08 17:36:37 -07002271 boolean waitForReady() {
Dianne Hackborn16036f22015-06-22 14:05:51 -07002272 boolean skipStructure = false;
2273 synchronized (this) {
2274 long endTime = SystemClock.uptimeMillis() + 5000;
2275 long now;
2276 while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
2277 try {
2278 wait(endTime-now);
2279 } catch (InterruptedException e) {
2280 }
2281 }
2282 if (mPendingAsyncChildren.size() > 0) {
2283 // We waited too long, assume none of the assist structure is valid.
Dianne Hackborn70d8be72015-06-23 19:33:02 +00002284 Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
2285 + mPendingAsyncChildren.size() + " remaining");
Dianne Hackborn16036f22015-06-22 14:05:51 -07002286 skipStructure = true;
2287 }
2288 }
Dianne Hackborn782d4982015-07-08 17:36:37 -07002289 return !skipStructure;
Dianne Hackborn16036f22015-06-22 14:05:51 -07002290 }
2291
Dianne Hackborn782d4982015-07-08 17:36:37 -07002292 /** @hide */
2293 public void clearSendChannel() {
2294 if (mSendChannel != null) {
2295 mSendChannel.mAssistStructure = null;
Dianne Hackborn16036f22015-06-22 14:05:51 -07002296 }
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002297 }
2298
Felipe Leme0200d9e2017-01-24 15:10:26 -08002299 @Override
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002300 public int describeContents() {
2301 return 0;
2302 }
2303
Felipe Leme0200d9e2017-01-24 15:10:26 -08002304 @Override
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002305 public void writeToParcel(Parcel out, int flags) {
Amith Yamasani858f98d2017-02-22 12:59:53 -08002306 out.writeInt(mIsHomeActivity ? 1 : 0);
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002307 if (mHaveData) {
2308 // This object holds its data. We want to write a send channel that the
2309 // other side can use to retrieve that data.
2310 if (mSendChannel == null) {
Dianne Hackborn782d4982015-07-08 17:36:37 -07002311 mSendChannel = new SendChannel(this);
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002312 }
2313 out.writeStrongBinder(mSendChannel);
2314 } else {
2315 // This object doesn't hold its data, so just propagate along its receive channel.
2316 out.writeStrongBinder(mReceiveChannel);
2317 }
2318 }
2319
2320 public static final Parcelable.Creator<AssistStructure> CREATOR
2321 = new Parcelable.Creator<AssistStructure>() {
Felipe Leme0200d9e2017-01-24 15:10:26 -08002322 @Override
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002323 public AssistStructure createFromParcel(Parcel in) {
2324 return new AssistStructure(in);
2325 }
2326
Felipe Leme0200d9e2017-01-24 15:10:26 -08002327 @Override
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07002328 public AssistStructure[] newArray(int size) {
2329 return new AssistStructure[size];
2330 }
2331 };
2332}