1082 lines
32 KiB
Java
1082 lines
32 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2018 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
package android.view.contentcapture;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.annotation.TestApi;
|
||
|
import android.app.assist.AssistStructure;
|
||
|
import android.graphics.Matrix;
|
||
|
import android.graphics.Rect;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.LocaleList;
|
||
|
import android.os.Parcel;
|
||
|
import android.text.TextUtils;
|
||
|
import android.util.Log;
|
||
|
import android.view.View;
|
||
|
import android.view.ViewParent;
|
||
|
import android.view.ViewStructure;
|
||
|
import android.view.ViewStructure.HtmlInfo.Builder;
|
||
|
import android.view.autofill.AutofillId;
|
||
|
import android.view.autofill.AutofillValue;
|
||
|
|
||
|
import java.util.Objects;
|
||
|
|
||
|
//TODO(b/122484602): add javadocs / implement Parcelable / implement
|
||
|
//TODO(b/122484602): for now it's extending ViewNode directly as it needs most of its properties,
|
||
|
// but it might be better to create a common, abstract android.view.ViewNode class that both extend
|
||
|
// instead
|
||
|
/** @hide */
|
||
|
@SystemApi
|
||
|
public final class ViewNode extends AssistStructure.ViewNode {
|
||
|
|
||
|
private static final String TAG = ViewNode.class.getSimpleName();
|
||
|
|
||
|
private static final long FLAGS_HAS_TEXT = 1L << 0;
|
||
|
private static final long FLAGS_HAS_COMPLEX_TEXT = 1L << 1;
|
||
|
private static final long FLAGS_VISIBILITY_MASK = View.VISIBLE | View.INVISIBLE | View.GONE;
|
||
|
private static final long FLAGS_HAS_CLASSNAME = 1L << 4;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_ID = 1L << 5;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_PARENT_ID = 1L << 6;
|
||
|
private static final long FLAGS_HAS_ID = 1L << 7;
|
||
|
private static final long FLAGS_HAS_LARGE_COORDS = 1L << 8;
|
||
|
private static final long FLAGS_HAS_SCROLL = 1L << 9;
|
||
|
private static final long FLAGS_ASSIST_BLOCKED = 1L << 10;
|
||
|
private static final long FLAGS_DISABLED = 1L << 11;
|
||
|
private static final long FLAGS_CLICKABLE = 1L << 12;
|
||
|
private static final long FLAGS_LONG_CLICKABLE = 1L << 13;
|
||
|
private static final long FLAGS_CONTEXT_CLICKABLE = 1L << 14;
|
||
|
private static final long FLAGS_FOCUSABLE = 1L << 15;
|
||
|
private static final long FLAGS_FOCUSED = 1L << 16;
|
||
|
private static final long FLAGS_ACCESSIBILITY_FOCUSED = 1L << 17;
|
||
|
private static final long FLAGS_CHECKABLE = 1L << 18;
|
||
|
private static final long FLAGS_CHECKED = 1L << 19;
|
||
|
private static final long FLAGS_SELECTED = 1L << 20;
|
||
|
private static final long FLAGS_ACTIVATED = 1L << 21;
|
||
|
private static final long FLAGS_OPAQUE = 1L << 22;
|
||
|
private static final long FLAGS_HAS_CONTENT_DESCRIPTION = 1L << 23;
|
||
|
private static final long FLAGS_HAS_EXTRAS = 1L << 24;
|
||
|
private static final long FLAGS_HAS_LOCALE_LIST = 1L << 25;
|
||
|
private static final long FLAGS_HAS_INPUT_TYPE = 1L << 26;
|
||
|
private static final long FLAGS_HAS_MIN_TEXT_EMS = 1L << 27;
|
||
|
private static final long FLAGS_HAS_MAX_TEXT_EMS = 1L << 28;
|
||
|
private static final long FLAGS_HAS_MAX_TEXT_LENGTH = 1L << 29;
|
||
|
private static final long FLAGS_HAS_TEXT_ID_ENTRY = 1L << 30;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_TYPE = 1L << 31;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 32;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
|
||
|
private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
|
||
|
private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35;
|
||
|
private static final long FLAGS_HAS_MIME_TYPES = 1L << 36;
|
||
|
|
||
|
/** Flags used to optimize what's written to the parcel */
|
||
|
private long mFlags;
|
||
|
|
||
|
private AutofillId mParentAutofillId;
|
||
|
|
||
|
private AutofillId mAutofillId;
|
||
|
private ViewNodeText mText;
|
||
|
private String mClassName;
|
||
|
private int mId = View.NO_ID;
|
||
|
private String mIdPackage;
|
||
|
private String mIdType;
|
||
|
private String mIdEntry;
|
||
|
private int mX;
|
||
|
private int mY;
|
||
|
private int mScrollX;
|
||
|
private int mScrollY;
|
||
|
private int mWidth;
|
||
|
private int mHeight;
|
||
|
private CharSequence mContentDescription;
|
||
|
private Bundle mExtras;
|
||
|
private LocaleList mLocaleList;
|
||
|
private int mInputType;
|
||
|
private int mMinEms = -1;
|
||
|
private int mMaxEms = -1;
|
||
|
private int mMaxLength = -1;
|
||
|
private String mTextIdEntry;
|
||
|
private String mHintIdEntry;
|
||
|
private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
|
||
|
private String[] mAutofillHints;
|
||
|
private AutofillValue mAutofillValue;
|
||
|
private CharSequence[] mAutofillOptions;
|
||
|
private String[] mReceiveContentMimeTypes;
|
||
|
|
||
|
/** @hide */
|
||
|
public ViewNode() {
|
||
|
}
|
||
|
|
||
|
private ViewNode(long nodeFlags, @NonNull Parcel parcel) {
|
||
|
mFlags = nodeFlags;
|
||
|
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
|
||
|
mAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
|
||
|
mParentAutofillId = parcel.readParcelable(null, android.view.autofill.AutofillId.class);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
|
||
|
mText = new ViewNodeText(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
|
||
|
mClassName = parcel.readString();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_ID) != 0) {
|
||
|
mId = parcel.readInt();
|
||
|
if (mId != View.NO_ID) {
|
||
|
mIdEntry = parcel.readString();
|
||
|
if (mIdEntry != null) {
|
||
|
mIdType = parcel.readString();
|
||
|
mIdPackage = parcel.readString();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
|
||
|
mX = parcel.readInt();
|
||
|
mY = parcel.readInt();
|
||
|
mWidth = parcel.readInt();
|
||
|
mHeight = parcel.readInt();
|
||
|
} else {
|
||
|
int val = parcel.readInt();
|
||
|
mX = val & 0x7fff;
|
||
|
mY = (val >> 16) & 0x7fff;
|
||
|
val = parcel.readInt();
|
||
|
mWidth = val & 0x7fff;
|
||
|
mHeight = (val >> 16) & 0x7fff;
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
|
||
|
mScrollX = parcel.readInt();
|
||
|
mScrollY = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
|
||
|
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
|
||
|
mExtras = parcel.readBundle();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
|
||
|
mLocaleList = parcel.readParcelable(null, android.os.LocaleList.class);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
|
||
|
mReceiveContentMimeTypes = parcel.readStringArray();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
|
||
|
mInputType = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
|
||
|
mMinEms = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
|
||
|
mMaxEms = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
|
||
|
mMaxLength = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
|
||
|
mTextIdEntry = parcel.readString();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
|
||
|
mAutofillType = parcel.readInt();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
|
||
|
mAutofillHints = parcel.readStringArray();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
|
||
|
mAutofillValue = parcel.readParcelable(null, android.view.autofill.AutofillValue.class);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
|
||
|
mAutofillOptions = parcel.readCharSequenceArray();
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
|
||
|
mHintIdEntry = parcel.readString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the {@link AutofillId} of this view's parent, if the parent is also part of the
|
||
|
* screen observation tree.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public AutofillId getParentAutofillId() {
|
||
|
return mParentAutofillId;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public AutofillId getAutofillId() {
|
||
|
return mAutofillId;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public CharSequence getText() {
|
||
|
return mText != null ? mText.mText : null;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getClassName() {
|
||
|
return mClassName;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getId() {
|
||
|
return mId;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getIdPackage() {
|
||
|
return mIdPackage;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getIdType() {
|
||
|
return mIdType;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getIdEntry() {
|
||
|
return mIdEntry;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getLeft() {
|
||
|
return mX;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTop() {
|
||
|
return mY;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getScrollX() {
|
||
|
return mScrollX;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getScrollY() {
|
||
|
return mScrollY;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getWidth() {
|
||
|
return mWidth;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getHeight() {
|
||
|
return mHeight;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isAssistBlocked() {
|
||
|
return (mFlags & FLAGS_ASSIST_BLOCKED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isEnabled() {
|
||
|
return (mFlags & FLAGS_DISABLED) == 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isClickable() {
|
||
|
return (mFlags & FLAGS_CLICKABLE) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isLongClickable() {
|
||
|
return (mFlags & FLAGS_LONG_CLICKABLE) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isContextClickable() {
|
||
|
return (mFlags & FLAGS_CONTEXT_CLICKABLE) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isFocusable() {
|
||
|
return (mFlags & FLAGS_FOCUSABLE) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isFocused() {
|
||
|
return (mFlags & FLAGS_FOCUSED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isAccessibilityFocused() {
|
||
|
return (mFlags & FLAGS_ACCESSIBILITY_FOCUSED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isCheckable() {
|
||
|
return (mFlags & FLAGS_CHECKABLE) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isChecked() {
|
||
|
return (mFlags & FLAGS_CHECKED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isSelected() {
|
||
|
return (mFlags & FLAGS_SELECTED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isActivated() {
|
||
|
return (mFlags & FLAGS_ACTIVATED) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isOpaque() {
|
||
|
return (mFlags & FLAGS_OPAQUE) != 0;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public CharSequence getContentDescription() {
|
||
|
return mContentDescription;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public Bundle getExtras() {
|
||
|
return mExtras;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getHint() {
|
||
|
return mText != null ? mText.mHint : null;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getHintIdEntry() {
|
||
|
return mHintIdEntry;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextSelectionStart() {
|
||
|
return mText != null ? mText.mTextSelectionStart : -1;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextSelectionEnd() {
|
||
|
return mText != null ? mText.mTextSelectionEnd : -1;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextColor() {
|
||
|
return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextBackgroundColor() {
|
||
|
return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public float getTextSize() {
|
||
|
return mText != null ? mText.mTextSize : 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextStyle() {
|
||
|
return mText != null ? mText.mTextStyle : 0;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public int[] getTextLineCharOffsets() {
|
||
|
return mText != null ? mText.mLineCharOffsets : null;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public int[] getTextLineBaselines() {
|
||
|
return mText != null ? mText.mLineBaselines : null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getVisibility() {
|
||
|
return (int) (mFlags & FLAGS_VISIBILITY_MASK);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getInputType() {
|
||
|
return mInputType;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getMinTextEms() {
|
||
|
return mMinEms;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getMaxTextEms() {
|
||
|
return mMaxEms;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getMaxTextLength() {
|
||
|
return mMaxLength;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public String getTextIdEntry() {
|
||
|
return mTextIdEntry;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public @View.AutofillType int getAutofillType() {
|
||
|
return mAutofillType;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@Nullable public String[] getAutofillHints() {
|
||
|
return mAutofillHints;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@Nullable public AutofillValue getAutofillValue() {
|
||
|
return mAutofillValue;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@Nullable public CharSequence[] getAutofillOptions() {
|
||
|
return mAutofillOptions;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@Nullable
|
||
|
public String[] getReceiveContentMimeTypes() {
|
||
|
return mReceiveContentMimeTypes;
|
||
|
}
|
||
|
|
||
|
@Nullable
|
||
|
@Override
|
||
|
public LocaleList getLocaleList() {
|
||
|
return mLocaleList;
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
public void setTextIdEntry(@NonNull String textIdEntry) {
|
||
|
mTextIdEntry = textIdEntry;
|
||
|
}
|
||
|
|
||
|
private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) {
|
||
|
long nodeFlags = mFlags;
|
||
|
|
||
|
if (mAutofillId != null) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_ID;
|
||
|
}
|
||
|
|
||
|
if (mParentAutofillId != null) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_PARENT_ID;
|
||
|
}
|
||
|
|
||
|
if (mText != null) {
|
||
|
nodeFlags |= FLAGS_HAS_TEXT;
|
||
|
if (!mText.isSimple()) {
|
||
|
nodeFlags |= FLAGS_HAS_COMPLEX_TEXT;
|
||
|
}
|
||
|
}
|
||
|
if (mClassName != null) {
|
||
|
nodeFlags |= FLAGS_HAS_CLASSNAME;
|
||
|
}
|
||
|
if (mId != View.NO_ID) {
|
||
|
nodeFlags |= FLAGS_HAS_ID;
|
||
|
}
|
||
|
if ((mX & ~0x7fff) != 0 || (mY & ~0x7fff) != 0
|
||
|
|| (mWidth & ~0x7fff) != 0 | (mHeight & ~0x7fff) != 0) {
|
||
|
nodeFlags |= FLAGS_HAS_LARGE_COORDS;
|
||
|
}
|
||
|
if (mScrollX != 0 || mScrollY != 0) {
|
||
|
nodeFlags |= FLAGS_HAS_SCROLL;
|
||
|
}
|
||
|
if (mContentDescription != null) {
|
||
|
nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION;
|
||
|
}
|
||
|
if (mExtras != null) {
|
||
|
nodeFlags |= FLAGS_HAS_EXTRAS;
|
||
|
}
|
||
|
if (mLocaleList != null) {
|
||
|
nodeFlags |= FLAGS_HAS_LOCALE_LIST;
|
||
|
}
|
||
|
if (mReceiveContentMimeTypes != null) {
|
||
|
nodeFlags |= FLAGS_HAS_MIME_TYPES;
|
||
|
}
|
||
|
if (mInputType != 0) {
|
||
|
nodeFlags |= FLAGS_HAS_INPUT_TYPE;
|
||
|
}
|
||
|
if (mMinEms > -1) {
|
||
|
nodeFlags |= FLAGS_HAS_MIN_TEXT_EMS;
|
||
|
}
|
||
|
if (mMaxEms > -1) {
|
||
|
nodeFlags |= FLAGS_HAS_MAX_TEXT_EMS;
|
||
|
}
|
||
|
if (mMaxLength > -1) {
|
||
|
nodeFlags |= FLAGS_HAS_MAX_TEXT_LENGTH;
|
||
|
}
|
||
|
if (mTextIdEntry != null) {
|
||
|
nodeFlags |= FLAGS_HAS_TEXT_ID_ENTRY;
|
||
|
}
|
||
|
if (mAutofillValue != null) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_VALUE;
|
||
|
}
|
||
|
if (mAutofillType != View.AUTOFILL_TYPE_NONE) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_TYPE;
|
||
|
}
|
||
|
if (mAutofillHints != null) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_HINTS;
|
||
|
}
|
||
|
if (mAutofillOptions != null) {
|
||
|
nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS;
|
||
|
}
|
||
|
if (mHintIdEntry != null) {
|
||
|
nodeFlags |= FLAGS_HAS_HINT_ID_ENTRY;
|
||
|
}
|
||
|
parcel.writeLong(nodeFlags);
|
||
|
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
|
||
|
parcel.writeParcelable(mAutofillId, parcelFlags);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
|
||
|
parcel.writeParcelable(mParentAutofillId, parcelFlags);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
|
||
|
mText.writeToParcel(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
|
||
|
parcel.writeString(mClassName);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_ID) != 0) {
|
||
|
parcel.writeInt(mId);
|
||
|
if (mId != View.NO_ID) {
|
||
|
parcel.writeString(mIdEntry);
|
||
|
if (mIdEntry != null) {
|
||
|
parcel.writeString(mIdType);
|
||
|
parcel.writeString(mIdPackage);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
|
||
|
parcel.writeInt(mX);
|
||
|
parcel.writeInt(mY);
|
||
|
parcel.writeInt(mWidth);
|
||
|
parcel.writeInt(mHeight);
|
||
|
} else {
|
||
|
parcel.writeInt((mY << 16) | mX);
|
||
|
parcel.writeInt((mHeight << 16) | mWidth);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
|
||
|
parcel.writeInt(mScrollX);
|
||
|
parcel.writeInt(mScrollY);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
|
||
|
TextUtils.writeToParcel(mContentDescription, parcel, 0);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
|
||
|
parcel.writeBundle(mExtras);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
|
||
|
parcel.writeParcelable(mLocaleList, 0);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
|
||
|
parcel.writeStringArray(mReceiveContentMimeTypes);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
|
||
|
parcel.writeInt(mInputType);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
|
||
|
parcel.writeInt(mMinEms);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
|
||
|
parcel.writeInt(mMaxEms);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
|
||
|
parcel.writeInt(mMaxLength);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
|
||
|
parcel.writeString(mTextIdEntry);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
|
||
|
parcel.writeInt(mAutofillType);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
|
||
|
parcel.writeStringArray(mAutofillHints);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
|
||
|
parcel.writeParcelable(mAutofillValue, 0);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
|
||
|
parcel.writeCharSequenceArray(mAutofillOptions);
|
||
|
}
|
||
|
if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
|
||
|
parcel.writeString(mHintIdEntry);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) {
|
||
|
if (node == null) {
|
||
|
parcel.writeLong(0);
|
||
|
} else {
|
||
|
node.writeSelfToParcel(parcel, flags);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) {
|
||
|
final long nodeFlags = parcel.readLong();
|
||
|
return nodeFlags == 0 ? null : new ViewNode(nodeFlags, parcel);
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public static final class ViewStructureImpl extends ViewStructure {
|
||
|
|
||
|
final ViewNode mNode = new ViewNode();
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public ViewStructureImpl(@NonNull View view) {
|
||
|
mNode.mAutofillId = Objects.requireNonNull(view).getAutofillId();
|
||
|
final ViewParent parent = view.getParent();
|
||
|
if (parent instanceof View) {
|
||
|
mNode.mParentAutofillId = ((View) parent).getAutofillId();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public ViewStructureImpl(@NonNull AutofillId parentId, long virtualId, int sessionId) {
|
||
|
mNode.mParentAutofillId = Objects.requireNonNull(parentId);
|
||
|
mNode.mAutofillId = new AutofillId(parentId, virtualId, sessionId);
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@TestApi
|
||
|
public ViewNode getNode() {
|
||
|
return mNode;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setId(int id, String packageName, String typeName, String entryName) {
|
||
|
mNode.mId = id;
|
||
|
mNode.mIdPackage = packageName;
|
||
|
mNode.mIdType = typeName;
|
||
|
mNode.mIdEntry = entryName;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
|
||
|
mNode.mX = left;
|
||
|
mNode.mY = top;
|
||
|
mNode.mScrollX = scrollX;
|
||
|
mNode.mScrollY = scrollY;
|
||
|
mNode.mWidth = width;
|
||
|
mNode.mHeight = height;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTransformation(Matrix matrix) {
|
||
|
Log.w(TAG, "setTransformation() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setElevation(float elevation) {
|
||
|
Log.w(TAG, "setElevation() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAlpha(float alpha) {
|
||
|
Log.w(TAG, "setAlpha() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setVisibility(int visibility) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_VISIBILITY_MASK)
|
||
|
| (visibility & FLAGS_VISIBILITY_MASK);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAssistBlocked(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_ASSIST_BLOCKED)
|
||
|
| (state ? FLAGS_ASSIST_BLOCKED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setEnabled(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_DISABLED) | (state ? 0 : FLAGS_DISABLED);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setClickable(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_CLICKABLE) | (state ? FLAGS_CLICKABLE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setLongClickable(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_LONG_CLICKABLE)
|
||
|
| (state ? FLAGS_LONG_CLICKABLE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setContextClickable(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_CONTEXT_CLICKABLE)
|
||
|
| (state ? FLAGS_CONTEXT_CLICKABLE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setFocusable(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSABLE) | (state ? FLAGS_FOCUSABLE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setFocused(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSED) | (state ? FLAGS_FOCUSED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAccessibilityFocused(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_ACCESSIBILITY_FOCUSED)
|
||
|
| (state ? FLAGS_ACCESSIBILITY_FOCUSED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setCheckable(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKABLE) | (state ? FLAGS_CHECKABLE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setChecked(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKED) | (state ? FLAGS_CHECKED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setSelected(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_SELECTED) | (state ? FLAGS_SELECTED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setActivated(boolean state) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_ACTIVATED) | (state ? FLAGS_ACTIVATED : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setOpaque(boolean opaque) {
|
||
|
mNode.mFlags = (mNode.mFlags & ~FLAGS_OPAQUE) | (opaque ? FLAGS_OPAQUE : 0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setClassName(String className) {
|
||
|
mNode.mClassName = className;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setContentDescription(CharSequence contentDescription) {
|
||
|
mNode.mContentDescription = contentDescription;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setText(CharSequence text) {
|
||
|
final ViewNodeText t = getNodeText();
|
||
|
t.mText = TextUtils.trimNoCopySpans(text);
|
||
|
t.mTextSelectionStart = t.mTextSelectionEnd = -1;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setText(CharSequence text, int selectionStart, int selectionEnd) {
|
||
|
final ViewNodeText t = getNodeText();
|
||
|
t.mText = TextUtils.trimNoCopySpans(text);
|
||
|
t.mTextSelectionStart = selectionStart;
|
||
|
t.mTextSelectionEnd = selectionEnd;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTextStyle(float size, int fgColor, int bgColor, int style) {
|
||
|
final ViewNodeText t = getNodeText();
|
||
|
t.mTextColor = fgColor;
|
||
|
t.mTextBackgroundColor = bgColor;
|
||
|
t.mTextSize = size;
|
||
|
t.mTextStyle = style;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTextLines(int[] charOffsets, int[] baselines) {
|
||
|
final ViewNodeText t = getNodeText();
|
||
|
t.mLineCharOffsets = charOffsets;
|
||
|
t.mLineBaselines = baselines;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTextIdEntry(@NonNull String entryName) {
|
||
|
mNode.mTextIdEntry = Objects.requireNonNull(entryName);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setHint(CharSequence hint) {
|
||
|
getNodeText().mHint = hint != null ? hint.toString() : null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setHintIdEntry(String entryName) {
|
||
|
mNode.mHintIdEntry = Objects.requireNonNull(entryName);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public CharSequence getText() {
|
||
|
return mNode.getText();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextSelectionStart() {
|
||
|
return mNode.getTextSelectionStart();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getTextSelectionEnd() {
|
||
|
return mNode.getTextSelectionEnd();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public CharSequence getHint() {
|
||
|
return mNode.getHint();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Bundle getExtras() {
|
||
|
if (mNode.mExtras != null) {
|
||
|
return mNode.mExtras;
|
||
|
}
|
||
|
mNode.mExtras = new Bundle();
|
||
|
return mNode.mExtras;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean hasExtras() {
|
||
|
return mNode.mExtras != null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setChildCount(int num) {
|
||
|
Log.w(TAG, "setChildCount() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int addChildCount(int num) {
|
||
|
Log.w(TAG, "addChildCount() is not supported");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getChildCount() {
|
||
|
Log.w(TAG, "getChildCount() is not supported");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public ViewStructure newChild(int index) {
|
||
|
Log.w(TAG, "newChild() is not supported");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public ViewStructure asyncNewChild(int index) {
|
||
|
Log.w(TAG, "asyncNewChild() is not supported");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public AutofillId getAutofillId() {
|
||
|
return mNode.mAutofillId;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillId(AutofillId id) {
|
||
|
mNode.mAutofillId = Objects.requireNonNull(id);
|
||
|
}
|
||
|
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillId(AutofillId parentId, int virtualId) {
|
||
|
mNode.mParentAutofillId = Objects.requireNonNull(parentId);
|
||
|
mNode.mAutofillId = new AutofillId(parentId, virtualId);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillType(@View.AutofillType int type) {
|
||
|
mNode.mAutofillType = type;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
|
||
|
mNode.mReceiveContentMimeTypes = mimeTypes;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillHints(String[] hints) {
|
||
|
mNode.mAutofillHints = hints;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillValue(AutofillValue value) {
|
||
|
mNode.mAutofillValue = value;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAutofillOptions(CharSequence[] options) {
|
||
|
mNode.mAutofillOptions = options;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setInputType(int inputType) {
|
||
|
mNode.mInputType = inputType;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setMinTextEms(int minEms) {
|
||
|
mNode.mMinEms = minEms;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setMaxTextEms(int maxEms) {
|
||
|
mNode.mMaxEms = maxEms;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setMaxTextLength(int maxLength) {
|
||
|
mNode.mMaxLength = maxLength;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setDataIsSensitive(boolean sensitive) {
|
||
|
Log.w(TAG, "setDataIsSensitive() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void asyncCommit() {
|
||
|
Log.w(TAG, "asyncCommit() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Rect getTempRect() {
|
||
|
Log.w(TAG, "getTempRect() is not supported");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setWebDomain(String domain) {
|
||
|
Log.w(TAG, "setWebDomain() is not supported");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setLocaleList(LocaleList localeList) {
|
||
|
mNode.mLocaleList = localeList;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Builder newHtmlInfoBuilder(String tagName) {
|
||
|
Log.w(TAG, "newHtmlInfoBuilder() is not supported");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setHtmlInfo(HtmlInfo htmlInfo) {
|
||
|
Log.w(TAG, "setHtmlInfo() is not supported");
|
||
|
}
|
||
|
|
||
|
private ViewNodeText getNodeText() {
|
||
|
if (mNode.mText != null) {
|
||
|
return mNode.mText;
|
||
|
}
|
||
|
mNode.mText = new ViewNodeText();
|
||
|
return mNode.mText;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//TODO(b/122484602): copied 'as-is' from AssistStructure, except for writeSensitive
|
||
|
static final class ViewNodeText {
|
||
|
CharSequence mText;
|
||
|
float mTextSize;
|
||
|
int mTextStyle;
|
||
|
int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
|
||
|
int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
|
||
|
int mTextSelectionStart;
|
||
|
int mTextSelectionEnd;
|
||
|
int[] mLineCharOffsets;
|
||
|
int[] mLineBaselines;
|
||
|
String mHint;
|
||
|
|
||
|
ViewNodeText() {
|
||
|
}
|
||
|
|
||
|
boolean isSimple() {
|
||
|
return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
|
||
|
&& mTextSelectionStart == 0 && mTextSelectionEnd == 0
|
||
|
&& mLineCharOffsets == null && mLineBaselines == null && mHint == null;
|
||
|
}
|
||
|
|
||
|
ViewNodeText(Parcel in, boolean simple) {
|
||
|
mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||
|
mTextSize = in.readFloat();
|
||
|
mTextStyle = in.readInt();
|
||
|
mTextColor = in.readInt();
|
||
|
if (!simple) {
|
||
|
mTextBackgroundColor = in.readInt();
|
||
|
mTextSelectionStart = in.readInt();
|
||
|
mTextSelectionEnd = in.readInt();
|
||
|
mLineCharOffsets = in.createIntArray();
|
||
|
mLineBaselines = in.createIntArray();
|
||
|
mHint = in.readString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void writeToParcel(Parcel out, boolean simple) {
|
||
|
CharSequence text = TextUtils.trimToParcelableSize(mText);
|
||
|
TextUtils.writeToParcel(text, out, 0);
|
||
|
out.writeFloat(mTextSize);
|
||
|
out.writeInt(mTextStyle);
|
||
|
out.writeInt(mTextColor);
|
||
|
if (!simple) {
|
||
|
int selectionStart = text != null
|
||
|
? Math.min(mTextSelectionStart, text.length())
|
||
|
: mTextSelectionStart;
|
||
|
int selectionEnd = text != null
|
||
|
? Math.min(mTextSelectionEnd, text.length())
|
||
|
: mTextSelectionEnd;
|
||
|
out.writeInt(mTextBackgroundColor);
|
||
|
out.writeInt(selectionStart);
|
||
|
out.writeInt(selectionEnd);
|
||
|
out.writeIntArray(mLineCharOffsets);
|
||
|
out.writeIntArray(mLineBaselines);
|
||
|
out.writeString(mHint);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|