info
.
*
* @param info The other info.
*/
public AccessibilityWindowInfo(@NonNull AccessibilityWindowInfo info) {
init(info);
}
/**
* Gets the title of the window.
*
* @return The title of the window, or {@code null} if none is available.
*/
@Nullable
public CharSequence getTitle() {
return mTitle;
}
/**
* Sets the title of the window.
*
* @param title The title.
*
* @hide
*/
public void setTitle(CharSequence title) {
mTitle = title;
}
/**
* Gets the type of the window.
*
* @return The type.
*
* @see #TYPE_APPLICATION
* @see #TYPE_INPUT_METHOD
* @see #TYPE_SYSTEM
* @see #TYPE_ACCESSIBILITY_OVERLAY
*/
public int getType() {
return mType;
}
/**
* Sets the type of the window.
*
* @param type The type
*
* @hide
*/
public void setType(int type) {
mType = type;
}
/**
* Gets the layer which determines the Z-order of the window. Windows
* with greater layer appear on top of windows with lesser layer.
*
* @return The window layer.
*/
public int getLayer() {
return mLayer;
}
/**
* Sets the layer which determines the Z-order of the window. Windows
* with greater layer appear on top of windows with lesser layer.
*
* @param layer The window layer.
*
* @hide
*/
public void setLayer(int layer) {
mLayer = layer;
}
/**
* Gets the root node in the window's hierarchy.
*
* @return The root node.
*/
public AccessibilityNodeInfo getRoot() {
return getRoot(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID);
}
/**
* Gets the root node in the window's hierarchy.
*
* @param prefetchingStrategy the prefetching strategy.
* @return The root node.
*
* @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
*/
@Nullable
public AccessibilityNodeInfo getRoot(
@AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) {
if (mConnectionId == UNDEFINED_WINDOW_ID) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mId, AccessibilityNodeInfo.ROOT_NODE_ID,
true, prefetchingStrategy, null);
}
/**
* Sets the anchor node's ID.
*
* @param anchorId The anchor's accessibility id in its window.
*
* @hide
*/
public void setAnchorId(long anchorId) {
mAnchorId = anchorId;
}
/**
* Gets the node that anchors this window to another.
*
* @return The anchor node, or {@code null} if none exists.
*/
public AccessibilityNodeInfo getAnchor() {
if ((mConnectionId == UNDEFINED_WINDOW_ID)
|| (mAnchorId == AccessibilityNodeInfo.UNDEFINED_NODE_ID)
|| (mParentId == UNDEFINED_WINDOW_ID)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
mParentId, mAnchorId, true, 0, null);
}
/** @hide */
public void setPictureInPicture(boolean pictureInPicture) {
setBooleanProperty(BOOLEAN_PROPERTY_PICTURE_IN_PICTURE, pictureInPicture);
}
/**
* Check if the window is in picture-in-picture mode.
*
* @return {@code true} if the window is in picture-in-picture mode, {@code false} otherwise.
*/
public boolean isInPictureInPictureMode() {
return getBooleanProperty(BOOLEAN_PROPERTY_PICTURE_IN_PICTURE);
}
/**
* Gets the parent window.
*
* @return The parent window, or {@code null} if none exists.
*/
public AccessibilityWindowInfo getParent() {
if (mConnectionId == UNDEFINED_WINDOW_ID || mParentId == UNDEFINED_WINDOW_ID) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
return client.getWindow(mConnectionId, mParentId);
}
/**
* Sets the parent window id.
*
* @param parentId The parent id.
*
* @hide
*/
public void setParentId(int parentId) {
mParentId = parentId;
}
/**
* Gets the unique window id.
*
* @return windowId The window id.
*/
public int getId() {
return mId;
}
/**
* Sets the unique window id.
*
* @param id The window id.
*
* @hide
*/
public void setId(int id) {
mId = id;
}
/**
* Gets the task ID.
*
* @return The task ID.
*
* @hide
*/
public int getTaskId() {
return mTaskId;
}
/**
* Sets the task ID.
*
* @param taskId The task ID.
*
* @hide
*/
public void setTaskId(int taskId) {
mTaskId = taskId;
}
/**
* Sets the unique id of the IAccessibilityServiceConnection over which
* this instance can send requests to the system.
*
* @param connectionId The connection id.
*
* @hide
*/
public void setConnectionId(int connectionId) {
mConnectionId = connectionId;
}
/**
* Gets the touchable region of this window in the screen.
*
* @param outRegion The out window region.
*/
public void getRegionInScreen(@NonNull Region outRegion) {
outRegion.set(mRegionInScreen);
}
/**
* Sets the touchable region of this window in the screen.
*
* @param region The window region.
*
* @hide
*/
public void setRegionInScreen(Region region) {
mRegionInScreen.set(region);
}
/**
* Gets the bounds of this window in the screen. This is equivalent to get the bounds of the
* Region from {@link #getRegionInScreen(Region)}.
*
* @param outBounds The out window bounds.
*/
public void getBoundsInScreen(Rect outBounds) {
outBounds.set(mRegionInScreen.getBounds());
}
/**
* Gets if this window is active. An active window is the one
* the user is currently touching or the window has input focus
* and the user is not touching any window.
* * This is defined as the window that most recently fired one * of the following events: * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}, * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}, * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}. * In other words, the last window shown that also has input focus. *
* * @return Whether this is the active window. */ public boolean isActive() { return getBooleanProperty(BOOLEAN_PROPERTY_ACTIVE); } /** * Sets if this window is active, which is this is the window * the user is currently touching or the window has input focus * and the user is not touching any window. * * @param active Whether this is the active window. * * @hide */ public void setActive(boolean active) { setBooleanProperty(BOOLEAN_PROPERTY_ACTIVE, active); } /** * Gets if this window has input focus. * * @return Whether has input focus. */ public boolean isFocused() { return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED); } /** * Sets if this window has input focus. * * @param focused Whether has input focus. * * @hide */ public void setFocused(boolean focused) { setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused); } /** * Gets if this window has accessibility focus. * * @return Whether has accessibility focus. */ public boolean isAccessibilityFocused() { return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED); } /** * Sets if this window has accessibility focus. * * @param focused Whether has accessibility focus. * * @hide */ public void setAccessibilityFocused(boolean focused) { setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused); } /** * Gets the number of child windows. * * @return The child count. */ public int getChildCount() { return (mChildIds != null) ? mChildIds.size() : 0; } /** * Gets the child window at a given index. * * @param index The index. * @return The child. */ public AccessibilityWindowInfo getChild(int index) { if (mChildIds == null) { throw new IndexOutOfBoundsException(); } if (mConnectionId == UNDEFINED_WINDOW_ID) { return null; } final int childId = (int) mChildIds.get(index); AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); return client.getWindow(mConnectionId, childId); } /** * Adds a child window. * * @param childId The child window id. * * @hide */ public void addChild(int childId) { if (mChildIds == null) { mChildIds = new LongArray(); } mChildIds.add(childId); } /** * Sets the display Id. * * @param displayId The display id. * * @hide */ public void setDisplayId(int displayId) { mDisplayId = displayId; } /** * Returns the ID of the display this window is on, for use with * {@link android.hardware.display.DisplayManager#getDisplay(int)}. * * @return The logical display id. */ public int getDisplayId() { return mDisplayId; } /** * Sets the timestamp of the transition. * * @param transitionTime The timestamp from {@link SystemClock#uptimeMillis()} at which the * transition happens. * * @hide */ @UptimeMillisLong public void setTransitionTimeMillis(long transitionTime) { mTransitionTime = transitionTime; } /** * Return the {@link SystemClock#uptimeMillis()} at which the last transition happens. * A transition happens when {@link #getBoundsInScreen(Rect)} is changed. * * @return The transition timestamp. */ @UptimeMillisLong public long getTransitionTimeMillis() { return mTransitionTime; } /** * Sets the locales of the window. Locales are populated by the view root by default. * * @param locales The {@link android.os.LocaleList}. * * @hide */ public void setLocales(@NonNull LocaleList locales) { mLocales = locales; } /** * Return the {@link android.os.LocaleList} of the window. * * @return the locales of the window. */ public @NonNull LocaleList getLocales() { return mLocales; } /** * Returns a cached instance if such is available or a new one is * created. * *In most situations object pooling is not beneficial. Create a new instance using the
* constructor {@link #AccessibilityWindowInfo()} instead.
*
* @return An instance.
*/
public static AccessibilityWindowInfo obtain() {
AccessibilityWindowInfo info = sPool.acquire();
if (info == null) {
info = new AccessibilityWindowInfo();
}
if (sNumInstancesInUse != null) {
sNumInstancesInUse.incrementAndGet();
}
return info;
}
/**
* Returns a cached instance if such is available or a new one is
* created. The returned instance is initialized from the given
* info
.
*
*
In most situations object pooling is not beneficial. Create a new instance using the * constructor {@link #AccessibilityWindowInfo(AccessibilityWindowInfo)} instead. * * @param info The other info. * @return An instance. */ public static AccessibilityWindowInfo obtain(AccessibilityWindowInfo info) { AccessibilityWindowInfo infoClone = obtain(); infoClone.init(info); return infoClone; } /** * Specify a counter that will be incremented on obtain() and decremented on recycle() * * @hide */ @TestApi public static void setNumInstancesInUseCounter(AtomicInteger counter) { if (sNumInstancesInUse != null) { sNumInstancesInUse = counter; } } /** * Return an instance back to be reused. *
* Note: You must not touch the object after calling this function. *
* *In most situations object pooling is not beneficial, and recycling is not necessary. * * @throws IllegalStateException If the info is already recycled. */ public void recycle() { clear(); sPool.release(this); if (sNumInstancesInUse != null) { sNumInstancesInUse.decrementAndGet(); } } /** * Refreshes this window with the latest state of the window it represents. *
* Note: If this method returns false this info is obsolete * since it represents a window that is no longer exist. *
* * @hide */ public boolean refresh() { if (mConnectionId == UNDEFINED_CONNECTION_ID || mId == UNDEFINED_WINDOW_ID) { return false; } final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); final AccessibilityWindowInfo refreshedInfo = client.getWindow(mConnectionId, mId, /* bypassCache */true); if (refreshedInfo == null) { return false; } init(refreshedInfo); refreshedInfo.recycle(); return true; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mDisplayId); parcel.writeInt(mType); parcel.writeInt(mLayer); parcel.writeInt(mBooleanProperties); parcel.writeInt(mId); parcel.writeInt(mParentId); parcel.writeInt(mTaskId); mRegionInScreen.writeToParcel(parcel, flags); parcel.writeCharSequence(mTitle); parcel.writeLong(mAnchorId); parcel.writeLong(mTransitionTime); final LongArray childIds = mChildIds; if (childIds == null) { parcel.writeInt(0); } else { final int childCount = childIds.size(); parcel.writeInt(childCount); for (int i = 0; i < childCount; i++) { parcel.writeInt((int) childIds.get(i)); } } parcel.writeInt(mConnectionId); parcel.writeParcelable(mLocales, flags); } /** * Initializes this instance from another one. * * @param other The other instance. */ private void init(AccessibilityWindowInfo other) { mDisplayId = other.mDisplayId; mType = other.mType; mLayer = other.mLayer; mBooleanProperties = other.mBooleanProperties; mId = other.mId; mParentId = other.mParentId; mTaskId = other.mTaskId; mRegionInScreen.set(other.mRegionInScreen); mTitle = other.mTitle; mAnchorId = other.mAnchorId; mTransitionTime = other.mTransitionTime; if (mChildIds != null) mChildIds.clear(); if (other.mChildIds != null && other.mChildIds.size() > 0) { if (mChildIds == null) { mChildIds = other.mChildIds.clone(); } else { mChildIds.addAll(other.mChildIds); } } mConnectionId = other.mConnectionId; mLocales = other.mLocales; } private void initFromParcel(Parcel parcel) { mDisplayId = parcel.readInt(); mType = parcel.readInt(); mLayer = parcel.readInt(); mBooleanProperties = parcel.readInt(); mId = parcel.readInt(); mParentId = parcel.readInt(); mTaskId = parcel.readInt(); mRegionInScreen = Region.CREATOR.createFromParcel(parcel); mTitle = parcel.readCharSequence(); mAnchorId = parcel.readLong(); mTransitionTime = parcel.readLong(); final int childCount = parcel.readInt(); if (childCount > 0) { if (mChildIds == null) { mChildIds = new LongArray(childCount); } for (int i = 0; i < childCount; i++) { final int childId = parcel.readInt(); mChildIds.add(childId); } } mConnectionId = parcel.readInt(); mLocales = parcel.readParcelable(null, LocaleList.class); } @Override public int hashCode() { return mId; } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AccessibilityWindowInfo other = (AccessibilityWindowInfo) obj; return (mId == other.mId); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("AccessibilityWindowInfo["); builder.append("title=").append(mTitle); builder.append(", displayId=").append(mDisplayId); builder.append(", id=").append(mId); builder.append(", taskId=").append(mTaskId); builder.append(", type=").append(typeToString(mType)); builder.append(", layer=").append(mLayer); builder.append(", region=").append(mRegionInScreen); builder.append(", bounds=").append(mRegionInScreen.getBounds()); builder.append(", focused=").append(isFocused()); builder.append(", active=").append(isActive()); builder.append(", pictureInPicture=").append(isInPictureInPictureMode()); builder.append(", transitionTime=").append(mTransitionTime); if (DEBUG) { builder.append(", parent=").append(mParentId); builder.append(", children=["); if (mChildIds != null) { final int childCount = mChildIds.size(); for (int i = 0; i < childCount; i++) { builder.append(mChildIds.get(i)); if (i < childCount - 1) { builder.append(','); } } } else { builder.append("null"); } builder.append(']'); } else { builder.append(", hasParent=").append(mParentId != UNDEFINED_WINDOW_ID); builder.append(", isAnchored=") .append(mAnchorId != AccessibilityNodeInfo.UNDEFINED_NODE_ID); builder.append(", hasChildren=").append(mChildIds != null && mChildIds.size() > 0); } builder.append(']'); return builder.toString(); } /** * Clears the internal state. */ private void clear() { mDisplayId = Display.INVALID_DISPLAY; mType = UNDEFINED_WINDOW_ID; mLayer = UNDEFINED_WINDOW_ID; mBooleanProperties = 0; mId = UNDEFINED_WINDOW_ID; mParentId = UNDEFINED_WINDOW_ID; mTaskId = ActivityTaskManager.INVALID_TASK_ID; mRegionInScreen.setEmpty(); mChildIds = null; mConnectionId = UNDEFINED_WINDOW_ID; mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID; mTitle = null; mTransitionTime = 0; mLocales = LocaleList.getEmptyLocaleList(); } /** * Gets the value of a boolean property. * * @param property The property. * @return The value. */ private boolean getBooleanProperty(int property) { return (mBooleanProperties & property) != 0; } /** * Sets a boolean property. * * @param property The property. * @param value The value. * * @throws IllegalStateException If called from an AccessibilityService. */ private void setBooleanProperty(int property, boolean value) { if (value) { mBooleanProperties |= property; } else { mBooleanProperties &= ~property; } } /** * @hide */ public static String typeToString(int type) { if (Flags.addTypeWindowControl() && type == TYPE_WINDOW_CONTROL) { return "TYPE_WINDOW_CONTROL"; } switch (type) { case TYPE_APPLICATION: { return "TYPE_APPLICATION"; } case TYPE_INPUT_METHOD: { return "TYPE_INPUT_METHOD"; } case TYPE_SYSTEM: { return "TYPE_SYSTEM"; } case TYPE_ACCESSIBILITY_OVERLAY: { return "TYPE_ACCESSIBILITY_OVERLAY"; } case TYPE_SPLIT_SCREEN_DIVIDER: { return "TYPE_SPLIT_SCREEN_DIVIDER"; } case TYPE_MAGNIFICATION_OVERLAY: { return "TYPE_MAGNIFICATION_OVERLAY"; } default: return "