summaryrefslogtreecommitdiffstats
path: root/core/java/android/app/AssistStructure.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/app/AssistStructure.java')
-rw-r--r--core/java/android/app/AssistStructure.java618
1 files changed, 618 insertions, 0 deletions
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
new file mode 100644
index 0000000..25153fc
--- /dev/null
+++ b/core/java/android/app/AssistStructure.java
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2015 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.app;
+
+import android.content.ComponentName;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PooledStringReader;
+import android.os.PooledStringWriter;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAssistStructure;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+import android.widget.Checkable;
+
+import java.util.ArrayList;
+
+/**
+ * Assist data automatically created by the platform's implementation
+ * of {@link Activity#onProvideAssistData}. Retrieve it from the assist
+ * data with {@link #getAssistStructure(android.os.Bundle)}.
+ */
+final public class AssistStructure implements Parcelable {
+ static final String TAG = "AssistStructure";
+
+ /**
+ * Key name this data structure is stored in the Bundle generated by
+ * {@link Activity#onProvideAssistData}.
+ */
+ public static final String ASSIST_KEY = "android:assist_structure";
+
+ final ComponentName mActivityComponent;
+
+ final ArrayList<ViewNodeImpl> mRootViews = new ArrayList<>();
+
+ ViewAssistStructureImpl mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
+ Bundle mTmpExtras = new Bundle();
+
+ final static class ViewAssistStructureImpl extends ViewAssistStructure {
+ CharSequence mText;
+ int mTextSelectionStart = -1;
+ int mTextSelectionEnd = -1;
+ int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
+ int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
+ float mTextSize = 0;
+ int mTextStyle = 0;
+ CharSequence mHint;
+
+ @Override
+ public void setText(CharSequence text) {
+ mText = text;
+ mTextSelectionStart = mTextSelectionEnd = -1;
+ }
+
+ @Override
+ public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+ mText = text;
+ mTextSelectionStart = selectionStart;
+ mTextSelectionEnd = selectionEnd;
+ }
+
+ @Override
+ public void setTextPaint(TextPaint paint) {
+ mTextColor = paint.getColor();
+ mTextBackgroundColor = paint.bgColor;
+ mTextSize = paint.getTextSize();
+ mTextStyle = 0;
+ Typeface tf = paint.getTypeface();
+ if (tf != null) {
+ if (tf.isBold()) {
+ mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+ }
+ if (tf.isItalic()) {
+ mTextStyle |= ViewNode.TEXT_STYLE_ITALIC;
+ }
+ }
+ int pflags = paint.getFlags();
+ if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+ mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+ }
+ if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) {
+ mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE;
+ }
+ if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+ mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU;
+ }
+ }
+
+ @Override
+ public void setHint(CharSequence hint) {
+ mHint = hint;
+ }
+
+ @Override
+ public CharSequence getText() {
+ return mText;
+ }
+
+ @Override
+ public int getTextSelectionStart() {
+ return mTextSelectionStart;
+ }
+
+ @Override
+ public int getTextSelectionEnd() {
+ return mTextSelectionEnd;
+ }
+
+ @Override
+ public CharSequence getHint() {
+ return mHint;
+ }
+ }
+
+ final static class ViewNodeTextImpl {
+ final CharSequence mText;
+ final int mTextSelectionStart;
+ final int mTextSelectionEnd;
+ int mTextColor;
+ int mTextBackgroundColor;
+ float mTextSize;
+ int mTextStyle;
+ final String mHint;
+
+ ViewNodeTextImpl(ViewAssistStructureImpl data) {
+ mText = data.mText;
+ mTextSelectionStart = data.mTextSelectionStart;
+ mTextSelectionEnd = data.mTextSelectionEnd;
+ mTextColor = data.mTextColor;
+ mTextBackgroundColor = data.mTextBackgroundColor;
+ mTextSize = data.mTextSize;
+ mTextStyle = data.mTextStyle;
+ mHint = data.mHint != null ? data.mHint.toString() : null;
+ }
+
+ ViewNodeTextImpl(Parcel in) {
+ mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mTextSelectionStart = in.readInt();
+ mTextSelectionEnd = in.readInt();
+ mTextColor = in.readInt();
+ mTextBackgroundColor = in.readInt();
+ mTextSize = in.readFloat();
+ mTextStyle = in.readInt();
+ mHint = in.readString();
+ }
+
+ void writeToParcel(Parcel out) {
+ TextUtils.writeToParcel(mText, out, 0);
+ out.writeInt(mTextSelectionStart);
+ out.writeInt(mTextSelectionEnd);
+ out.writeInt(mTextColor);
+ out.writeInt(mTextBackgroundColor);
+ out.writeFloat(mTextSize);
+ out.writeInt(mTextStyle);
+ out.writeString(mHint);
+ }
+ }
+
+ final static class ViewNodeImpl {
+ final int mX;
+ final int mY;
+ final int mScrollX;
+ final int mScrollY;
+ final int mWidth;
+ final int mHeight;
+
+ static final int FLAGS_DISABLED = 0x00000001;
+ static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
+ static final int FLAGS_FOCUSABLE = 0x00000010;
+ static final int FLAGS_FOCUSED = 0x00000020;
+ static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
+ static final int FLAGS_SELECTED = 0x00000040;
+ static final int FLAGS_ACTIVATED = 0x40000000;
+ static final int FLAGS_CHECKABLE = 0x00000100;
+ static final int FLAGS_CHECKED = 0x00000200;
+ static final int FLAGS_CLICKABLE = 0x00004000;
+ static final int FLAGS_LONG_CLICKABLE = 0x00200000;
+
+ final int mFlags;
+
+ final String mClassName;
+ final String mContentDescription;
+
+ final ViewNodeTextImpl mText;
+ final Bundle mExtras;
+
+ final ViewNodeImpl[] mChildren;
+
+ ViewNodeImpl(AssistStructure assistStructure, View view, int left, int top,
+ CharSequence contentDescription) {
+ mX = left;
+ mY = top;
+ mScrollX = view.getScrollX();
+ mScrollY = view.getScrollY();
+ mWidth = view.getWidth();
+ mHeight = view.getHeight();
+ int flags = view.getVisibility();
+ if (!view.isEnabled()) {
+ flags |= FLAGS_DISABLED;
+ }
+ if (!view.isClickable()) {
+ flags |= FLAGS_CLICKABLE;
+ }
+ if (!view.isFocusable()) {
+ flags |= FLAGS_FOCUSABLE;
+ }
+ if (!view.isFocused()) {
+ flags |= FLAGS_FOCUSED;
+ }
+ if (!view.isAccessibilityFocused()) {
+ flags |= FLAGS_ACCESSIBILITY_FOCUSED;
+ }
+ if (!view.isSelected()) {
+ flags |= FLAGS_SELECTED;
+ }
+ if (!view.isActivated()) {
+ flags |= FLAGS_ACTIVATED;
+ }
+ if (!view.isLongClickable()) {
+ flags |= FLAGS_LONG_CLICKABLE;
+ }
+ if (view instanceof Checkable) {
+ flags |= FLAGS_CHECKABLE;
+ if (((Checkable)view).isChecked()) {
+ flags |= FLAGS_CHECKED;
+ }
+ }
+ mFlags = flags;
+ mClassName = view.getAccessibilityClassName().toString();
+ mContentDescription = contentDescription != null ? contentDescription.toString() : null;
+ final ViewAssistStructureImpl viewData = assistStructure.mTmpViewAssistStructureImpl;
+ final Bundle extras = assistStructure.mTmpExtras;
+ view.onProvideAssistStructure(viewData, extras);
+ if (viewData.mText != null || viewData.mHint != null) {
+ mText = new ViewNodeTextImpl(viewData);
+ assistStructure.mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
+ } else {
+ mText = null;
+ }
+ if (!extras.isEmpty()) {
+ mExtras = extras;
+ assistStructure.mTmpExtras = new Bundle();
+ } else {
+ mExtras = null;
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup)view;
+ final int NCHILDREN = vg.getChildCount();
+ if (NCHILDREN > 0) {
+ mChildren = new ViewNodeImpl[NCHILDREN];
+ for (int i=0; i<NCHILDREN; i++) {
+ mChildren[i] = new ViewNodeImpl(assistStructure, vg.getChildAt(i));
+ }
+ } else {
+ mChildren = null;
+ }
+ } else {
+ mChildren = null;
+ }
+ }
+
+ ViewNodeImpl(AssistStructure assistStructure, View view) {
+ this(assistStructure, view, view.getLeft(), view.getTop(), view.getContentDescription());
+ }
+
+ ViewNodeImpl(Parcel in, PooledStringReader preader) {
+ mX = in.readInt();
+ mY = in.readInt();
+ mScrollX = in.readInt();
+ mScrollY = in.readInt();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ mFlags = in.readInt();
+ mClassName = preader.readString();
+ mContentDescription = in.readString();
+ if (in.readInt() != 0) {
+ mText = new ViewNodeTextImpl(in);
+ } else {
+ mText = null;
+ }
+ mExtras = in.readBundle();
+ final int NCHILDREN = in.readInt();
+ if (NCHILDREN > 0) {
+ mChildren = new ViewNodeImpl[NCHILDREN];
+ for (int i=0; i<NCHILDREN; i++) {
+ mChildren[i] = new ViewNodeImpl(in, preader);
+ }
+ } else {
+ mChildren = null;
+ }
+ }
+
+ void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+ out.writeInt(mX);
+ out.writeInt(mY);
+ out.writeInt(mScrollX);
+ out.writeInt(mScrollY);
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ out.writeInt(mFlags);
+ pwriter.writeString(mClassName);
+ out.writeString(mContentDescription);
+ if (mText != null) {
+ out.writeInt(1);
+ mText.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeBundle(mExtras);
+ if (mChildren != null) {
+ final int NCHILDREN = mChildren.length;
+ out.writeInt(NCHILDREN);
+ for (int i=0; i<NCHILDREN; i++) {
+ mChildren[i].writeToParcel(out, pwriter);
+ }
+ } else {
+ out.writeInt(0);
+ }
+ }
+ }
+
+ /**
+ * Provides access to information about a single view in the assist data.
+ */
+ static public class ViewNode {
+ /**
+ * Magic value for text color that has not been defined, which is very unlikely
+ * to be confused with a real text color.
+ */
+ public static final int TEXT_COLOR_UNDEFINED = 1;
+
+ public static final int TEXT_STYLE_BOLD = 1<<0;
+ public static final int TEXT_STYLE_ITALIC = 1<<1;
+ public static final int TEXT_STYLE_UNDERLINE = 1<<2;
+ public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
+
+ ViewNodeImpl mImpl;
+
+ public ViewNode() {
+ }
+
+ public int getLeft() {
+ return mImpl.mX;
+ }
+
+ public int getTop() {
+ return mImpl.mY;
+ }
+
+ public int getScrollX() {
+ return mImpl.mScrollX;
+ }
+
+ public int getScrollY() {
+ return mImpl.mScrollY;
+ }
+
+ public int getWidth() {
+ return mImpl.mWidth;
+ }
+
+ public int getHeight() {
+ return mImpl.mHeight;
+ }
+
+ public int getVisibility() {
+ return mImpl.mFlags&ViewNodeImpl.FLAGS_VISIBILITY_MASK;
+ }
+
+ public boolean isEnabled() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_DISABLED) == 0;
+ }
+
+ public boolean isClickable() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_CLICKABLE) != 0;
+ }
+
+ public boolean isFocusable() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSABLE) != 0;
+ }
+
+ public boolean isFocused() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSED) != 0;
+ }
+
+ public boolean isAccessibilityFocused() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+ }
+
+ public boolean isCheckable() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKABLE) != 0;
+ }
+
+ public boolean isChecked() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKED) != 0;
+ }
+
+ public boolean isSelected() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_SELECTED) != 0;
+ }
+
+ public boolean isActivated() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACTIVATED) != 0;
+ }
+
+ public boolean isLongClickable() {
+ return (mImpl.mFlags&ViewNodeImpl.FLAGS_LONG_CLICKABLE) != 0;
+ }
+
+ public String getClassName() {
+ return mImpl.mClassName;
+ }
+
+ public String getContentDescription() {
+ return mImpl.mContentDescription;
+ }
+
+ public CharSequence getText() {
+ return mImpl.mText != null ? mImpl.mText.mText : null;
+ }
+
+ public int getTextSelectionStart() {
+ return mImpl.mText != null ? mImpl.mText.mTextSelectionStart : -1;
+ }
+
+ public int getTextSelectionEnd() {
+ return mImpl.mText != null ? mImpl.mText.mTextSelectionEnd : -1;
+ }
+
+ public int getTextColor() {
+ return mImpl.mText != null ? mImpl.mText.mTextColor : TEXT_COLOR_UNDEFINED;
+ }
+
+ public int getTextBackgroundColor() {
+ return mImpl.mText != null ? mImpl.mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+ }
+
+ public float getTextSize() {
+ return mImpl.mText != null ? mImpl.mText.mTextSize : 0;
+ }
+
+ public int getTextStyle() {
+ return mImpl.mText != null ? mImpl.mText.mTextStyle : 0;
+ }
+
+ public String getHint() {
+ return mImpl.mText != null ? mImpl.mText.mHint : null;
+ }
+
+ public Bundle getExtras() {
+ return mImpl.mExtras;
+ }
+
+ public int getChildCount() {
+ return mImpl.mChildren != null ? mImpl.mChildren.length : 0;
+ }
+
+ public void getChildAt(int index, ViewNode outNode) {
+ outNode.mImpl = mImpl.mChildren[index];
+ }
+ }
+
+ AssistStructure(Activity activity) {
+ mActivityComponent = activity.getComponentName();
+ ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
+ activity.getActivityToken());
+ for (int i=0; i<views.size(); i++) {
+ ViewRootImpl root = views.get(i);
+ View view = root.getView();
+ Rect rect = new Rect();
+ view.getBoundsOnScreen(rect);
+ CharSequence title = root.getTitle();
+ mRootViews.add(new ViewNodeImpl(this, view, rect.left, rect.top,
+ title != null ? title : view.getContentDescription()));
+ }
+ }
+
+ AssistStructure(Parcel in) {
+ PooledStringReader preader = new PooledStringReader(in);
+ mActivityComponent = ComponentName.readFromParcel(in);
+ final int N = in.readInt();
+ for (int i=0; i<N; i++) {
+ mRootViews.add(new ViewNodeImpl(in, preader));
+ }
+ //dump();
+ }
+
+ /** @hide */
+ public void dump() {
+ Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+ ViewNode node = new ViewNode();
+ final int N = getWindowCount();
+ for (int i=0; i<N; i++) {
+ Log.i(TAG, "Window #" + i + ":");
+ getWindowAt(i, node);
+ dump(" ", node);
+ }
+ }
+
+ void dump(String prefix, ViewNode node) {
+ Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+ + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
+ int scrollX = node.getScrollX();
+ int scrollY = node.getScrollY();
+ if (scrollX != 0 || scrollY != 0) {
+ Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
+ }
+ String contentDescription = node.getContentDescription();
+ if (contentDescription != null) {
+ Log.i(TAG, prefix + " Content description: " + contentDescription);
+ }
+ CharSequence text = node.getText();
+ if (text != null) {
+ Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
+ + node.getTextSelectionEnd() + "): " + text);
+ Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
+ + node.getTextStyle());
+ Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
+ + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+ }
+ String hint = node.getHint();
+ if (hint != null) {
+ Log.i(TAG, prefix + " Hint: " + hint);
+ }
+ Bundle extras = node.getExtras();
+ if (extras != null) {
+ Log.i(TAG, prefix + " Extras: " + extras);
+ }
+ final int NCHILDREN = node.getChildCount();
+ if (NCHILDREN > 0) {
+ Log.i(TAG, prefix + " Children:");
+ String cprefix = prefix + " ";
+ ViewNode cnode = new ViewNode();
+ for (int i=0; i<NCHILDREN; i++) {
+ node.getChildAt(i, cnode);
+ dump(cprefix, cnode);
+ }
+ }
+ }
+
+ /**
+ * Retrieve the framework-generated AssistStructure that is stored within
+ * the Bundle filled in by {@link Activity#onProvideAssistData}.
+ */
+ public static AssistStructure getAssistStructure(Bundle assistBundle) {
+ return assistBundle.getParcelable(ASSIST_KEY);
+ }
+
+ public ComponentName getActivityComponent() {
+ return mActivityComponent;
+ }
+
+ /**
+ * Return the number of window contents that have been collected in this assist data.
+ */
+ public int getWindowCount() {
+ return mRootViews.size();
+ }
+
+ /**
+ * Return the root view for one of the windows in the assist data.
+ * @param index Which window to retrieve, may be 0 to {@link #getWindowCount()}-1.
+ * @param outNode Node in which to place the window's root view.
+ */
+ public void getWindowAt(int index, ViewNode outNode) {
+ outNode.mImpl = mRootViews.get(index);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ int start = out.dataPosition();
+ PooledStringWriter pwriter = new PooledStringWriter(out);
+ ComponentName.writeToParcel(mActivityComponent, out);
+ final int N = mRootViews.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ mRootViews.get(i).writeToParcel(out, pwriter);
+ }
+ pwriter.finish();
+ Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
+ }
+
+ public static final Parcelable.Creator<AssistStructure> CREATOR
+ = new Parcelable.Creator<AssistStructure>() {
+ public AssistStructure createFromParcel(Parcel in) {
+ return new AssistStructure(in);
+ }
+
+ public AssistStructure[] newArray(int size) {
+ return new AssistStructure[size];
+ }
+ };
+}