summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2014-10-14 09:54:26 -0700
committerSvetoslav <svetoslavganov@google.com>2014-10-21 14:45:53 -0700
commit3a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bb (patch)
tree764dfd933c0a80c42fd4214f375c456e6370e548 /core/java/android
parentd00e68c3b6a4c727bd59a7e7c4524fb3fdd193f0 (diff)
downloadframeworks_base-3a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bb.zip
frameworks_base-3a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bb.tar.gz
frameworks_base-3a5c721072c60c7ed9c8a95d0a65d0e3cb4eb9bb.tar.bz2
APIs for an accessibility service to put interaction tracking overlays.
An accessibility service may register to observe the interactive windows on the primary display. These windows are the one that has input focus and ones a sighted user can touch. It is sometimes beneficial for an accessibility service to overlay a window to intercept user interaction and based on that introspect and perform an action on the windows that are on the screen. This is problematic as overlaying a full screen window that is touchable prevents the accessibility service to introspect the content under this window. This change adds a special type of window that only an accessibility service can place which does not affect what an accessibility service can "see" on the screen. Hence, even putting such a window full screen the service will be able to interact with the other interactive windows it covers. Change-Id: I053ccc3a5c6360a98dc40bdb172b54dab35d8b31
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java96
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl2
-rw-r--r--core/java/android/app/UiAutomation.java3
-rw-r--r--core/java/android/view/WindowManager.java13
-rw-r--r--core/java/android/view/WindowManagerInternal.java16
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java35
6 files changed, 144 insertions, 21 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 13ceb4a..1e1b33f 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -24,13 +24,18 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Display;
import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
import java.util.List;
@@ -366,7 +371,7 @@ public abstract class AccessibilityService extends Service {
public void onAccessibilityEvent(AccessibilityEvent event);
public void onInterrupt();
public void onServiceConnected();
- public void onSetConnectionId(int connectionId);
+ public void init(int connectionId, IBinder windowToken);
public boolean onGesture(int gestureId);
public boolean onKeyEvent(KeyEvent event);
}
@@ -375,6 +380,10 @@ public abstract class AccessibilityService extends Service {
private AccessibilityServiceInfo mInfo;
+ private IBinder mWindowToken;
+
+ private WindowManager mWindowManager;
+
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
*
@@ -611,6 +620,18 @@ public abstract class AccessibilityService extends Service {
}
}
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.WINDOW_SERVICE.equals(name)) {
+ if (mWindowManager == null) {
+ WindowManager wrapped = (WindowManager) super.getSystemService(name);
+ mWindowManager = new LocalWindowManager(wrapped);
+ }
+ return mWindowManager;
+ }
+ return super.getSystemService(name);
+ }
+
/**
* Implement to return the implementation of the internal accessibility
* service interface.
@@ -634,8 +655,9 @@ public abstract class AccessibilityService extends Service {
}
@Override
- public void onSetConnectionId( int connectionId) {
+ public void init(int connectionId, IBinder windowToken) {
mConnectionId = connectionId;
+ mWindowToken = windowToken;
}
@Override
@@ -658,7 +680,7 @@ public abstract class AccessibilityService extends Service {
*/
public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
implements HandlerCaller.Callback {
- private static final int DO_SET_SET_CONNECTION = 1;
+ private static final int DO_INIT = 1;
private static final int DO_ON_INTERRUPT = 2;
private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
private static final int DO_ON_GESTURE = 4;
@@ -677,9 +699,10 @@ public abstract class AccessibilityService extends Service {
mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
}
- public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
- Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId,
- connection);
+ public void init(IAccessibilityServiceConnection connection, int connectionId,
+ IBinder windowToken) {
+ Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
+ connection, windowToken);
mCaller.sendMessage(message);
}
@@ -730,20 +753,24 @@ public abstract class AccessibilityService extends Service {
mCallback.onInterrupt();
} return;
- case DO_SET_SET_CONNECTION: {
+ case DO_INIT: {
mConnectionId = message.arg1;
+ SomeArgs args = (SomeArgs) message.obj;
IAccessibilityServiceConnection connection =
- (IAccessibilityServiceConnection) message.obj;
+ (IAccessibilityServiceConnection) args.arg1;
+ IBinder windowToken = (IBinder) args.arg2;
+ args.recycle();
if (connection != null) {
AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
connection);
- mCallback.onSetConnectionId(mConnectionId);
+ mCallback.init(mConnectionId, windowToken);
mCallback.onServiceConnected();
} else {
AccessibilityInteractionClient.getInstance().removeConnection(
mConnectionId);
+ mConnectionId = AccessibilityInteractionClient.NO_ID;
AccessibilityInteractionClient.getInstance().clearCache();
- mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
+ mCallback.init(AccessibilityInteractionClient.NO_ID, null);
}
} return;
@@ -785,4 +812,53 @@ public abstract class AccessibilityService extends Service {
}
}
}
+
+ private class LocalWindowManager implements WindowManager {
+ private final WindowManager mImpl;
+
+ private LocalWindowManager(WindowManager impl) {
+ mImpl = impl;
+ }
+
+ @Override
+ public Display getDefaultDisplay() {
+ return mImpl.getDefaultDisplay();
+ }
+
+ @Override
+ public void addView(View view, ViewGroup.LayoutParams params) {
+ if (!(params instanceof WindowManager.LayoutParams)) {
+ throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+ }
+ WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
+ if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
+ && windowParams.token == null) {
+ windowParams.token = mWindowToken;
+ }
+ mImpl.addView(view, params);
+ }
+
+ @Override
+ public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
+ if (!(params instanceof WindowManager.LayoutParams)) {
+ throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+ }
+ WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
+ if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
+ && windowParams.token == null) {
+ windowParams.token = mWindowToken;
+ }
+ mImpl.updateViewLayout(view, params);
+ }
+
+ @Override
+ public void removeViewImmediate(View view) {
+ mImpl.removeViewImmediate(view);
+ }
+
+ @Override
+ public void removeView(View view) {
+ mImpl.removeView(view);
+ }
+ }
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6ce0219..8b503dd 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -28,7 +28,7 @@ import android.view.KeyEvent;
*/
oneway interface IAccessibilityServiceClient {
- void setConnection(in IAccessibilityServiceConnection connection, int connectionId);
+ void init(in IAccessibilityServiceConnection connection, int connectionId, IBinder windowToken);
void onAccessibilityEvent(in AccessibilityEvent event);
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 4aec9e0..b0dd70f 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -25,6 +25,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -919,7 +920,7 @@ public final class UiAutomation {
public IAccessibilityServiceClientImpl(Looper looper) {
super(null, looper, new Callbacks() {
@Override
- public void onSetConnectionId(int connectionId) {
+ public void init(int connectionId, IBinder windowToken) {
synchronized (mLock) {
mConnectionId = connectionId;
mLock.notifyAll();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 75c9ebd..7f3829a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -542,6 +542,19 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
/**
+ * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * android.accessibilityservice.AccessibilityService} for interception of
+ * user interactions without changing the windows an accessibility service
+ * can introspect. In particular, an accessibility service can introspect
+ * only windows that a sighted user can interact with which is they can touch
+ * these windows or can type into these windows. For example, if there
+ * is a full screen accessibility overlay that is touchable, the windows
+ * below it will be introspectable by an accessibility service regardless
+ * they are covered by a touchable window.
+ */
+ public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 38e3723..f557b97 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -173,4 +173,20 @@ public abstract class WindowManagerInternal {
* redrawn.
*/
public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout);
+
+ /**
+ * Adds a window token for a given window type.
+ *
+ * @param token The token to add.
+ * @param type The window type.
+ */
+ public abstract void addWindowToken(android.os.IBinder token, int type);
+
+ /**
+ * Removes a window token.
+ *
+ * @param token The toke to remove.
+ * @param removeWindows Whether to also remove the windows associated with the token.
+ */
+ public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows);
}
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ad55f5f..e1942be 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -51,11 +51,24 @@ public final class AccessibilityWindowInfo implements Parcelable {
*/
public static final int TYPE_SYSTEM = 3;
+ /**
+ * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * android.accessibilityservice.AccessibilityService} for interception of
+ * user interactions without changing the windows an accessibility service
+ * can introspect. In particular, an accessibility service can introspect
+ * only windows that a sighted user can interact with which they can touch
+ * these windows or can type into these windows. For example, if there
+ * is a full screen accessibility overlay that is touchable, the windows
+ * below it will be introspectable by an accessibility service regardless
+ * they are covered by a touchable window.
+ */
+ public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
+
private static final int UNDEFINED = -1;
private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0;
private static final int BOOLEAN_PROPERTY_FOCUSED = 1 << 1;
- private static final int BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED = 1 << 2;
+ private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 1 << 2;
// Housekeeping.
private static final int MAX_POOL_SIZE = 10;
@@ -85,6 +98,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
* @see #TYPE_APPLICATION
* @see #TYPE_INPUT_METHOD
* @see #TYPE_SYSTEM
+ * @see #TYPE_ACCESSIBILITY_OVERLAY
*/
public int getType() {
return mType;
@@ -93,7 +107,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
/**
* Sets the type of the window.
*
- * @param The type
+ * @param type The type
*
* @hide
*/
@@ -115,7 +129,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
* Sets the layer which determines the Z-order of the window. Windows
* with greater layer appear on top of windows with lesser layer.
*
- * @param The window layer.
+ * @param layer The window layer.
*
* @hide
*/
@@ -174,7 +188,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
/**
* Sets the unique window id.
*
- * @param windowId The window id.
+ * @param id The window id.
*
* @hide
*/
@@ -230,7 +244,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
* the user is currently touching or the window has input focus
* and the user is not touching any window.
*
- * @param Whether this is the active window.
+ * @param active Whether this is the active window.
*
* @hide
*/
@@ -250,7 +264,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
/**
* Sets if this window has input focus.
*
- * @param Whether has input focus.
+ * @param focused Whether has input focus.
*
* @hide
*/
@@ -264,18 +278,18 @@ public final class AccessibilityWindowInfo implements Parcelable {
* @return Whether has accessibility focus.
*/
public boolean isAccessibilityFocused() {
- return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED);
+ return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
}
/**
* Sets if this window has accessibility focus.
*
- * @param Whether has accessibility focus.
+ * @param focused Whether has accessibility focus.
*
* @hide
*/
public void setAccessibilityFocused(boolean focused) {
- setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED, focused);
+ setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
}
/**
@@ -534,6 +548,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
case TYPE_SYSTEM: {
return "TYPE_SYSTEM";
}
+ case TYPE_ACCESSIBILITY_OVERLAY: {
+ return "TYPE_ACCESSIBILITY_OVERLAY";
+ }
default:
return "<UNKNOWN>";
}