
android.app.assist.AssistStructure Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of android-all Show documentation
Show all versions of android-all Show documentation
A library jar that provides APIs for Applications written for the Google Android Platform.
package android.app.assist;
import android.app.Activity;
import android.content.ComponentName;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.BadParcelableException;
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.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewStructure;
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 android.app.Activity#onProvideAssistData}.
*/
public class AssistStructure implements Parcelable {
static final String TAG = "AssistStructure";
static final boolean DEBUG_PARCEL = false;
static final boolean DEBUG_PARCEL_CHILDREN = false;
static final boolean DEBUG_PARCEL_TREE = false;
static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
static final int VALIDATE_VIEW_TOKEN = 0x22222222;
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 static class SendChannel extends Binder {
volatile AssistStructure mAssistStructure;
SendChannel(AssistStructure as) {
mAssistStructure = as;
}
@Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
if (code == TRANSACTION_XFER) {
AssistStructure as = mAssistStructure;
if (as == null) {
return true;
}
data.enforceInterface(DESCRIPTOR);
IBinder token = data.readStrongBinder();
if (DEBUG_PARCEL) Log.d(TAG, "Request for data on " + as
+ " using token " + token);
if (token != null) {
if (DEBUG_PARCEL) Log.d(TAG, "Resuming partial write of " + token);
if (token instanceof ParcelTransferWriter) {
ParcelTransferWriter xfer = (ParcelTransferWriter)token;
xfer.writeToParcel(as, reply);
return true;
}
Log.w(TAG, "Caller supplied bad token type: " + token);
// Don't write anything; this is the end of the data.
return true;
}
//long start = SystemClock.uptimeMillis();
ParcelTransferWriter xfer = new ParcelTransferWriter(as, reply);
xfer.writeToParcel(as, reply);
//Log.i(TAG, "Time to parcel: " + (SystemClock.uptimeMillis()-start) + "ms");
return true;
} else {
return super.onTransact(code, data, reply, flags);
}
}
}
final static class ViewStackEntry {
ViewNode node;
int curChild;
int numChildren;
}
final static class ParcelTransferWriter extends Binder {
final boolean mWriteStructure;
int mCurWindow;
int mNumWindows;
final ArrayList mViewStack = new ArrayList<>();
ViewStackEntry mCurViewStackEntry;
int mCurViewStackPos;
int mNumWrittenWindows;
int mNumWrittenViews;
final float[] mTmpMatrix = new float[9];
ParcelTransferWriter(AssistStructure as, Parcel out) {
mWriteStructure = as.waitForReady();
ComponentName.writeToParcel(as.mActivityComponent, out);
mNumWindows = as.mWindowNodes.size();
if (mWriteStructure && mNumWindows > 0) {
out.writeInt(mNumWindows);
} else {
out.writeInt(0);
}
}
void writeToParcel(AssistStructure as, Parcel out) {
int start = out.dataPosition();
mNumWrittenWindows = 0;
mNumWrittenViews = 0;
boolean more = writeToParcelInner(as, out);
Log.i(TAG, "Flattened " + (more ? "partial" : "final") + " assist data: "
+ (out.dataPosition() - start)
+ " bytes, containing " + mNumWrittenWindows + " windows, "
+ mNumWrittenViews + " views");
}
boolean writeToParcelInner(AssistStructure as, Parcel out) {
if (mNumWindows == 0) {
return false;
}
if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringWriter @ " + out.dataPosition());
PooledStringWriter pwriter = new PooledStringWriter(out);
while (writeNextEntryToParcel(as, out, pwriter)) {
// If the parcel is above the IPC limit, then we are getting too
// large for a single IPC so stop here and let the caller come back when it
// is ready for more.
if (out.dataSize() > IBinder.MAX_IPC_SIZE) {
if (DEBUG_PARCEL) Log.d(TAG, "Assist data size is " + out.dataSize()
+ " @ pos " + out.dataPosition() + "; returning partial result");
out.writeInt(0);
out.writeStrongBinder(this);
if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
+ out.dataPosition() + ", size " + pwriter.getStringCount());
pwriter.finish();
return true;
}
}
if (DEBUG_PARCEL) Log.d(TAG, "Finishing PooledStringWriter @ "
+ out.dataPosition() + ", size " + pwriter.getStringCount());
pwriter.finish();
mViewStack.clear();
return false;
}
void pushViewStackEntry(ViewNode node, int pos) {
ViewStackEntry entry;
if (pos >= mViewStack.size()) {
entry = new ViewStackEntry();
mViewStack.add(entry);
if (DEBUG_PARCEL_TREE) Log.d(TAG, "New stack entry at " + pos + ": " + entry);
} else {
entry = mViewStack.get(pos);
if (DEBUG_PARCEL_TREE) Log.d(TAG, "Existing stack entry at " + pos + ": " + entry);
}
entry.node = node;
entry.numChildren = node.getChildCount();
entry.curChild = 0;
mCurViewStackEntry = entry;
}
void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
+ ", windows=" + mNumWrittenWindows
+ ", views=" + mNumWrittenViews
+ ", level=" + (mCurViewStackPos+levelAdj));
out.writeInt(VALIDATE_VIEW_TOKEN);
int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
mNumWrittenViews++;
// If the child has children, push it on the stack to write them next.
if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
"Preparing to write " + child.mChildren.length
+ " children: @ #" + mNumWrittenViews
+ ", level " + (mCurViewStackPos+levelAdj));
out.writeInt(child.mChildren.length);
int pos = ++mCurViewStackPos;
pushViewStackEntry(child, pos);
}
}
boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
// Write next view node if appropriate.
if (mCurViewStackEntry != null) {
if (mCurViewStackEntry.curChild < mCurViewStackEntry.numChildren) {
// Write the next child in the current view.
if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing child #"
+ mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
mCurViewStackEntry.curChild++;
writeView(child, out, pwriter, 1);
return true;
}
// We are done writing children of the current view; pop off the stack.
do {
int pos = --mCurViewStackPos;
if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with " + mCurViewStackEntry.node
+ "; popping up to " + pos);
if (pos < 0) {
// Reached the last view; step to next window.
if (DEBUG_PARCEL_TREE) Log.d(TAG, "Done with view hierarchy!");
mCurViewStackEntry = null;
break;
}
mCurViewStackEntry = mViewStack.get(pos);
} while (mCurViewStackEntry.curChild >= mCurViewStackEntry.numChildren);
return true;
}
// Write the next window if appropriate.
int pos = mCurWindow;
if (pos < mNumWindows) {
WindowNode win = as.mWindowNodes.get(pos);
mCurWindow++;
if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
+ ", windows=" + mNumWrittenWindows
+ ", views=" + mNumWrittenViews);
out.writeInt(VALIDATE_WINDOW_TOKEN);
win.writeSelfToParcel(out, pwriter, mTmpMatrix);
mNumWrittenWindows++;
ViewNode root = win.mRoot;
mCurViewStackPos = 0;
if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
writeView(root, out, pwriter, 0);
return true;
}
return false;
}
}
final class ParcelTransferReader {
final float[] mTmpMatrix = new float[9];
PooledStringReader mStringReader;
int mNumReadWindows;
int mNumReadViews;
private final IBinder mChannel;
private IBinder mTransferToken;
private Parcel mCurParcel;
ParcelTransferReader(IBinder channel) {
mChannel = channel;
}
void go() {
fetchData();
mActivityComponent = ComponentName.readFromParcel(mCurParcel);
final int N = mCurParcel.readInt();
if (N > 0) {
if (DEBUG_PARCEL) Log.d(TAG, "Creating PooledStringReader @ "
+ mCurParcel.dataPosition());
mStringReader = new PooledStringReader(mCurParcel);
if (DEBUG_PARCEL) Log.d(TAG, "PooledStringReader size = "
+ mStringReader.getStringCount());
for (int i=0; i>16)&0x7fff;
val = in.readInt();
mWidth = val&0x7fff;
mHeight = (val>>16)&0x7fff;
}
if ((flags&FLAGS_HAS_SCROLL) != 0) {
mScrollX = in.readInt();
mScrollY = in.readInt();
}
if ((flags&FLAGS_HAS_MATRIX) != 0) {
mMatrix = new Matrix();
in.readFloatArray(reader.mTmpMatrix);
mMatrix.setValues(reader.mTmpMatrix);
}
if ((flags&FLAGS_HAS_ELEVATION) != 0) {
mElevation = in.readFloat();
}
if ((flags&FLAGS_HAS_ALPHA) != 0) {
mAlpha = in.readFloat();
}
if ((flags&FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
}
if ((flags&FLAGS_HAS_TEXT) != 0) {
mText = new ViewNodeText(in, (flags&FLAGS_HAS_COMPLEX_TEXT) == 0);
}
if ((flags&FLAGS_HAS_EXTRAS) != 0) {
mExtras = in.readBundle();
}
if ((flags&FLAGS_HAS_CHILDREN) != 0) {
final int NCHILDREN = in.readInt();
if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
"Preparing to read " + NCHILDREN
+ " children: @ #" + reader.mNumReadViews
+ ", level " + nestingLevel);
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.
Log.w(TAG, "Skipping assist structure, waiting too long for async children (have "
+ mPendingAsyncChildren.size() + " remaining");
skipStructure = true;
}
}
return !skipStructure;
}
/** @hide */
public void clearSendChannel() {
if (mSendChannel != null) {
mSendChannel.mAssistStructure = null;
}
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
if (mHaveData) {
// This object holds its data. We want to write a send channel that the
// other side can use to retrieve that data.
if (mSendChannel == null) {
mSendChannel = new SendChannel(this);
}
out.writeStrongBinder(mSendChannel);
} else {
// This object doesn't hold its data, so just propagate along its receive channel.
out.writeStrongBinder(mReceiveChannel);
}
}
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public AssistStructure createFromParcel(Parcel in) {
return new AssistStructure(in);
}
public AssistStructure[] newArray(int size) {
return new AssistStructure[size];
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy