am 38f96e50: Add support for injecting events into ActivityContainers. (DO NOT MERGE)

* commit '38f96e5020b3e82b98fe97b0be363a5ad185860f':
  Add support for injecting events into ActivityContainers. (DO NOT MERGE)
This commit is contained in:
Jeff Brown
2014-02-12 00:37:24 +00:00
committed by Android Git Automerger
9 changed files with 218 additions and 98 deletions

View File

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

View File

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

View File

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

View File

@@ -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;
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;
mTouchState.windows.removeAt(i);
state.windows.removeAt(i);
int32_t newTargetFlags = oldTargetFlags
& (InputTarget::FLAG_FOREGROUND
| InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
int32_t newTargetFlags = oldTargetFlags
& (InputTarget::FLAG_FOREGROUND
| InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
found = true;
break;
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));
}
}
}

View File

@@ -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.

View File

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

View File

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

View File

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

View File

@@ -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 },