diff options
| -rw-r--r-- | core/java/android/app/ActivityView.java | 26 | ||||
| -rw-r--r-- | core/java/android/app/IActivityContainer.aidl | 2 | ||||
| -rw-r--r-- | core/java/android/hardware/input/InputManagerInternal.java | 3 | ||||
| -rw-r--r-- | libs/input/InputDispatcher.cpp | 190 | ||||
| -rw-r--r-- | libs/input/InputDispatcher.h | 9 | ||||
| -rw-r--r-- | libs/input/tests/InputDispatcher_test.cpp | 39 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityStackSupervisor.java | 29 | ||||
| -rw-r--r-- | services/core/java/com/android/server/input/InputManagerService.java | 16 | ||||
| -rw-r--r-- | services/core/jni/com_android_server_input_InputManagerService.cpp | 8 |
9 files changed, 221 insertions, 101 deletions
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 8acd19beea01..48ec420bb435 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -27,6 +27,9 @@ import android.os.RemoteException; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.TextureView.SurfaceTextureListener; @@ -112,6 +115,29 @@ public class ActivityView extends ViewGroup { } } + private boolean injectInputEvent(InputEvent event) { + try { + return mActivityContainer != null && mActivityContainer.injectEvent(event); + } catch (RemoteException e) { + return false; + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return injectInputEvent(event) || super.onTouchEvent(event); + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { + if (injectInputEvent(event)) { + return true; + } + } + return super.onGenericMotionEvent(event); + } + public boolean isAttachedToDisplay() { return mSurface != null; } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl index abd296a20b9f..5b80e06e1611 100644 --- a/core/java/android/app/IActivityContainer.aidl +++ b/core/java/android/app/IActivityContainer.aidl @@ -20,6 +20,7 @@ import android.app.IActivityContainerCallback; import android.content.Intent; import android.content.IIntentSender; import android.os.IBinder; +import android.view.InputEvent; import android.view.Surface; /** @hide */ @@ -30,4 +31,5 @@ interface IActivityContainer { int startActivity(in Intent intent); int startActivityIntentSender(in IIntentSender intentSender); int getDisplayId(); + boolean injectEvent(in InputEvent event); } diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java index ecd32ea8b41c..8be94d0f7e85 100644 --- a/core/java/android/hardware/input/InputManagerInternal.java +++ b/core/java/android/hardware/input/InputManagerInternal.java @@ -17,6 +17,7 @@ package android.hardware.input; import android.hardware.display.DisplayViewport; +import android.view.InputEvent; /** * Input manager local system service interface. @@ -30,4 +31,6 @@ public abstract class InputManagerInternal { */ public abstract void setDisplayViewports(DisplayViewport defaultViewport, DisplayViewport externalTouchViewport); + + public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode); } diff --git a/libs/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp index 10a639e7aaad..4d447878da4b 100644 --- a/libs/input/InputDispatcher.cpp +++ b/libs/input/InputDispatcher.cpp @@ -1020,7 +1020,14 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout sp<InputWindowHandle> windowHandle = connection->inputWindowHandle; if (windowHandle != NULL) { - mTouchState.removeWindow(windowHandle); + const InputWindowInfo* info = windowHandle->getInfo(); + if (info) { + ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId); + if (stateIndex >= 0) { + mTouchStatesByDisplay.editValueAt(stateIndex).removeWindow( + windowHandle); + } + } } if (connection->status == Connection::STATUS_NORMAL) { @@ -1161,11 +1168,21 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp<InputWindowHandle> newHoverWindowHandle; - bool isSplit = mTouchState.split; - bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0 - && (mTouchState.deviceId != entry->deviceId - || mTouchState.source != entry->source - || mTouchState.displayId != displayId); + // Copy current touch state into mTempTouchState. + // This state is always reset at the end of this function, so if we don't find state + // for the specified display then our initial state will be empty. + const TouchState* oldState = NULL; + ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId); + if (oldStateIndex >= 0) { + oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex); + mTempTouchState.copyFrom(*oldState); + } + + bool isSplit = mTempTouchState.split; + bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 + && (mTempTouchState.deviceId != entry->deviceId + || mTempTouchState.source != entry->source + || mTempTouchState.displayId != displayId); bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); @@ -1175,11 +1192,10 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && mTouchState.down && !down) { + if (switchedDevice && mTempTouchState.down && !down) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down."); #endif - mTempTouchState.copyFrom(mTouchState); injectionResult = INPUT_EVENT_INJECTION_FAILED; switchedDevice = false; wrongDevice = true; @@ -1191,8 +1207,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; isSplit = false; - } else { - mTempTouchState.copyFrom(mTouchState); } if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { @@ -1515,32 +1529,31 @@ Failed: if (isHoverAction) { // Started hovering, therefore no longer down. - if (mTouchState.down) { + if (oldState && oldState->down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Hover received while pointer was down."); #endif *outConflictingPointerActions = true; } - mTouchState.reset(); + mTempTouchState.reset(); if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mTouchState.deviceId = entry->deviceId; - mTouchState.source = entry->source; - mTouchState.displayId = displayId; + mTempTouchState.deviceId = entry->deviceId; + mTempTouchState.source = entry->source; + mTempTouchState.displayId = displayId; } } else if (maskedAction == AMOTION_EVENT_ACTION_UP || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. - mTouchState.reset(); + mTempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. - if (mTouchState.down) { + if (oldState && oldState->down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Down received while already down."); #endif *outConflictingPointerActions = true; } - mTouchState.copyFrom(mTempTouchState); } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. if (isSplit) { @@ -1559,12 +1572,20 @@ Failed: i += 1; } } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - // Discard temporary touch state since it was only valid for this action. - } else { - // Save changes to touch state as-is for all other actions. - mTouchState.copyFrom(mTempTouchState); + } + + // Save changes unless the action was scroll in which case the temporary touch + // state was only valid for this one action. + if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { + if (mTempTouchState.displayId >= 0) { + if (oldStateIndex >= 0) { + mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState); + } else { + mTouchStatesByDisplay.add(displayId, mTempTouchState); + } + } else if (oldStateIndex >= 0) { + mTouchStatesByDisplay.removeItemsAt(oldStateIndex); + } } // Update hover state. @@ -2316,7 +2337,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet originalMotionEntry->yPrecision, originalMotionEntry->downTime, originalMotionEntry->displayId, - splitPointerCount, splitPointerProperties, splitPointerCoords); + splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; @@ -2488,7 +2509,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->action, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, - args->pointerCount, args->pointerProperties, args->pointerCoords); + args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2536,7 +2557,7 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } } -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, +int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS @@ -2587,7 +2608,6 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t displayId = ADISPLAY_ID_DEFAULT; int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); @@ -2610,7 +2630,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry = firstInjectedEntry; for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -2622,7 +2643,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry->next = nextInjectedEntry; lastInjectedEntry = nextInjectedEntry; } @@ -2847,22 +2869,25 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inpu mFocusedWindowHandle = newFocusedWindowHandle; } - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { + for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { + TouchState& state = mTouchStatesByDisplay.editValueAt(d); + for (size_t i = 0; i < state.windows.size(); i++) { + TouchedWindow& touchedWindow = state.windows.editItemAt(i); + if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS - ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().string()); + ALOGD("Touched window was removed: %s", + touchedWindow.windowHandle->getName().string()); #endif - sp<InputChannel> touchedInputChannel = - touchedWindow.windowHandle->getInputChannel(); - if (touchedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); + sp<InputChannel> touchedInputChannel = + touchedWindow.windowHandle->getInputChannel(); + if (touchedInputChannel != NULL) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "touched window was removed"); + synthesizeCancelationEventsForInputChannelLocked( + touchedInputChannel, options); + } + state.windows.removeAt(i--); } - mTouchState.windows.removeAt(i--); } } @@ -3003,23 +3028,27 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, } bool found = false; - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.windowHandle == fromWindowHandle) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - mTouchState.windows.removeAt(i); - - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); - mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); - - found = true; - break; + for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { + TouchState& state = mTouchStatesByDisplay.editValueAt(d); + for (size_t i = 0; i < state.windows.size(); i++) { + const TouchedWindow& touchedWindow = state.windows[i]; + if (touchedWindow.windowHandle == fromWindowHandle) { + int32_t oldTargetFlags = touchedWindow.targetFlags; + BitSet32 pointerIds = touchedWindow.pointerIds; + + state.windows.removeAt(i); + + int32_t newTargetFlags = oldTargetFlags + & (InputTarget::FLAG_FOREGROUND + | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); + state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); + + found = true; + goto Found; + } } } +Found: if (! found) { #if DEBUG_FOCUS @@ -3063,7 +3092,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { drainInboundQueueLocked(); resetANRTimeoutsLocked(); - mTouchState.reset(); + mTouchStatesByDisplay.clear(); mLastHoverWindowHandle.clear(); } @@ -3098,22 +3127,28 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>"); - dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); - dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); - dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId); - dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source); - dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId); - if (!mTouchState.windows.isEmpty()) { - dump.append(INDENT "TouchedWindows:\n"); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().string(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); + if (!mTouchStatesByDisplay.isEmpty()) { + dump.appendFormat(INDENT "TouchStatesByDisplay:\n"); + for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { + const TouchState& state = mTouchStatesByDisplay.valueAt(i); + dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", + state.displayId, toString(state.down), toString(state.split), + state.deviceId, state.source); + if (!state.windows.isEmpty()) { + dump.append(INDENT3 "Windows:\n"); + for (size_t i = 0; i < state.windows.size(); i++) { + const TouchedWindow& touchedWindow = state.windows[i]; + dump.appendFormat(INDENT4 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.windowHandle->getName().string(), + touchedWindow.pointerIds.value, + touchedWindow.targetFlags); + } + } else { + dump.append(INDENT3 "Windows: <none>\n"); + } } } else { - dump.append(INDENT "TouchedWindows: <none>\n"); + dump.append(INDENT "TouchStates: <no displays touched>\n"); } if (!mWindowHandles.isEmpty()) { @@ -3898,7 +3933,8 @@ InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset) : EventEntry(TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), deviceId(deviceId), source(source), action(action), flags(flags), @@ -3908,6 +3944,9 @@ InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); + if (xOffset || yOffset) { + this->pointerCoords[i].applyOffset(xOffset, yOffset); + } } } @@ -4201,7 +4240,8 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim memento.flags, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.displayId, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); + memento.pointerCount, memento.pointerProperties, memento.pointerCoords, + 0, 0)); } } } diff --git a/libs/input/InputDispatcher.h b/libs/input/InputDispatcher.h index 190e7b221058..29854b2d56e4 100644 --- a/libs/input/InputDispatcher.h +++ b/libs/input/InputDispatcher.h @@ -297,7 +297,7 @@ public: * * This method may be called on any thread (usually by the input manager). */ - virtual int32_t injectInputEvent(const InputEvent* event, + virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; @@ -381,7 +381,7 @@ public: virtual void notifySwitch(const NotifySwitchArgs* args); virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - virtual int32_t injectInputEvent(const InputEvent* event, + virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags); @@ -525,7 +525,8 @@ private: int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); virtual void appendDescription(String8& msg) const; protected: @@ -959,7 +960,7 @@ private: bool isSlippery() const; }; - TouchState mTouchState; + KeyedVector<int32_t, TouchState> mTouchStatesByDisplay; TouchState mTempTouchState; // Focused application. diff --git a/libs/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp index 26b4fab794d8..fc89a9b18905 100644 --- a/libs/input/tests/InputDispatcher_test.cpp +++ b/libs/input/tests/InputDispatcher_test.cpp @@ -27,6 +27,9 @@ static const nsecs_t ARBITRARY_TIME = 1234; // An arbitrary device id. static const int32_t DEVICE_ID = 1; +// An arbitrary display id. +static const int32_t DISPLAY_ID = 0; + // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; static const int32_t INJECTOR_UID = 1001; @@ -126,7 +129,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject key events with undefined action."; @@ -134,7 +138,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject key events with ACTION_MULTIPLE."; } @@ -154,7 +159,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with undefined action."; @@ -164,7 +170,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; @@ -173,7 +180,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too small."; @@ -183,7 +191,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; @@ -192,7 +201,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too small."; @@ -201,7 +211,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; @@ -209,7 +220,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with more than MAX_POINTERS pointers."; @@ -219,7 +231,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids less than 0."; @@ -228,7 +241,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; @@ -239,7 +253,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( + &event, DISPLAY_ID, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with duplicate pointer ids."; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f609e7e6dfca..b99823f51290 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -61,6 +61,8 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.VirtualDisplay; +import android.hardware.input.InputManager; +import android.hardware.input.InputManagerInternal; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -81,9 +83,11 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayInfo; +import android.view.InputEvent; import android.view.Surface; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.os.TransferPipe; +import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.PendingActivityLaunch; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.wm.WindowManagerService; @@ -225,6 +229,8 @@ public final class ActivityStackSupervisor implements DisplayListener { /** Mapping from displayId to display current state */ private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>(); + InputManagerInternal mInputManagerInternal; + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); @@ -255,6 +261,8 @@ public final class ActivityStackSupervisor implements DisplayListener { createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); + + mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } } @@ -2940,7 +2948,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void attachToDisplay(int displayId) throws RemoteException { + public void attachToDisplay(int displayId) { synchronized (mService) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay == null) { @@ -2951,13 +2959,28 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public int getDisplayId() throws RemoteException { + public int getDisplayId() { if (mActivityDisplay != null) { return mActivityDisplay.mDisplayId; } return -1; } + @Override + public boolean injectEvent(InputEvent event) { + final long origId = Binder.clearCallingIdentity(); + try { + if (mActivityDisplay != null) { + return mInputManagerInternal.injectInputEvent(event, + mActivityDisplay.mDisplayId, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + } + return false; + } finally { + Binder.restoreCallingIdentity(origId); + } + } + private void detachLocked() { if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); @@ -2971,7 +2994,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void detachFromDisplay() throws RemoteException { + public void detachFromDisplay() { synchronized (mService) { detachLocked(); } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index fa18149112bd..69281bc3a3f9 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -16,6 +16,7 @@ package com.android.server.input; +import android.view.Display; import com.android.internal.R; import com.android.internal.util.XmlUtils; import com.android.server.DisplayThread; @@ -169,7 +170,7 @@ public class InputManagerService extends IInputManager.Stub InputWindowHandle inputWindowHandle, boolean monitor); private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); - private static native int nativeInjectInputEvent(long ptr, InputEvent event, + private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); @@ -508,6 +509,10 @@ public class InputManagerService extends IInputManager.Stub @Override // Binder call public boolean injectInputEvent(InputEvent event, int mode) { + return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); + } + + private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } @@ -522,7 +527,7 @@ public class InputManagerService extends IInputManager.Stub final long ident = Binder.clearCallingIdentity(); final int result; try { - result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, + result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); } finally { Binder.restoreCallingIdentity(ident); @@ -1552,7 +1557,7 @@ public class InputManagerService extends IInputManager.Stub synchronized (mInputFilterLock) { if (!mDisconnected) { - nativeInjectInputEvent(mPtr, event, 0, 0, + nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, policyFlags | WindowManagerPolicy.FLAG_FILTERED); } @@ -1649,5 +1654,10 @@ public class InputManagerService extends IInputManager.Stub DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { setDisplayViewportsInternal(defaultViewport, externalTouchViewport); } + + @Override + public boolean injectInputEvent(InputEvent event, int displayId, int mode) { + return injectInputEventInternal(event, displayId, mode); + } } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 10ad278a8e10..0542ce012130 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1143,7 +1143,7 @@ static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz, } static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, - jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid, + jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid, jint syncMode, jint timeoutMillis, jint policyFlags) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1156,7 +1156,7 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( - & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); @@ -1166,7 +1166,7 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( - motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else { jniThrowRuntimeException(env, "Invalid input event type."); @@ -1326,7 +1326,7 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) nativeUnregisterInputChannel }, { "nativeSetInputFilterEnabled", "(JZ)V", (void*) nativeSetInputFilterEnabled }, - { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I", + { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I", (void*) nativeInjectInputEvent }, { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V", (void*) nativeSetInputWindows }, |