Commit 8e3feb15 authored by Svetoslav's avatar Svetoslav Committed by Svetoslav Ganov

Added accessibility APIs for introspecting interactive windows.

1. The old introspection model was allowing querying only the active window
   which is the one the user is touching or the focused one if no window is
   touched. This was limiting as auto completion drop downs were not inspectable,
   there was not way to know when the IME toggles, non-focusable windows were
   not inspectable if the user taps them as until a screen-reader starts
   introspecting the users finger is up, accessibility focus was limited to
   only one window and the user couldn't use gestures to visit the whole UI,
   and other things I can't remember right now.

   The new APIs allow getting all interactive windows, i.e. ones that a
   sighted user can interact with. This prevents an accessibility service
   from interacting with content a sighter user cannot. The list of windows
   can be obtained from an accessibility service or the host window from an
   accessibility node info. Introspecting windows obey the same rules for
   introspecting node, i.e. the service has to declare this capability
   in its manifest.

   When some windows change accessibility services receive a new type
   of event. Initially the types of windows is very limited. We provide
   the bounds in screen, layer, and some other properties which are
   enough for a client to determined the spacial and hierarchical
   relationship of the windows.

2. Update the documentation in AccessibilityService for newer event types.

3. LongArray was not removing elements properly.

4. Composite accessibility node ids were not properly constructed as they
   are composed of two ints, each taking 32 bits. However, the values for
   undefined were -1 so composing a 64 long from -1, -1 prevents from getting
   back these values when unpacking.

5. Some apps were generating inconsistent AccessibilityNodeInfo tree. Added
   a check that enforces such trees to be well formed on dev builds.

6. Removed an necessary code for piping the touch exploration state to
   the policy as it should just use the AccessibilityManager from context.

7. When view's visibility changed it was not firing an event to notify
   clients it disappeared/appeared. Also ViewGroup was sending accessibility
   events for changes if the view is included for accessibility but this is
   wrong as there may be a service that want all nodes, hence events from them.
   The accessibility manager service takes care of delivering events from
   not important for accessibility nodes only to services that want such.

8. Several places were asking for prefetching of sibling but not predecessor
   nodes which resulted in prefetching of unconnected subtrees.

9. The local AccessibilityManager implementation was relying on the backing
   service being ready when it is created but it can be fetched from a context
   before that. If that happens the local manager was in a broken state forever.
   Now it is more robust and starts working properly once the backing service
   is up. Several places were lacking locking.

bug:13331285

