/* * 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.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.PooledStringReader; import android.os.PooledStringWriter; import android.os.RemoteException; import android.os.SystemClock; import android.text.TextPaint; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewAssistStructure; import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowManagerGlobal; 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"; boolean mHaveData; ComponentName mActivityComponent; final ArrayList mWindowNodes = new ArrayList<>(); final ArrayList mPendingAsyncChildren = new ArrayList<>(); SendChannel mSendChannel; IBinder mReceiveChannel; Rect mTmpRect = new Rect(); static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1; static final String DESCRIPTOR = "android.app.AssistStructure"; final class SendChannel extends Binder { @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == TRANSACTION_XFER) { data.enforceInterface(DESCRIPTOR); writeContentToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; } else { return super.onTransact(code, data, reply, flags); } } } final static class ViewNodeText { CharSequence mText; int mTextSelectionStart; int mTextSelectionEnd; int mTextColor; int mTextBackgroundColor; float mTextSize; int mTextStyle; String mHint; ViewNodeText() { } ViewNodeText(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); } } /** * Describes a window in the assist data. */ static public class WindowNode { final int mX; final int mY; final int mWidth; final int mHeight; final CharSequence mTitle; final ViewNode mRoot; WindowNode(AssistStructure assist, ViewRootImpl root) { View view = root.getView(); Rect rect = new Rect(); view.getBoundsOnScreen(rect); mX = rect.left - view.getLeft(); mY = rect.top - view.getTop(); mWidth = rect.width(); mHeight = rect.height(); mTitle = root.getTitle(); mRoot = new ViewNode(); ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false); if ((root.getWindowFlags()&WindowManager.LayoutParams.FLAG_SECURE) != 0) { // This is a secure window, so it doesn't want a screenshot, and that // means we should also not copy out its view hierarchy. view.onProvideStructure(builder); builder.setAssistBlocked(true); return; } view.dispatchProvideStructure(builder); } WindowNode(Parcel in, PooledStringReader preader) { mX = in.readInt(); mY = in.readInt(); mWidth = in.readInt(); mHeight = in.readInt(); mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mRoot = new ViewNode(in, preader); } void writeToParcel(Parcel out, PooledStringWriter pwriter) { out.writeInt(mX); out.writeInt(mY); out.writeInt(mWidth); out.writeInt(mHeight); TextUtils.writeToParcel(mTitle, out, 0); mRoot.writeToParcel(out, pwriter); } public int getLeft() { return mX; } public int getTop() { return mY; } public int getWidth() { return mWidth; } public int getHeight() { return mHeight; } public CharSequence getTitle() { return mTitle; } public ViewNode getRootViewNode() { return mRoot; } } /** * Describes 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; int mId; String mIdPackage; String mIdType; String mIdEntry; int mX; int mY; int mScrollX; int mScrollY; int mWidth; 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_ASSIST_BLOCKED = 0x00000080; 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; static final int FLAGS_STYLUS_BUTTON_PRESSABLE = 0x00400000; int mFlags; String mClassName; CharSequence mContentDescription; ViewNodeText mText; Bundle mExtras; ViewNode[] mChildren; ViewNode() { } ViewNode(Parcel in, PooledStringReader preader) { mId = in.readInt(); if (mId != 0) { mIdEntry = preader.readString(); if (mIdEntry != null) { mIdType = preader.readString(); mIdPackage = preader.readString(); } else { mIdPackage = mIdType = null; } } else { mIdPackage = mIdType = mIdEntry = null; } 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 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readInt() != 0) { mText = new ViewNodeText(in); } else { mText = null; } mExtras = in.readBundle(); final int NCHILDREN = in.readInt(); if (NCHILDREN > 0) { mChildren = new ViewNode[NCHILDREN]; for (int i=0; i views = WindowManagerGlobal.getInstance().getRootViews( activity.getActivityToken()); for (int i=0; i 0) { Log.i(TAG, prefix + " Children:"); String cprefix = prefix + " "; for (int i=0; i 0 && (now=SystemClock.uptimeMillis()) < endTime) { try { wait(endTime-now); } catch (InterruptedException e) { } } if (mPendingAsyncChildren.size() > 0) { // We waited too long, assume none of the assist structure is valid. skipStructure = true; } } int start = out.dataPosition(); PooledStringWriter pwriter = new PooledStringWriter(out); ComponentName.writeToParcel(mActivityComponent, out); final int N = skipStructure ? 0 : mWindowNodes.size(); out.writeInt(N); for (int i=0; i CREATOR = new Parcelable.Creator() { public AssistStructure createFromParcel(Parcel in) { return new AssistStructure(in); } public AssistStructure[] newArray(int size) { return new AssistStructure[size]; } }; }