summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/input/InputManagerService.java
diff options
context:
space:
mode:
authorJens Doll <jens.doll@gmail.com>2013-04-17 17:32:04 +0200
committerDanny Baumann <dannybaumann@web.de>2013-05-15 13:44:23 +0200
commit9f11bd11a1389bb98d54f6e6114028f4e39f90e1 (patch)
tree9ca53656e66ccc069f452ed8f7544f6aaf6613cf /services/java/com/android/server/input/InputManagerService.java
parentcdd98977f5089eb829724579943dbe23480ea272 (diff)
downloadframeworks_base-9f11bd11a1389bb98d54f6e6114028f4e39f90e1.zip
frameworks_base-9f11bd11a1389bb98d54f6e6114028f4e39f90e1.tar.gz
frameworks_base-9f11bd11a1389bb98d54f6e6114028f4e39f90e1.tar.bz2
Pie controls: Introducing a pie delivery service
To make pie controls more reliable, it is neccessary to detect trigger actions directly from the input stream. This commit introduces a new system service, that filters all input events in front of the input dispatcher to detect pie activations. This commit introduces: * A new system server local API in the input manager service to register secondary input filters. These filters are behind the default accessibility filter but before the input event dispatching of the android framework. * A new system service, that binds to the new API to listen for pie activation gestures. * A non-public manager class providing access to the newly created pie service. The service manager name of the service is "pieservice". The non-public AIDL interface of the service is IPieService.aidl. To register a new pie activation listener the INJECT_INPUT permission is needed. The service state can be dumped by the "dumpsys pieservice" command. Note: This commit only introduces the pie service. There is another commit, that binds the actual pie controls to the pie service. Patch Set #1: * The pie service is currently disabled by default and needs to be enabled by device overlays (see config.xml / config_allowPieService). Patch Set #2: * Activation fixes * Debug dump improvements Patch Set #4: * Added systrace support (TRACE_INPUT_TAG) * Switch default to enable service on all devices. * Moved Position to com.internal.android.utils.pie.* * Some more code rearrangements Patch Set #5: * Rebase Patch Set #6: * Cover more corner cases on PieInputFilter * Adjust gesture time out Patch Set #7: * Do not send events that are from the past * Recycle all events Patch Set #8: * Handle binder died events in PieService correctly Patch Set #10: * Simplified locking * SYSTEM_UI_FLAG_HIDE_NAVIGATION support * Fixed ADW Lauchner bug Change-Id: I6a4a4635bed420e800a3230457ee690131116a11
Diffstat (limited to 'services/java/com/android/server/input/InputManagerService.java')
-rw-r--r--services/java/com/android/server/input/InputManagerService.java136
1 files changed, 109 insertions, 27 deletions
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 9921b5c..aa3b283 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -97,6 +97,7 @@ public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
static final String TAG = "InputManager";
static final boolean DEBUG = false;
+ static final boolean DEBUG_FILTER = false;
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
@@ -143,8 +144,9 @@ public class InputManagerService extends IInputManager.Stub
// State for the currently installed input filter.
final Object mInputFilterLock = new Object();
- IInputFilter mInputFilter; // guarded by mInputFilterLock
- InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ ChainedInputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ ArrayList<ChainedInputFilterHost> mInputFilterChain =
+ new ArrayList<ChainedInputFilterHost>(); // guarded by mInputFilterLock
private static native int nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
@@ -475,34 +477,77 @@ public class InputManagerService extends IInputManager.Stub
*/
public void setInputFilter(IInputFilter filter) {
synchronized (mInputFilterLock) {
- final IInputFilter oldFilter = mInputFilter;
+ final IInputFilter oldFilter = mInputFilterHost != null
+ ? mInputFilterHost.mInputFilter : null;
if (oldFilter == filter) {
return; // nothing to do
}
if (oldFilter != null) {
- mInputFilter = null;
mInputFilterHost.disconnectLocked();
+ mInputFilterChain.remove(mInputFilterHost);
mInputFilterHost = null;
- try {
- oldFilter.uninstall();
- } catch (RemoteException re) {
- /* ignore */
- }
}
if (filter != null) {
- mInputFilter = filter;
- mInputFilterHost = new InputFilterHost();
- try {
- filter.install(mInputFilterHost);
- } catch (RemoteException re) {
- /* ignore */
+ ChainedInputFilterHost head = mInputFilterChain.isEmpty() ? null :
+ mInputFilterChain.get(0);
+ mInputFilterHost = new ChainedInputFilterHost(filter, head);
+ mInputFilterHost.connectLocked();
+ mInputFilterChain.add(0, mInputFilterHost);
+ }
+
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ /**
+ * Registers a secondary input filter. These filters are always behind the "original"
+ * input filter. This ensures that all input events will be filtered by the
+ * {@code AccessibilityManagerService} first.
+ * <p>
+ * <b>Note:</b> Even though this implementation using AIDL interfaces, it is designed to only
+ * provide direct access. Therefore, any filter registering should reside in the
+ * system server DVM only!
+ *
+ * @param filter The input filter to register.
+ */
+ public void registerSecondaryInputFilter(IInputFilter filter) {
+ synchronized (mInputFilterLock) {
+ ChainedInputFilterHost host = new ChainedInputFilterHost(filter, null);
+ if (!mInputFilterChain.isEmpty()) {
+ mInputFilterChain.get(mInputFilterChain.size() - 1).mNext = host;
+ }
+ host.connectLocked();
+ mInputFilterChain.add(host);
+
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ public void unregisterSecondaryInputFilter(IInputFilter filter) {
+ synchronized (mInputFilterLock) {
+ int index = findInputFilterIndexLocked(filter);
+ if (index >= 0) {
+ ChainedInputFilterHost host = mInputFilterChain.get(index);
+ host.disconnectLocked();
+ if (index >= 1) {
+ mInputFilterChain.get(index - 1).mNext = host.mNext;
}
+ mInputFilterChain.remove(index);
}
- nativeSetInputFilterEnabled(mPtr, filter != null);
+ nativeSetInputFilterEnabled(mPtr, !mInputFilterChain.isEmpty());
+ }
+ }
+
+ private int findInputFilterIndexLocked(IInputFilter filter) {
+ for (int i = 0; i < mInputFilterChain.size(); i++) {
+ if (mInputFilterChain.get(i).mInputFilter == filter) {
+ return i;
+ }
}
+ return -1;
}
@Override // Binder call
@@ -1327,16 +1372,23 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
final boolean filterInputEvent(InputEvent event, int policyFlags) {
+ ChainedInputFilterHost head = null;
synchronized (mInputFilterLock) {
- if (mInputFilter != null) {
- try {
- mInputFilter.filterInputEvent(event, policyFlags);
- } catch (RemoteException e) {
- /* ignore */
- }
- return false;
+ if (!mInputFilterChain.isEmpty()) {
+ head = mInputFilterChain.get(0);
}
}
+ // call filter input event outside of the lock.
+ // this is safe, because we know that mInputFilter never changes.
+ // we may loose a event, but this does not differ from the original implementation.
+ if (head != null) {
+ try {
+ head.mInputFilter.filterInputEvent(event, policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ return false;
+ }
event.recycle();
return true;
}
@@ -1561,10 +1613,32 @@ public class InputManagerService extends IInputManager.Stub
/**
* Hosting interface for input filters to call back into the input manager.
*/
- private final class InputFilterHost extends IInputFilterHost.Stub {
+ private final class ChainedInputFilterHost extends IInputFilterHost.Stub {
+ private final IInputFilter mInputFilter;
+ private ChainedInputFilterHost mNext;
private boolean mDisconnected;
+ private ChainedInputFilterHost(IInputFilter filter, ChainedInputFilterHost next) {
+ mInputFilter = filter;
+ mNext = next;
+ mDisconnected = false;
+ }
+
+ public void connectLocked() {
+ try {
+ mInputFilter.install(this);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
public void disconnectLocked() {
+ try {
+ mInputFilter.uninstall();
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ // DO NOT set mInputFilter to null here! mInputFilter is used outside of the lock!
mDisconnected = true;
}
@@ -1576,9 +1650,17 @@ public class InputManagerService extends IInputManager.Stub
synchronized (mInputFilterLock) {
if (!mDisconnected) {
- nativeInjectInputEvent(mPtr, event, 0, 0,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
- policyFlags | WindowManagerPolicy.FLAG_FILTERED);
+ if (mNext == null) {
+ nativeInjectInputEvent(mPtr, event, 0, 0,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
+ policyFlags | WindowManagerPolicy.FLAG_FILTERED);
+ } else {
+ try {
+ mNext.mInputFilter.filterInputEvent(event, policyFlags);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
}
}
}