Change-Id: Ie51166d4875d5f3def8d29d77973da4b9251f5c8
parent 17cb5813
......@@ -196,7 +196,6 @@ LOCAL_SRC_FILES += \
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
core/java/android/view/IApplicationToken.aidl \
core/java/android/view/IAssetAtlas.aidl \
core/java/android/view/IMagnificationCallbacks.aidl \
core/java/android/view/IInputFilter.aidl \
core/java/android/view/IInputFilterHost.aidl \
core/java/android/view/IOnKeyguardExitResult.aidl \
......@@ -399,6 +398,7 @@ aidl_files := \
frameworks/base/core/java/android/view/accessibility/AccessibilityEvent.aidl \
frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.aidl \
frameworks/base/core/java/android/view/accessibility/AccessibilityRecord.aidl \
frameworks/base/core/java/android/view/accessibility/AccessibilityWindowInfo.aidl \
frameworks/base/core/java/android/view/KeyEvent.aidl \
frameworks/base/core/java/android/view/MotionEvent.aidl \
frameworks/base/core/java/android/view/Surface.aidl \
......
......@@ -187,6 +187,8 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_in
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrintClient.*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/IMedia*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/view/IMagnificationCallbacks*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
......@@ -2328,6 +2328,7 @@ package android.accessibilityservice {
ctor public AccessibilityService();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
method protected boolean onGesture(int);
......@@ -2393,6 +2394,7 @@ package android.accessibilityservice {
field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
field public int eventTypes;
field public int feedbackType;
field public int flags;
......@@ -4600,6 +4602,7 @@ package android.app {
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public boolean injectInputEvent(android.view.InputEvent, boolean);
method public final boolean performGlobalAction(int);
method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
......@@ -30400,6 +30403,7 @@ package android.view.accessibility {
field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
field public static final int TYPE_WINDOW_STATE_CHANGED = 32; // 0x20
}
......@@ -30463,6 +30467,7 @@ package android.view.accessibility {
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
method public java.lang.String getViewIdResourceName();
method public android.view.accessibility.AccessibilityWindowInfo getWindow();
method public int getWindowId();
method public boolean isAccessibilityFocused();
method public boolean isCheckable();
......@@ -30609,6 +30614,7 @@ package android.view.accessibility {
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public boolean performAction(int, int, android.os.Bundle);
field public static final int HOST_VIEW_ID = -1; // 0xffffffff
}
public class AccessibilityRecord {
......@@ -30660,6 +30666,28 @@ package android.view.accessibility {
method public void setToIndex(int);
}
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public int describeContents();
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
method public int getChildCount();
method public int getId();
method public int getLayer();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
method public int getType();
method public boolean isActive();
method public boolean isFocused();
method public static android.view.accessibility.AccessibilityWindowInfo obtain();
method public static android.view.accessibility.AccessibilityWindowInfo obtain(android.view.accessibility.AccessibilityWindowInfo);
method public void recycle();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int TYPE_APPLICATION = 1; // 0x1
field public static final int TYPE_INPUT_METHOD = 2; // 0x2
field public static final int TYPE_SYSTEM = 3; // 0x3
}
public class CaptioningManager {
method public void addCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
method public final float getFontScale();
......@@ -283,6 +283,27 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
/**
* This flag indicates to the system that the accessibility service wants
* to access content of all interactive windows. An interactive window is a
* window that can be touched by a sighted user when explore by touch is not
* enabled. If this flag is not set your service will not receive
* {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
* events, calling AccessibilityService{@link AccessibilityService#getWindows()
* AccessibilityService.getWindows()} will return an empty list, and {@link
* AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will
* return null.
* <p>
* Services that want to set this flag have to declare the capability
* to retrieve window content in their meta-data by setting the attribute
* {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to
* true, otherwise this flag will be ignored. For how to declare the meta-data
* of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
* </p>
* @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
*/
public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
/**
* The event types an {@link AccessibilityService} is interested in.
* <p>
......@@ -302,6 +323,15 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
* @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
* @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
* @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
* @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT
* @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START
* @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
* @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED
*/
public int eventTypes;
......@@ -354,6 +384,7 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
* @see #FLAG_REQUEST_FILTER_KEY_EVENTS
* @see #FLAG_REPORT_VIEW_IDS
* @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
*/
public int flags;
......@@ -449,7 +480,7 @@ public class AccessibilityServiceInfo implements Parcelable {
com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
0);
notificationTimeout = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
0);
flags = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
......@@ -861,6 +892,8 @@ public class AccessibilityServiceInfo implements Parcelable {
return "FLAG_REPORT_VIEW_IDS";
case FLAG_REQUEST_FILTER_KEY_EVENTS:
return "FLAG_REQUEST_FILTER_KEY_EVENTS";
case FLAG_RETRIEVE_INTERACTIVE_WINDOWS:
return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
default:
return null;
}
......
......@@ -18,6 +18,7 @@ package android.accessibilityservice;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.KeyEvent;
/**
......@@ -35,7 +36,9 @@ import android.view.KeyEvent;
void onGesture(int gesture);
void clearAccessibilityNodeInfoCache();
void clearAccessibilityCache();
void onKeyEvent(in KeyEvent event, int sequence);
void onWindowsChanged(in int[] changedWindowIds);
}
......@@ -21,6 +21,7 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.view.MagnificationSpec;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.accessibility.AccessibilityWindowInfo;
/**
* Interface given to an AccessibilitySerivce to talk to the AccessibilityManagerService.
......@@ -53,6 +54,10 @@ interface IAccessibilityServiceConnection {
int action, in Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId);
AccessibilityWindowInfo getWindow(int windowId);
List<AccessibilityWindowInfo> getWindows();
AccessibilityServiceInfo getServiceInfo();
boolean performGlobalAction(int action);
......
......@@ -36,9 +36,11 @@ import android.view.Surface;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
......@@ -269,10 +271,10 @@ public final class UiAutomation {
* @param action The action to perform.
* @return Whether the action was successfully performed.
*
* @see AccessibilityService#GLOBAL_ACTION_BACK
* @see AccessibilityService#GLOBAL_ACTION_HOME
* @see AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
* @see AccessibilityService#GLOBAL_ACTION_RECENTS
* @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK
* @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_HOME
* @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS
* @see android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_RECENTS
*/
public final boolean performGlobalAction(int action) {
final IAccessibilityServiceConnection connection;
......@@ -345,6 +347,33 @@ public final class UiAutomation {
}
}
/**
* Gets the windows on the screen. This method returns only the windows
* that a sighted user can interact with, as opposed to all windows.
* For example, if there is a modal dialog shown and the user cannot touch
* anything behind it, then only the modal window will be reported
* (assuming it is the top one). For convenience the returned windows
* are ordered in a descending layer order, which is the windows that
* are higher in the Z-order are reported first.
* <p>
* <strong>Note:</strong> In order to access the windows you have to opt-in
* to retrieve the interactive windows by setting the
* {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
* </p>
*
* @return The windows if there are windows such, otherwise an empty list.
*/
public List<AccessibilityWindowInfo> getWindows() {
final int connectionId;
synchronized (mLock) {
throwIfNotConnectedLocked();
connectionId = mConnectionId;
}
// Calling out without a lock held.
return AccessibilityInteractionClient.getInstance()
.getWindows(connectionId);
}
/**
* Gets the root {@link AccessibilityNodeInfo} in the active window.
*
......@@ -632,7 +661,7 @@ public final class UiAutomation {
* potentially undesirable actions such as calling 911 or posting on public forums etc.
*
* @param enable whether to run in a "monkey" mode or not. Default is not.
* @see {@link ActivityManager#isUserAMonkey()}
* @see {@link android.app.ActivityManager#isUserAMonkey()}
*/
public void setRunAsMonkey(boolean enable) {
synchronized (mLock) {
......
......@@ -111,7 +111,6 @@ public class LongArray implements Cloneable {
}
@Override
@SuppressWarnings("unchecked")
public LongArray clone() {
LongArray clone = null;
try {
......@@ -154,7 +153,8 @@ public class LongArray implements Cloneable {
if (index >= mSize) {
throw new ArrayIndexOutOfBoundsException(mSize, index);
}
System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
mSize--;
}
/**
......
/*
** Copyright 2012, 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;
import android.graphics.Region;
/**
* {@hide}
*/
oneway interface IMagnificationCallbacks {
void onMagnifedBoundsChanged(in Region bounds);
void onRectangleOnScreenRequested(int left, int top, int right, int bottom);
void onRotationChanged(int rotation);
void onUserContextChanged();
}
......@@ -27,7 +27,6 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IMagnificationCallbacks;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowSession;
......@@ -197,7 +196,7 @@ interface IWindowManager
void thawRotation();
/**
* Gets whether the rotation is frozen.
* Gets whether the rotation is frozen.
*
* @return Whether the rotation is frozen.
*/
......@@ -230,56 +229,8 @@ interface IWindowManager
*/
void lockNow(in Bundle options);
/**
* Gets the token for the focused window.
*/
IBinder getFocusedWindowToken();
/**
* Sets an input filter for manipulating the input event stream.
*/
void setInputFilter(in IInputFilter filter);
/**
* Gets the frame of a window given its token.
*/
void getWindowFrame(IBinder token, out Rect outFrame);
/**
* Device is in safe mode.
*/
boolean isSafeModeEnabled();
/**
* Sets the display magnification callbacks. These callbacks notify
* the client for contextual changes related to display magnification.
*
* @param callbacks The magnification callbacks.
*/
void setMagnificationCallbacks(IMagnificationCallbacks callbacks);
/**
* Sets the magnification spec to be applied to all windows that can be
* magnified.
*
* @param spec The current magnification spec.
*/
void setMagnificationSpec(in MagnificationSpec spec);
/**
* Gets the magnification spec for a window given its token. If the
* window has a compatibility scale it is also folded in the returned
* magnification spec.
*
* @param windowToken The unique window token.
* @return The magnification spec if such or null.
*/
MagnificationSpec getCompatibleMagnificationSpecForWindow(in IBinder windowToken);
/**
* Sets the current touch exploration state.
*
* @param enabled Whether touch exploration is enabled.
*/
void setTouchExplorationEnabled(boolean enabled);
}
......@@ -5101,10 +5101,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see AccessibilityDelegate
*/
public void sendAccessibilityEvent(int eventType) {
// Excluded views do not send accessibility events.
if (!includeForAccessibility()) {
return;
}
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
} else {
......@@ -9386,6 +9382,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mParent.invalidateChild(this, null);
}
dispatchVisibilityChanged(this, newVisibility);
notifySubtreeAccessibilityStateChangedIfNeeded();
}
if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
......
......@@ -3711,7 +3711,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
childHasTransientStateChanged(child, true);
}
if (child.isImportantForAccessibility() && child.getVisibility() != View.GONE) {
if (child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
......@@ -3954,7 +3954,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
onViewRemoved(view);
if (view.isImportantForAccessibility() && view.getVisibility() != View.GONE) {
if (view.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
......
......@@ -6355,7 +6355,7 @@ public final class ViewRootImpl implements ViewParent,
public void ensureConnection() {
if (mAttachInfo != null) {
final boolean registered =
mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
if (!registered) {
mAttachInfo.mAccessibilityWindowId =
mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
......@@ -6366,9 +6366,9 @@ public final class ViewRootImpl implements ViewParent,
public void ensureNoConnection() {
final boolean registered =
mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
if (registered) {
mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
}
}
......
/**
* Copyright (c) 2014, 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;
parcelable WindowInfo;
/*
* Copyright (C) 2014 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;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pools;
import java.util.ArrayList;
import java.util.List;
/**
* This class represents information about a window from the
* window manager to another part of the system.
*
* @hide
*/
public class WindowInfo implements Parcelable {
private static final int MAX_POOL_SIZE = 10;
private static final Pools.SynchronizedPool<WindowInfo> sPool =
new Pools.SynchronizedPool<WindowInfo>(MAX_POOL_SIZE);
public int type;
public int layer;
public IBinder token;
public IBinder parentToken;
public boolean focused;
public final Rect boundsInScreen = new Rect();
public List<IBinder> childTokens;
private WindowInfo() {
/* do nothing - hide constructor */
}
public static WindowInfo obtain() {
WindowInfo window = sPool.acquire();
if (window == null) {
window = new WindowInfo();
}
return window;
}
public static WindowInfo obtain(WindowInfo other) {
WindowInfo window = obtain();
window.type = other.type;
window.layer = other.layer;
window.token = other.token;
window.parentToken = other.parentToken;
window.focused = other.focused;
window.boundsInScreen.set(other.boundsInScreen);
if (other.childTokens != null && !other.childTokens.isEmpty()) {
if (window.childTokens == null) {
window.childTokens = new ArrayList<IBinder>(other.childTokens);
} else {
window.childTokens.addAll(other.childTokens);
}
}
return window;
}
public void recycle() {
clear();
sPool.release(this);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(type);
parcel.writeInt(layer);
parcel.writeStrongBinder(token);
parcel.writeStrongBinder(parentToken);
parcel.writeInt(focused ? 1 : 0);
boundsInScreen.writeToParcel(parcel, flags);
if (childTokens != null && !childTokens.isEmpty()) {
parcel.writeInt(1);
parcel.writeBinderList(childTokens);
} else {
parcel.writeInt(0);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WindowInfo[");
builder.append("type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
builder.append(", parent=").append(parentToken);
builder.append(", focused=").append(focused);
builder.append(", children=").append(childTokens);
builder.append(']');
return builder.toString();
}
private void initFromParcel(Parcel parcel) {
type = parcel.readInt();
layer = parcel.readInt();
token = parcel.readStrongBinder();
parentToken = parcel.readStrongBinder();
focused = (parcel.readInt() == 1);
boundsInScreen.readFromParcel(parcel);
final boolean hasChildren = (parcel.readInt() == 1);
if (hasChildren) {
if (childTokens == null) {
childTokens = new ArrayList<IBinder>();
}
parcel.readBinderList(childTokens);
}
}
private void clear() {
type = 0;
layer = 0;
token = null;
parentToken = null;
focused = false;
boundsInScreen.setEmpty();
if (childTokens != null) {
childTokens.clear();
}
}
public static final Parcelable.Creator<WindowInfo> CREATOR =
new Creator<WindowInfo>() {
@Override
public WindowInfo createFromParcel(Parcel parcel) {
WindowInfo window = obtain();
window.initFromParcel(parcel);
return window;
}
@Override
public WindowInfo[] newArray(int size) {
return new WindowInfo[size];
}
};
}
......@@ -16,7 +16,12 @@
package android.view;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
import android.os.IBinder;
import java.util.List;
/**
* Window manager local system service interface.
......@@ -24,10 +29,136 @@ import android.hardware.display.DisplayManagerInternal;
* @hide Only for use within the system server.
*/
public abstract class WindowManagerInternal {
/**
* Interface to receive a callback when the windows reported for
* accessibility changed.
*/
public interface WindowsForAccessibilityCallback {
/**
* Called when the windows for accessibility changed.
*
* @param windows The windows for accessibility.
*/
public void onWindowsForAccessibilityChanged(List<WindowInfo> windows);
}
/**
* Callbacks for contextual changes that affect the screen magnification
* feature.
*/
public interface MagnificationCallbacks {
/**
* Called when the bounds of the screen content that is magnified changed.
* Note that not the entire screen is magnified.
*
* @param bounds The bounds.
*/
public void onMagnifedBoundsChanged(Region bounds);
/**
* Called when an application requests a rectangle on the screen to allow
* the client to apply the appropriate pan and scale.
*
* @param left The rectangle left.
* @param top The rectangle top.
* @param right The rectangle right.
* @param bottom The rectangle bottom.
*/
public void onRectangleOnScreenRequested(int left, int top, int right, int bottom);
/**
* Notifies that the rotation changed.
*
* @param rotation The current rotation.
*/
public void onRotationChanged(int rotation);
/**
* Notifies that the context of the user changed. For example, an application