From 56194ebec6212e229f4ccdaa4b187166d20013ef Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 2 Mar 2011 19:23:13 -0800 Subject: [PATCH] Wake screen from external HID peripherals. Added some plumbing to enable the policy to intercept motion events when the screen is off to handle wakeup if needed. Added a basic concept of an external device to limit the scope of the wakeup policy to external devices only. The wakeup policy for internal devices should be based on explicit rules such as policy flags in key layout files. Moved isTouchEvent to native. Ensure the dispatcher sends the right event type to userActivity for non-touch pointer events like HOVER_MOVE and SCROLL. Bug: 3193114 Change-Id: I15dbd48a16810dfaf226ff7ad117d46908ca4f86 --- core/java/android/view/MotionEvent.java | 15 +--- .../android/view/WindowManagerPolicy.java | 16 ++++- core/jni/android_view_MotionEvent.cpp | 9 +++ include/ui/Input.h | 5 ++ libs/ui/Input.cpp | 17 +++++ .../policy/impl/KeyguardViewBase.java | 3 +- .../policy/impl/KeyguardViewManager.java | 3 +- .../policy/impl/KeyguardViewMediator.java | 22 ++++++ .../policy/impl/PhoneWindowManager.java | 19 +++++ services/input/EventHub.cpp | 16 +++++ services/input/EventHub.h | 5 ++ services/input/InputDispatcher.cpp | 9 +-- services/input/InputDispatcher.h | 4 +- services/input/InputReader.cpp | 52 ++++++++++++-- services/input/InputReader.h | 4 ++ services/input/tests/InputDispatcher_test.cpp | 2 +- services/input/tests/InputReader_test.cpp | 6 ++ .../com/android/server/wm/InputManager.java | 8 ++- .../com/android/server/wm/InputMonitor.java | 9 ++- .../jni/com_android_server_InputManager.cpp | 69 ++++++++++++++----- 20 files changed, 244 insertions(+), 49 deletions(-) diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index a26dd0425b690..076f71298490a 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -937,6 +937,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native int nativeSetSource(int nativePtr, int source); private static native int nativeGetAction(int nativePtr); private static native void nativeSetAction(int nativePtr, int action); + private static native boolean nativeIsTouchEvent(int nativePtr); private static native int nativeGetFlags(int nativePtr); private static native int nativeGetEdgeFlags(int nativePtr); private static native void nativeSetEdgeFlags(int nativePtr, int action); @@ -1275,19 +1276,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @hide */ public final boolean isTouchEvent() { - if ((getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - switch (getActionMasked()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_OUTSIDE: - return true; - } - } - return false; + return nativeIsTouchEvent(mNativePtr); } /** diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index be68cb9e4a449..334c68e9c06a2 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -573,7 +573,21 @@ public interface WindowManagerPolicy { * {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags. */ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); - + + /** + * Called from the input reader thread before a motion is enqueued when the screen is off. + * + *

There are some actions that need to be handled here because they + * affect the power state of the device, for example, waking on motions. + * Generally, it's best to keep as little as possible in the queue thread + * because it's the most fragile. + * @param policyFlags The policy flags associated with the motion. + * + * @return The bitwise or of the {@link #ACTION_PASS_TO_USER}, + * {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags. + */ + public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); + /** * Called from the input dispatcher thread before a key is dispatched to a window. * diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index b01400628f192..97cba23f84eac 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -429,6 +429,12 @@ static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz, event->setAction(action); } +static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz, + jint nativePtr) { + MotionEvent* event = reinterpret_cast(nativePtr); + return event->isTouchEvent(); +} + static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz, jint nativePtr) { MotionEvent* event = reinterpret_cast(nativePtr); @@ -661,6 +667,9 @@ static JNINativeMethod gMotionEventMethods[] = { { "nativeSetAction", "(II)V", (void*)android_view_MotionEvent_nativeSetAction }, + { "nativeIsTouchEvent", + "(I)Z", + (void*)android_view_MotionEvent_nativeIsTouchEvent }, { "nativeGetFlags", "(I)I", (void*)android_view_MotionEvent_nativeGetFlags }, diff --git a/include/ui/Input.h b/include/ui/Input.h index 082f11c655382..e92d7f5fc25de 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -476,6 +476,11 @@ public: status_t writeToParcel(Parcel* parcel) const; #endif + static bool isTouchEvent(int32_t source, int32_t action); + inline bool isTouchEvent() const { + return isTouchEvent(mSource, mAction); + } + // Low-level accessors. inline const int32_t* getPointerIds() const { return mPointerIds.array(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index a80320e475ebb..0ed086662c57e 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -616,6 +616,23 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { } #endif +bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { + if (source & AINPUT_SOURCE_CLASS_POINTER) { + // Specifically excludes HOVER_MOVE and SCROLL. + switch (action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_OUTSIDE: + return true; + } + } + return false; +} + // --- InputDeviceInfo --- diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java index 36afd750c5283..74dde9c93f5d2 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java @@ -108,7 +108,8 @@ public abstract class KeyguardViewBase extends FrameLayout { * action should be posted to a handler. * * @param keyCode The wake key, which may be relevant for configuring the - * keyguard. + * keyguard. May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking for a reason + * other than a key press. */ abstract public void wakeWhenReadyTq(int keyCode); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java index edab69085f077..8d70a7b8cd8ce 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java @@ -201,7 +201,8 @@ public class KeyguardViewManager implements KeyguardWindowController { * Be sure not to take any action that takes a long time; any significant * action should be posted to a handler. * - * @param keyCode The wake key. + * @param keyCode The wake key. May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking + * for a reason other than a key press. */ public boolean wakeWhenReadyTq(int keyCode) { if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")"); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index b32a729701512..e7a9eb1dec21c 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -809,6 +809,28 @@ public class KeyguardViewMediator implements KeyguardViewCallback, return true; } + /** + * When a wake motion such as an external mouse movement is received when the screen + * is off and the keyguard is showing, we need to decide whether to actually turn + * on the screen, and if so, tell the keyguard to prepare itself and poke the wake + * lock when it is ready. + * + * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. + * Be sure not to take any action that takes a long time; any significant + * action should be posted to a handler. + * + * @return Whether we poked the wake lock (and turned the screen on) + */ + public boolean onWakeMotionWhenKeyguardShowingTq() { + if (DEBUG) Log.d(TAG, "onWakeMotionWhenKeyguardShowing()"); + + // give the keyguard view manager a chance to adjust the state of the + // keyguard based on the key that woke the device before poking + // the wake lock + wakeWhenReadyLocked(KeyEvent.KEYCODE_UNKNOWN); + return true; + } + /** * Callbacks from {@link KeyguardViewManager}. */ diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 75ef7629b0763..8e18f2a1040ec 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2364,6 +2364,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { return result; } + /** {@inheritDoc} */ + @Override + public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { + int result = 0; + + final boolean isWakeMotion = (policyFlags + & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + if (isWakeMotion) { + if (mKeyguardMediator.isShowing()) { + // If the keyguard is showing, let it decide what to do with the wake motion. + mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq(); + } else { + // Otherwise, wake the device ourselves. + result |= ACTION_POKE_USER_ACTIVITY; + } + } + return result; + } + class PassHeadsetKey implements Runnable { KeyEvent mKeyEvent; diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 25db25e6773e4..2fe5980068b5b 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -933,6 +933,11 @@ int EventHub::openDevice(const char *devicePath) { return -1; } + // Determine whether the device is external or internal. + if (isExternalDevice(device)) { + device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; + } + LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s", deviceId, fd, devicePath, device->identifier.name.string(), @@ -997,6 +1002,17 @@ void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) { android::clearKeyboardProperties(id); } +bool EventHub::isExternalDevice(Device* device) { + if (device->configuration) { + bool value; + if (device->configuration->tryGetProperty(String8("device.internal"), value) + && value) { + return false; + } + } + return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; +} + bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; diff --git a/services/input/EventHub.h b/services/input/EventHub.h index f7936d255b080..445c04b187c96 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -126,6 +126,9 @@ enum { /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, + + /* The input device is external (not built-in). */ + INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, }; /* @@ -304,6 +307,8 @@ private: void setKeyboardProperties(Device* device, bool builtInKeyboard); void clearKeyboardProperties(Device* device, bool builtInKeyboard); + bool isExternalDevice(Device* device); + // Protect all internal state. mutable Mutex mLock; diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index c064a9ceb1575..655b67217edf8 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -1572,7 +1572,7 @@ String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* } void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { - int32_t eventType = POWER_MANAGER_BUTTON_EVENT; + int32_t eventType = POWER_MANAGER_OTHER_EVENT; switch (eventEntry->type) { case EventEntry::TYPE_MOTION: { const MotionEntry* motionEntry = static_cast(eventEntry); @@ -1580,7 +1580,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { return; } - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { eventType = POWER_MANAGER_TOUCH_EVENT; } break; @@ -1590,6 +1590,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { return; } + eventType = POWER_MANAGER_BUTTON_EVENT; break; } } @@ -2304,7 +2305,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t } policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); + mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); bool needWake; { // acquire lock @@ -2498,7 +2499,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, } nsecs_t eventTime = motionEvent->getEventTime(); - mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); + mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 304b1bbd92d5f..1e118c4d28919 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -165,14 +165,14 @@ public: */ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; - /* Intercepts a generic touch, trackball or other event before queueing it. + /* Intercepts a touch, trackball or other motion event before queueing it. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. * * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ - virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; + virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ virtual bool interceptKeyBeforeDispatching(const sp& inputWindowHandle, diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index c3c143c89c2d9..b92c3b57d6b23 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -233,6 +233,11 @@ void InputReader::removeDevice(int32_t deviceId) { InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) { InputDevice* device = new InputDevice(this, deviceId, name); + // External devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { + device->setExternal(true); + } + // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); @@ -565,7 +570,7 @@ bool InputReaderThread::threadLoop() { // --- InputDevice --- InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) : - mContext(context), mId(id), mName(name), mSources(0) { + mContext(context), mId(id), mName(name), mSources(0), mIsExternal(false) { } InputDevice::~InputDevice() { @@ -582,6 +587,7 @@ void InputDevice::dump(String8& dump) { dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getName().string()); + dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -985,6 +991,16 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, downTime = mLocked.downTime; } // release lock + // Key down on external an keyboard should wake the device. + // We don't do this for internal keyboards to prevent them from waking up in your pocket. + // For internal keyboards, the key layout file should specify the policy flags for + // each wake key individually. + // TODO: Use the input device configuration to control this behavior more finely. + if (down && getDevice()->isExternal() + && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { + policyFlags |= POLICY_FLAG_WAKE_DROPPED; + } + if (metaStateChanged) { getContext()->updateGlobalMetaState(); } @@ -1379,9 +1395,18 @@ void CursorInputMapper::sync(nsecs_t when) { } } // release lock + // Moving an external trackball or mouse should wake the device. + // We don't do this for internal cursor devices to prevent them from waking up + // the device in your pocket. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + if (getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE_DROPPED; + } + int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; - getDispatcher()->notifyMotion(when, getDeviceId(), mSources, 0, + getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); @@ -1391,7 +1416,7 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - getDispatcher()->notifyMotion(when, getDeviceId(), mSources, 0, + getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); } @@ -2308,8 +2333,6 @@ void TouchInputMapper::reset() { } void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { - uint32_t policyFlags = 0; - // Preprocess pointer data. if (mParameters.useBadTouchFilter) { if (applyBadTouchFilter()) { @@ -2338,9 +2361,18 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { savedTouch = & mCurrentTouch; } - // Hide the pointer on an initial down. + uint32_t policyFlags = 0; if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { + // Hide the pointer on an initial down. getContext()->fadePointer(); + + // Initial downs on external touch devices should wake the device. + // We don't do this for internal touch screens to prevent them from waking + // up in your pocket. + // TODO: Use the input device configuration to control this behavior more finely. + if (getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE_DROPPED; + } } // Process touches and virtual keys. @@ -4017,8 +4049,14 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { axis.oldValue = axis.newValue; } + // Moving a joystick axis should not wake the devide because joysticks can + // be fairly noisy even when not in use. On the other hand, pushing a gamepad + // button will likely wake the device. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + int32_t pointerId = 0; - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, 0, + getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, 0, 0, 0); } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index b344ffe1005f4..655f0f04a79d9 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -286,6 +286,9 @@ public: inline const String8& getName() { return mName; } inline uint32_t getSources() { return mSources; } + inline bool isExternal() { return mIsExternal; } + inline void setExternal(bool external) { mIsExternal = external; } + inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); @@ -317,6 +320,7 @@ private: String8 mName; uint32_t mSources; + bool mIsExternal; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index 5ba18671441eb..bb3449b576ded 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -58,7 +58,7 @@ private: virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { } - virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { + virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { } virtual bool interceptKeyBeforeDispatching(const sp& inputWindowHandle, diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 864241e56dbbf..8404b3ac55528 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -188,6 +188,8 @@ private: class FakeInputDispatcher : public InputDispatcherInterface { public: struct NotifyConfigurationChangedArgs { + NotifyConfigurationChangedArgs() : eventTime(0) { } + nsecs_t eventTime; }; @@ -687,6 +689,10 @@ private: } } + virtual bool isExternal(int32_t deviceId) const { + return false; + } + virtual void dump(String8& dump) { } }; diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index 326eca73f5e6c..77cec5d737ec2 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -448,7 +448,13 @@ public class InputManager { return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing( event, policyFlags, isScreenOn); } - + + @SuppressWarnings("unused") + public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { + return mWindowManagerService.mInputMonitor.interceptMotionBeforeQueueingWhenScreenOff( + policyFlags); + } + @SuppressWarnings("unused") public boolean interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags) { diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index b1833c45d9f32..45a78af37af36 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -258,7 +258,14 @@ final class InputMonitor { KeyEvent event, int policyFlags, boolean isScreenOn) { return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn); } - + + /* Provides an opportunity for the window manager policy to intercept early + * motion event processing when the screen is off since these events are normally + * dropped. */ + public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { + return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + } + /* Provides an opportunity for the window manager policy to process a key before * ordinary dispatch. */ public boolean interceptKeyBeforeDispatching( diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 5ef234a89db75..00d0af1c0f374 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -59,6 +59,7 @@ static struct { jmethodID notifyInputChannelBroken; jmethodID notifyANR; jmethodID interceptKeyBeforeQueueing; + jmethodID interceptMotionBeforeQueueingWhenScreenOff; jmethodID interceptKeyBeforeDispatching; jmethodID dispatchUnhandledKey; jmethodID checkInjectEventsPermission; @@ -178,7 +179,7 @@ public: virtual nsecs_t getKeyRepeatDelay(); virtual int32_t getMaxEventsPerSecond(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); - virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags); + virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual bool interceptKeyBeforeDispatching(const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags); virtual bool dispatchUnhandledKey(const sp& inputWindowHandle, @@ -215,6 +216,7 @@ private: } mLocked; void updateInactivityFadeDelayLocked(const sp& controller); + void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); // Power manager interactions. bool isScreenOn(); @@ -620,10 +622,6 @@ void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, // - Ask the window manager what to do with normal events and trusted injected events. // - For normal events wake and brighten the screen if currently off or dim. if ((policyFlags & POLICY_FLAG_TRUSTED)) { - const int32_t WM_ACTION_PASS_TO_USER = 1; - const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; - const int32_t WM_ACTION_GO_TO_SLEEP = 4; - nsecs_t when = keyEvent->getEventTime(); bool isScreenOn = this->isScreenOn(); bool isScreenBright = this->isScreenBright(); @@ -655,23 +653,13 @@ void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, } } - if (wmActions & WM_ACTION_GO_TO_SLEEP) { - android_server_PowerManagerService_goToSleep(when); - } - - if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { - android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); - } - - if (wmActions & WM_ACTION_PASS_TO_USER) { - policyFlags |= POLICY_FLAG_PASS_TO_USER; - } + handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } else { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } -void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { +void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { // Policy: // - Ignore untrusted events and pass them along. // - No special filtering for injected events required at this time. @@ -684,12 +672,55 @@ void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& if (!isScreenBright()) { policyFlags |= POLICY_FLAG_BRIGHT_HERE; } + } else { + JNIEnv* env = jniEnv(); + jint wmActions = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff, + policyFlags); + if (checkAndClearExceptionFromCallback(env, + "interceptMotionBeforeQueueingWhenScreenOff")) { + wmActions = 0; + } + + policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE; + handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } } else { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } +void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, + uint32_t& policyFlags) { + enum { + WM_ACTION_PASS_TO_USER = 1, + WM_ACTION_POKE_USER_ACTIVITY = 2, + WM_ACTION_GO_TO_SLEEP = 4, + }; + + if (wmActions & WM_ACTION_GO_TO_SLEEP) { +#ifdef DEBUG_INPUT_DISPATCHER_POLICY + LOGD("handleInterceptActions: Going to sleep."); +#endif + android_server_PowerManagerService_goToSleep(when); + } + + if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { +#ifdef DEBUG_INPUT_DISPATCHER_POLICY + LOGD("handleInterceptActions: Poking user activity."); +#endif + android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); + } + + if (wmActions & WM_ACTION_PASS_TO_USER) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + } else { +#ifdef DEBUG_INPUT_DISPATCHER_POLICY + LOGD("handleInterceptActions: Not passing key to user."); +#endif + } +} + bool NativeInputManager::interceptKeyBeforeDispatching( const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { @@ -1204,6 +1235,10 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I"); + GET_METHOD_ID(gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff, + gCallbacksClassInfo.clazz, + "interceptMotionBeforeQueueingWhenScreenOff", "(I)I"); + GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, "interceptKeyBeforeDispatching", "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Z");