am bd6fabe2: Merge "APIs for an accessibility service to put interaction tracking overlays." into lmp-mr1-dev

automerge: 89e7ffe

* commit '89e7ffedadd20a3091e72b42f86c500452df193c':
  APIs for an accessibility service to put interaction tracking overlays.
This commit is contained in:
Svetoslav
2014-10-24 02:04:11 +00:00
committed by android-build-merger
12 changed files with 234 additions and 36 deletions

View File

@@ -34967,6 +34967,7 @@ package android.view {
field public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0; // 0x0
field public static final int SOFT_INPUT_STATE_VISIBLE = 4; // 0x4
field public static final int TITLE_CHANGED = 64; // 0x40
field public static final int TYPE_ACCESSIBILITY_OVERLAY = 2032; // 0x7f0
field public static final int TYPE_APPLICATION = 2; // 0x2
field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
@@ -35386,6 +35387,7 @@ package android.view.accessibility {
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_ACCESSIBILITY_OVERLAY = 4; // 0x4
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

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -541,6 +541,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.
*/

View File

@@ -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);
}

View File

@@ -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>";
}

View File

@@ -1431,6 +1431,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case TYPE_WALLPAPER:
case TYPE_PRIVATE_PRESENTATION:
case TYPE_VOICE_INTERACTION:
case TYPE_ACCESSIBILITY_OVERLAY:
// The window manager will check these.
break;
case TYPE_PHONE:
@@ -1660,15 +1661,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
return 25;
case TYPE_SECURE_SYSTEM_OVERLAY:
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
return 26;
case TYPE_BOOT_PROGRESS:
case TYPE_SECURE_SYSTEM_OVERLAY:
return 27;
case TYPE_BOOT_PROGRESS:
return 28;
case TYPE_POINTER:
// the (mouse) pointer layer
return 28;
case TYPE_HIDDEN_NAV_CONSUMER:
return 29;
case TYPE_HIDDEN_NAV_CONSUMER:
return 30;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
@@ -1972,7 +1976,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
mKeyguardScrim = win;
break;
}
return WindowManagerGlobal.ADD_OKAY;
}

View File

@@ -1040,7 +1040,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void addServiceLocked(Service service, UserState userState) {
try {
service.linkToOwnDeathLocked();
service.onAdded();
userState.mBoundServices.add(service);
userState.mComponentNameToServiceMap.put(service.mComponentName, service);
} catch (RemoteException re) {
@@ -1056,7 +1056,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void removeServiceLocked(Service service, UserState userState) {
userState.mBoundServices.remove(service);
userState.mComponentNameToServiceMap.remove(service.mComponentName);
service.unlinkToOwnDeathLocked();
service.onRemoved();
}
/**
@@ -1931,6 +1931,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final ResolveInfo mResolveInfo;
final IBinder mOverlayWindowToken = new Binder();
// the events pending events to be dispatched to this service
final SparseArray<AccessibilityEvent> mPendingEvents =
new SparseArray<>();
@@ -2112,7 +2114,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
userState.mBindingServices.remove(mComponentName);
mWasConnectedAndDied = false;
try {
mServiceInterface.setConnection(this, mId);
mServiceInterface.init(this, mId, mOverlayWindowToken);
onUserStateChangedLocked(userState);
} catch (RemoteException re) {
Slog.w(LOG_TAG, "Error while setting connection for service: "
@@ -2602,6 +2604,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
/* do nothing - #binderDied takes care */
}
public void onAdded() throws RemoteException {
linkToOwnDeathLocked();
final long identity = Binder.clearCallingIdentity();
try {
mWindowManagerService.addWindowToken(mOverlayWindowToken,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
public void onRemoved() {
final long identity = Binder.clearCallingIdentity();
try {
mWindowManagerService.removeWindowToken(mOverlayWindowToken, true);
} finally {
Binder.restoreCallingIdentity(identity);
}
unlinkToOwnDeathLocked();
}
public void linkToOwnDeathLocked() throws RemoteException {
mService.linkToDeath(this, 0);
}
@@ -2614,7 +2637,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
try {
// Clear the proxy in the other process so this
// IAccessibilityServiceConnection can be garbage collected.
mServiceInterface.setConnection(null, mId);
mServiceInterface.init(null, mId, null);
} catch (RemoteException re) {
/* ignore */
}
@@ -3164,6 +3187,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
}
default: {
return -1;
}

View File

@@ -992,8 +992,7 @@ final class AccessibilityController {
final int flags = windowState.mAttrs.flags;
// If the window is not touchable, do not report it but take into account
// the space it takes since the content behind it cannot be touched.
// If the window is not touchable - ignore.
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
continue;
}
@@ -1014,9 +1013,14 @@ final class AccessibilityController {
}
}
// Account for the space this window takes.
unaccountedSpace.op(boundsInScreen, unaccountedSpace,
Region.Op.REVERSE_DIFFERENCE);
// Account for the space this window takes if the window
// is not an accessibility overlay which does not change
// the reported windows.
if (windowState.mAttrs.type == WindowManager.LayoutParams
.TYPE_ACCESSIBILITY_OVERLAY) {
unaccountedSpace.op(boundsInScreen, unaccountedSpace,
Region.Op.REVERSE_DIFFERENCE);
}
// We figured out what is touchable for the entire screen - done.
if (unaccountedSpace.isEmpty()) {

View File

@@ -2337,6 +2337,11 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (type == TYPE_ACCESSIBILITY_OVERLAY) {
Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
} else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -2380,6 +2385,12 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (token.appWindowToken != null) {
Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
// It is not valid to use an app token with other system types; we will
@@ -11627,5 +11638,23 @@ public class WindowManagerService extends IWindowManager.Stub
checkDrawnWindowsLocked();
}
}
@Override
public void addWindowToken(IBinder token, int type) {
WindowManagerService.this.addWindowToken(token, type);
}
@Override
public void removeWindowToken(IBinder token, boolean removeWindows) {
synchronized(mWindowMap) {
if (removeWindows) {
WindowToken wtoken = mTokenMap.remove(token);
if (wtoken != null) {
wtoken.removeAllWindows();
}
}
WindowManagerService.this.removeWindowToken(token);
}
}
}
}

View File

@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.os.IBinder;
import android.util.Slog;
import java.io.PrintWriter;
@@ -29,7 +30,7 @@ import java.io.PrintWriter;
class WindowToken {
// The window manager!
final WindowManagerService service;
// The actual token.
final IBinder token;
@@ -77,6 +78,15 @@ class WindowToken {
explicit = _explicit;
}
void removeAllWindows() {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
WindowState win = windows.get(winNdx);
if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) Slog.w(WindowManagerService.TAG,
"removeAllWindows: removing win=" + win);
win.mService.removeWindowLocked(win.mSession, win);
}
}
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("windows="); pw.println(windows);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);