| /* |
| * 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.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 com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.util.Preconditions; |
| |
| //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 boolean VERBOSE = false; |
| |
| 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_MATRIX = 1L << 23; |
| private static final long FLAGS_HAS_ELEVATION = 1L << 24; |
| private static final long FLAGS_HAS_ALPHA = 1L << 25; |
| private static final long FLAGS_HAS_CONTENT_DESCRIPTION = 1L << 26; |
| private static final long FLAGS_HAS_EXTRAS = 1L << 27; |
| private static final long FLAGS_HAS_LOCALE_LIST = 1L << 28; |
| private static final long FLAGS_HAS_INPUT_TYPE = 1L << 29; |
| private static final long FLAGS_HAS_MIN_TEXT_EMS = 1L << 30; |
| private static final long FLAGS_HAS_MAX_TEXT_EMS = 1L << 31; |
| private static final long FLAGS_HAS_MAX_TEXT_LENGTH = 1L << 32; |
| private static final long FLAGS_HAS_TEXT_ID_ENTRY = 1L << 33; |
| private static final long FLAGS_HAS_AUTOFILL_TYPE = 1L << 34; |
| private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 35; |
| private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 36; |
| private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 37; |
| |
| /** 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 Matrix mMatrix; |
| private float mElevation; |
| private float mAlpha = 1.0f; |
| 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 @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE; |
| private String[] mAutofillHints; |
| private AutofillValue mAutofillValue; |
| private CharSequence[] mAutofillOptions; |
| |
| /** @hide */ |
| public ViewNode() { |
| } |
| |
| private ViewNode(long nodeFlags, @NonNull Parcel parcel) { |
| mFlags = nodeFlags; |
| |
| if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) { |
| mAutofillId = parcel.readParcelable(null); |
| } |
| if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) { |
| mParentAutofillId = parcel.readParcelable(null); |
| } |
| 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_MATRIX) != 0) { |
| mMatrix = new Matrix(); |
| final float[] tmpMatrix = new float[9]; |
| parcel.readFloatArray(tmpMatrix); |
| mMatrix.setValues(tmpMatrix); |
| } |
| if ((nodeFlags & FLAGS_HAS_ELEVATION) != 0) { |
| mElevation = parcel.readFloat(); |
| } |
| if ((nodeFlags & FLAGS_HAS_ALPHA) != 0) { |
| mAlpha = parcel.readFloat(); |
| } |
| 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); |
| } |
| 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); |
| } |
| if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) { |
| mAutofillOptions = parcel.readCharSequenceArray(); |
| } |
| } |
| |
| /** |
| * 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; |
| } |
| |
| @Override |
| public AutofillId getAutofillId() { |
| return mAutofillId; |
| } |
| |
| @Override |
| public CharSequence getText() { |
| return mText != null ? mText.mText : null; |
| } |
| |
| @Override |
| public String getClassName() { |
| return mClassName; |
| } |
| |
| @Override |
| public int getId() { |
| return mId; |
| } |
| |
| @Override |
| public String getIdPackage() { |
| return mIdPackage; |
| } |
| |
| @Override |
| public String getIdType() { |
| return mIdType; |
| } |
| |
| @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; |
| } |
| |
| @Override |
| public Matrix getTransformation() { |
| return mMatrix; |
| } |
| |
| @Override |
| public float getElevation() { |
| return mElevation; |
| } |
| |
| @Override |
| public float getAlpha() { |
| return mAlpha; |
| } |
| |
| @Override |
| public CharSequence getContentDescription() { |
| return mContentDescription; |
| } |
| |
| @Override |
| public Bundle getExtras() { |
| return mExtras; |
| } |
| |
| @Override |
| public String getHint() { |
| return mText != null ? mText.mHint : null; |
| } |
| |
| @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; |
| } |
| |
| @Override |
| public int[] getTextLineCharOffsets() { |
| return mText != null ? mText.mLineCharOffsets : null; |
| } |
| |
| @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; |
| } |
| |
| @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 |
| public LocaleList getLocaleList() { |
| return mLocaleList; |
| } |
| |
| 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 (mMatrix != null) { |
| nodeFlags |= FLAGS_HAS_MATRIX; |
| } |
| if (mElevation != 0) { |
| nodeFlags |= FLAGS_HAS_ELEVATION; |
| } |
| if (mAlpha != 1.0f) { |
| nodeFlags |= FLAGS_HAS_ALPHA; |
| } |
| if (mContentDescription != null) { |
| nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION; |
| } |
| if (mExtras != null) { |
| nodeFlags |= FLAGS_HAS_EXTRAS; |
| } |
| if (mLocaleList != null) { |
| nodeFlags |= FLAGS_HAS_LOCALE_LIST; |
| } |
| 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; |
| } |
| 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_MATRIX) != 0) { |
| //TODO(b/122484602): use a singleton tmpMatrix (if logic is not moved to superclass) |
| final float[] tmpMatrix = new float[9]; |
| mMatrix.getValues(tmpMatrix); |
| parcel.writeFloatArray(tmpMatrix); |
| } |
| if ((nodeFlags & FLAGS_HAS_ELEVATION) != 0) { |
| parcel.writeFloat(mElevation); |
| } |
| if ((nodeFlags & FLAGS_HAS_ALPHA) != 0) { |
| parcel.writeFloat(mAlpha); |
| } |
| 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_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); |
| } |
| } |
| |
| /** @hide */ |
| public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) { |
| if (node == null) { |
| parcel.writeLong(0); |
| } else { |
| node.writeSelfToParcel(parcel, flags); |
| } |
| } |
| |
| /** @hide */ |
| public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) { |
| final long nodeFlags = parcel.readLong(); |
| return nodeFlags == 0 ? new ViewNode() : new ViewNode(nodeFlags, parcel); |
| } |
| |
| /** @hide */ |
| @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk. |
| public static final class ViewStructureImpl extends ViewStructure { |
| |
| final ViewNode mNode = new ViewNode(); |
| |
| @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk. |
| public ViewStructureImpl(@NonNull View view) { |
| mNode.mAutofillId = Preconditions.checkNotNull(view).getAutofillId(); |
| final ViewParent parent = view.getParent(); |
| if (parent instanceof View) { |
| mNode.mParentAutofillId = ((View) parent).getAutofillId(); |
| } |
| } |
| |
| @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk. |
| public ViewStructureImpl(@NonNull AutofillId parentId, int virtualId) { |
| mNode.mParentAutofillId = Preconditions.checkNotNull(parentId); |
| mNode.mAutofillId = new AutofillId(parentId, virtualId); |
| } |
| |
| @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk. |
| 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) { |
| if (matrix == null) { |
| mNode.mMatrix = null; |
| } else { |
| mNode.mMatrix = new Matrix(matrix); |
| } |
| } |
| |
| @Override |
| public void setElevation(float elevation) { |
| mNode.mElevation = elevation; |
| } |
| |
| @Override |
| public void setAlpha(float alpha) { |
| mNode.mAlpha = alpha; |
| } |
| |
| @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(String entryName) { |
| mNode.mTextIdEntry = Preconditions.checkNotNull(entryName); |
| } |
| |
| @Override |
| public void setHint(CharSequence hint) { |
| getNodeText().mHint = hint != null ? hint.toString() : null; |
| } |
| |
| @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 = Preconditions.checkNotNull(id); |
| } |
| |
| |
| @Override |
| public void setAutofillId(AutofillId parentId, int virtualId) { |
| mNode.mParentAutofillId = Preconditions.checkNotNull(parentId); |
| mNode.mAutofillId = new AutofillId(parentId, virtualId); |
| } |
| |
| @Override |
| public void setAutofillType(@View.AutofillType int type) { |
| mNode.mAutofillType = type; |
| } |
| |
| @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) { |
| TextUtils.writeToParcel(mText, out, 0); |
| out.writeFloat(mTextSize); |
| out.writeInt(mTextStyle); |
| out.writeInt(mTextColor); |
| if (!simple) { |
| out.writeInt(mTextBackgroundColor); |
| out.writeInt(mTextSelectionStart); |
| out.writeInt(mTextSelectionEnd); |
| out.writeIntArray(mLineCharOffsets); |
| out.writeIntArray(mLineBaselines); |
| out.writeString(mHint); |
| } |
| } |
| } |
| } |