Centralize all system InputEventReceiver monitors.
Implement all system level InputEvent monitors as new
InputEventListeners. Only one InputChannel required and monitoring
can be enabled or disabled by registering with WindowManagerService.
Change-Id: I64714ab858342ed183c62b421098478ffb6637bc
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 6291e62..c735dd7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -408,11 +408,6 @@
public int getLidState();
/**
- * Creates an input channel that will receive all input from the input dispatcher.
- */
- public InputChannel monitorInput(String name);
-
- /**
* Switch the keyboard layout for the given device.
* Direction should be +1 or -1 to go to the next or previous keyboard layout.
*/
@@ -425,6 +420,21 @@
* Return the window manager lock needed to correctly call "Lw" methods.
*/
public Object getWindowManagerLock();
+
+ /** Register a system listener for touch events */
+ void registerPointerEventListener(PointerEventListener listener);
+
+ /** Unregister a system listener for touch events */
+ void unregisterPointerEventListener(PointerEventListener listener);
+ }
+
+ public interface PointerEventListener {
+ /**
+ * 1. onPointerEvent will be called on the service.UiThread.
+ * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
+ * copy() must be made and the copy must be recycled.
+ **/
+ public void onPointerEvent(MotionEvent motionEvent);
}
/** Window has been added to the screen. */
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 0da3b56..4930d59 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -296,35 +296,18 @@
WindowState mFocusedWindow;
IApplicationToken mFocusedApp;
- private static final class PointerLocationInputEventReceiver extends InputEventReceiver {
- private final PointerLocationView mView;
-
- public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper,
- PointerLocationView view) {
- super(inputChannel, looper);
- mView = view;
- }
-
+ private final class PointerLocationPointerEventListener implements PointerEventListener {
@Override
- public void onInputEvent(InputEvent event) {
- boolean handled = false;
- try {
- if (event instanceof MotionEvent
- && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- final MotionEvent motionEvent = (MotionEvent)event;
- mView.addPointerEvent(motionEvent);
- handled = true;
- }
- } finally {
- finishInputEvent(event, handled);
+ public void onPointerEvent(MotionEvent motionEvent) {
+ if (mPointerLocationView != null) {
+ mPointerLocationView.addPointerEvent(motionEvent);
}
}
}
// Pointer location view state, only modified on the mHandler Looper.
- PointerLocationInputEventReceiver mPointerLocationInputEventReceiver;
+ PointerLocationPointerEventListener mPointerLocationPointerEventListener;
PointerLocationView mPointerLocationView;
- InputChannel mPointerLocationInputChannel;
// The current size of the screen; really; extends into the overscan area of
// the screen and doesn't account for any system elements like the status bar.
@@ -568,8 +551,7 @@
private int mStatusHideybar;
private int mNavigationHideybar;
- private InputChannel mSystemGestureInputChannel;
- private SystemGestures mSystemGestures;
+ private SystemGesturesPointerEventListener mSystemGestures;
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
@@ -925,10 +907,8 @@
context.registerReceiver(mMultiuserReceiver, filter);
// monitor for system gestures
- mSystemGestureInputChannel = mWindowManagerFuncs.monitorInput("SystemGestures");
- mSystemGestures = new SystemGestures(mSystemGestureInputChannel,
- mHandler.getLooper(), context,
- new SystemGestures.Callbacks() {
+ mSystemGestures = new SystemGesturesPointerEventListener(context,
+ new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
if (mStatusBar != null) {
@@ -954,6 +934,7 @@
}
}
});
+ mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
@@ -1212,23 +1193,16 @@
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(mPointerLocationView, lp);
- mPointerLocationInputChannel =
- mWindowManagerFuncs.monitorInput("PointerLocationView");
- mPointerLocationInputEventReceiver =
- new PointerLocationInputEventReceiver(mPointerLocationInputChannel,
- Looper.myLooper(), mPointerLocationView);
+ mPointerLocationPointerEventListener = new PointerLocationPointerEventListener();
+ mWindowManagerFuncs.registerPointerEventListener(mPointerLocationPointerEventListener);
}
}
private void disablePointerLocation() {
- if (mPointerLocationInputEventReceiver != null) {
- mPointerLocationInputEventReceiver.dispose();
- mPointerLocationInputEventReceiver = null;
- }
-
- if (mPointerLocationInputChannel != null) {
- mPointerLocationInputChannel.dispose();
- mPointerLocationInputChannel = null;
+ if (mPointerLocationPointerEventListener != null) {
+ mWindowManagerFuncs.unregisterPointerEventListener(
+ mPointerLocationPointerEventListener);
+ mPointerLocationPointerEventListener = null;
}
if (mPointerLocationView != null) {
diff --git a/policy/src/com/android/internal/policy/impl/SystemGestures.java b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
similarity index 90%
rename from policy/src/com/android/internal/policy/impl/SystemGestures.java
rename to policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
index c9731a5..6e8c841 100644
--- a/policy/src/com/android/internal/policy/impl/SystemGestures.java
+++ b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
@@ -17,19 +17,15 @@
package com.android.internal.policy.impl;
import android.content.Context;
-import android.os.Looper;
import android.util.Slog;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
/*
* Listens for system-wide input gestures, firing callbacks when detected.
* @hide
*/
-public class SystemGestures extends InputEventReceiver {
+public class SystemGesturesPointerEventListener implements PointerEventListener {
private static final String TAG = "SystemGestures";
private static final boolean DEBUG = false;
private static final long SWIPE_TIMEOUT_MS = 500;
@@ -55,9 +51,7 @@
private boolean mSwipeFireable;
private boolean mDebugFireable;
- public SystemGestures(InputChannel inputChannel, Looper looper,
- Context context, Callbacks callbacks) {
- super(inputChannel, looper);
+ public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
mCallbacks = checkNull("callbacks", callbacks);
mSwipeStartThreshold = checkNull("context", context).getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -72,14 +66,7 @@
}
@Override
- public void onInputEvent(InputEvent event) {
- if (event instanceof MotionEvent && event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
- onPointerMotionEvent((MotionEvent) event);
- }
- finishInputEvent(event, false /*handled*/);
- }
-
- private void onPointerMotionEvent(MotionEvent event) {
+ public void onPointerEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mSwipeFireable = true;
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 4a3699c..82e8c7f 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -28,7 +28,6 @@
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.InputChannel;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -101,11 +100,8 @@
/** Sorted most recent at top, oldest at [0]. */
ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>();
- /** Forward motion events to mTapDetector. */
- InputChannel mTapInputChannel;
-
/** Detect user tapping outside of current focused stack bounds .*/
- StackTapDetector mTapDetector;
+ StackTapPointerEventListener mTapDetector;
/** Detect user tapping outside of current focused stack bounds .*/
Region mTouchExcludeRegion = new Region();
diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/java/com/android/server/wm/PointerEventDispatcher.java
new file mode 100644
index 0000000..6b0e4c9
--- /dev/null
+++ b/services/java/com/android/server/wm/PointerEventDispatcher.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 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 com.android.server.wm;
+
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.UiThread;
+
+import java.util.ArrayList;
+
+public class PointerEventDispatcher extends InputEventReceiver {
+ ArrayList<PointerEventListener> mListeners = new ArrayList<PointerEventListener>();
+ PointerEventListener[] mListenersArray = new PointerEventListener[0];
+
+ public PointerEventDispatcher(InputChannel inputChannel) {
+ super(inputChannel, UiThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ try {
+ if (event instanceof MotionEvent
+ && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ final MotionEvent motionEvent = (MotionEvent)event;
+ PointerEventListener[] listeners;
+ synchronized (mListeners) {
+ if (mListenersArray == null) {
+ mListenersArray = new PointerEventListener[mListeners.size()];
+ mListeners.toArray(mListenersArray);
+ }
+ listeners = mListenersArray;
+ }
+ for (int i = 0; i < listeners.length; ++i) {
+ listeners[i].onPointerEvent(motionEvent);
+ }
+ }
+ } finally {
+ finishInputEvent(event, false);
+ }
+ }
+
+ /**
+ * Add the specified listener to the list.
+ * @param listener The listener to add.
+ */
+ public void registerInputEventListener(PointerEventListener listener) {
+ synchronized (mListeners) {
+ if (mListeners.contains(listener)) {
+ throw new IllegalStateException("registerInputEventListener: trying to register" +
+ listener + " twice.");
+ }
+ mListeners.add(listener);
+ mListenersArray = null;
+ }
+ }
+
+ /**
+ * Remove the specified listener from the list.
+ * @param listener The listener to remove.
+ */
+ public void unregisterInputEventListener(PointerEventListener listener) {
+ synchronized (mListeners) {
+ if (!mListeners.contains(listener)) {
+ throw new IllegalStateException("registerInputEventListener: " + listener +
+ " not registered.");
+ }
+ mListeners.remove(listener);
+ mListenersArray = null;
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/StackTapDetector.java b/services/java/com/android/server/wm/StackTapDetector.java
deleted file mode 100644
index 7127fd2..0000000
--- a/services/java/com/android/server/wm/StackTapDetector.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.android.server.wm;
-
-import android.graphics.Region;
-import android.os.Looper;
-import android.view.DisplayInfo;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.MotionEvent;
-
-import com.android.server.wm.WindowManagerService.H;
-
-public class StackTapDetector extends InputEventReceiver {
- private static final int TAP_TIMEOUT_MSEC = 300;
- private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
-
- private final int mMotionSlop;
- private float mDownX;
- private float mDownY;
- private int mPointerId;
- final private Region mTouchExcludeRegion;
- private final WindowManagerService mService;
- private final DisplayContent mDisplayContent;
-
- public StackTapDetector(WindowManagerService service, DisplayContent displayContent,
- InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- mService = service;
- mDisplayContent = displayContent;
- mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
- DisplayInfo info = displayContent.getDisplayInfo();
- mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
- }
-
- @Override
- public void onInputEvent(InputEvent event) {
- try {
- if (!(event instanceof MotionEvent)
- || !event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
- return;
- }
- final MotionEvent motionEvent = (MotionEvent)event;
- final int action = motionEvent.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- mPointerId = motionEvent.getPointerId(0);
- mDownX = motionEvent.getX();
- mDownY = motionEvent.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- if (mPointerId >= 0) {
- int index = motionEvent.findPointerIndex(mPointerId);
- if ((motionEvent.getEventTime() - motionEvent.getDownTime())
- > TAP_TIMEOUT_MSEC
- || (motionEvent.getX(index) - mDownX) > mMotionSlop
- || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
- mPointerId = -1;
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP: {
- int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- // Extract the index of the pointer that left the touch sensor
- if (mPointerId == motionEvent.getPointerId(index)) {
- final int x = (int)motionEvent.getX(index);
- final int y = (int)motionEvent.getY(index);
- synchronized (this) {
- if ((motionEvent.getEventTime() - motionEvent.getDownTime())
- < TAP_TIMEOUT_MSEC
- && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
- && !mTouchExcludeRegion.contains(x, y)) {
- mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
- mDisplayContent).sendToTarget();
- }
- }
- mPointerId = -1;
- }
- break;
- }
- }
- } finally {
- finishInputEvent(event, false /*ignored for monitors*/);
- }
- }
-}
diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/java/com/android/server/wm/StackTapPointerEventListener.java
new file mode 100644
index 0000000..19d8ab3
--- /dev/null
+++ b/services/java/com/android/server/wm/StackTapPointerEventListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 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 com.android.server.wm;
+
+import android.graphics.Region;
+import android.view.DisplayInfo;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.wm.WindowManagerService.H;
+
+public class StackTapPointerEventListener implements PointerEventListener {
+ private static final int TAP_TIMEOUT_MSEC = 300;
+ private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
+
+ private final int mMotionSlop;
+ private float mDownX;
+ private float mDownY;
+ private int mPointerId;
+ final private Region mTouchExcludeRegion;
+ private final WindowManagerService mService;
+ private final DisplayContent mDisplayContent;
+
+ public StackTapPointerEventListener(WindowManagerService service,
+ DisplayContent displayContent) {
+ mService = service;
+ mDisplayContent = displayContent;
+ mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
+ DisplayInfo info = displayContent.getDisplayInfo();
+ mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
+ }
+
+ @Override
+ public void onPointerEvent(MotionEvent motionEvent) {
+ final int action = motionEvent.getAction();
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ mPointerId = motionEvent.getPointerId(0);
+ mDownX = motionEvent.getX();
+ mDownY = motionEvent.getY();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mPointerId >= 0) {
+ int index = motionEvent.findPointerIndex(mPointerId);
+ if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
+ || (motionEvent.getX(index) - mDownX) > mMotionSlop
+ || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
+ mPointerId = -1;
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP: {
+ int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ // Extract the index of the pointer that left the touch sensor
+ if (mPointerId == motionEvent.getPointerId(index)) {
+ final int x = (int)motionEvent.getX(index);
+ final int y = (int)motionEvent.getY(index);
+ if ((motionEvent.getEventTime() - motionEvent.getDownTime())
+ < TAP_TIMEOUT_MSEC
+ && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
+ && !mTouchExcludeRegion.contains(x, y)) {
+ mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
+ mDisplayContent).sendToTarget();
+ }
+ mPointerId = -1;
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f166c31..079134b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -124,6 +124,7 @@
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerPolicy.FakeWindow;
+import android.view.WindowManagerPolicy.PointerEventListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
@@ -281,8 +282,6 @@
private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- private static final String TAP_INPUT_CHANNEL_NAME = "StackTapDetector";
-
private static final int MAX_SCREENSHOT_RETRIES = 3;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -594,6 +593,8 @@
SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
+ private final PointerEventDispatcher mPointerEventDispatcher;
+
final class DragInputEventReceiver extends InputEventReceiver {
public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
@@ -728,6 +729,8 @@
mDisplaySettings = new DisplaySettings(context);
mDisplaySettings.readSettingsLocked();
+ mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
+
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this, null);
Display[] displays = mDisplayManager.getDisplays();
@@ -5098,6 +5101,16 @@
mAnimatorDurationScale };
}
+ @Override
+ public void registerPointerEventListener(PointerEventListener listener) {
+ mPointerEventDispatcher.registerInputEventListener(listener);
+ }
+
+ @Override
+ public void unregisterPointerEventListener(PointerEventListener listener) {
+ mPointerEventDispatcher.unregisterInputEventListener(listener);
+ }
+
// Called by window manager policy. Not exposed externally.
@Override
public int getLidState() {
@@ -5117,12 +5130,6 @@
// Called by window manager policy. Not exposed externally.
@Override
- public InputChannel monitorInput(String inputChannelName) {
- return mInputManager.monitorInput(inputChannelName);
- }
-
- // Called by window manager policy. Not exposed externally.
- @Override
public void switchKeyboardLayout(int deviceId, int direction) {
mInputManager.switchKeyboardLayout(deviceId, direction);
}
@@ -10652,10 +10659,8 @@
// TODO: Create an input channel for each display with touch capability.
if (displayId == Display.DEFAULT_DISPLAY) {
- InputChannel inputChannel = monitorInput(TAP_INPUT_CHANNEL_NAME);
- displayContent.mTapInputChannel = inputChannel;
- displayContent.mTapDetector =
- new StackTapDetector(this, displayContent, inputChannel, Looper.myLooper());
+ displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
+ registerPointerEventListener(displayContent.mTapDetector);
}
return displayContent;
@@ -10838,10 +10843,9 @@
if (displayContent != null) {
mDisplayContents.delete(displayId);
- if (displayContent.mTapInputChannel != null) {
- displayContent.mTapInputChannel.dispose();
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ unregisterPointerEventListener(displayContent.mTapDetector);
}
-
WindowList windows = displayContent.getWindowList();
while (!windows.isEmpty()) {
final WindowState win = windows.get(windows.size() - 1);