diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/input/EventHub.cpp | 5 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 106 | ||||
-rw-r--r-- | services/input/InputReader.h | 32 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 97 | ||||
-rw-r--r-- | services/java/com/android/server/input/InputManagerService.java | 183 | ||||
-rw-r--r-- | services/jni/com_android_server_input_InputManagerService.cpp | 78 |
6 files changed, 350 insertions, 151 deletions
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 2ba821e..fbffc94 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -720,6 +720,11 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz break; } } + } else if (eventItem.events & EPOLLHUP) { + ALOGI("Removing device %s due to epoll hang-up event.", + device->identifier.name.string()); + deviceChanged = true; + closeDeviceLocked(device); } else { ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, device->identifier.name.string()); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index ea614ad..71eba52 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -237,7 +237,8 @@ InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), - mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), + mGlobalMetaState(0), mGeneration(1), + mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); @@ -257,18 +258,24 @@ InputReader::~InputReader() { } void InputReader::loopOnce() { + int32_t oldGeneration; int32_t timeoutMillis; + bool inputDevicesChanged = false; + Vector<InputDeviceInfo> inputDevices; { // acquire lock AutoMutex _l(mLock); + oldGeneration = mGeneration; + timeoutMillis = -1; + uint32_t changes = mConfigurationChangesToRefresh; if (changes) { mConfigurationChangesToRefresh = 0; + timeoutMillis = 0; refreshConfigurationLocked(changes); } - timeoutMillis = -1; - if (mNextTimeout != LLONG_MAX) { + if (timeoutMillis < 0 && mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } @@ -283,7 +290,8 @@ void InputReader::loopOnce() { if (count) { processEventsLocked(mEventBuffer, count); } - if (!count || timeoutMillis == 0) { + + if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { #if DEBUG_RAW_EVENTS @@ -293,8 +301,18 @@ void InputReader::loopOnce() { timeoutExpiredLocked(now); } } + + if (oldGeneration != mGeneration) { + inputDevicesChanged = true; + getInputDevicesLocked(inputDevices); + } } // release lock + // Send out a message that the describes the changed input devices. + if (inputDevicesChanged) { + mPolicy->notifyInputDevicesChanged(inputDevices); + } + // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked @@ -344,6 +362,12 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { } void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); + return; + } + InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); @@ -359,27 +383,22 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { identifier.name.string(), device->getSources()); } - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - mDevices.add(deviceId, device); - } else { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - delete device; - return; - } + mDevices.add(deviceId, device); + bumpGenerationLocked(); } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { InputDevice* device = NULL; ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - } else { + if (deviceIndex < 0) { ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); return; } + device = mDevices.valueAt(deviceIndex); + mDevices.removeItemsAt(deviceIndex, 1); + bumpGenerationLocked(); + if (device->isIgnored()) { ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), device->getName().string()); @@ -394,7 +413,8 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { InputDevice* InputReader::createDeviceLocked(int32_t deviceId, const InputDeviceIdentifier& identifier, uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, identifier, classes); + InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), + identifier, classes); // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { @@ -577,39 +597,30 @@ void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { } } +int32_t InputReader::bumpGenerationLocked() { + return ++mGeneration; +} + void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) { AutoMutex _l(mLock); *outConfiguration = mInputConfiguration; } -status_t InputReader::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) { +void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) { AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - return NAME_NOT_FOUND; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - return NAME_NOT_FOUND; - } - - device->getDeviceInfo(outDeviceInfo); - return OK; + getInputDevicesLocked(outInputDevices); } -void InputReader::getInputDeviceIds(Vector<int32_t>& outDeviceIds) { - AutoMutex _l(mLock); - - outDeviceIds.clear(); +void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) { + outInputDevices.clear(); size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (!device->isIgnored()) { - outDeviceIds.add(device->getId()); + outInputDevices.push(); + device->getDeviceInfo(&outInputDevices.editTop()); } } } @@ -824,6 +835,11 @@ void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { mReader->requestTimeoutAtTimeLocked(when); } +int32_t InputReader::ContextImpl::bumpGeneration() { + // lock is already held by the input loop + return mReader->bumpGenerationLocked(); +} + InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } @@ -854,9 +870,10 @@ bool InputReaderThread::threadLoop() { // --- InputDevice --- -InputDevice::InputDevice(InputReaderContext* context, int32_t id, +InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, uint32_t classes) : - mContext(context), mId(id), mIdentifier(identifier), mClasses(classes), + mContext(context), mId(id), mGeneration(generation), + mIdentifier(identifier), mClasses(classes), mSources(0), mIsExternal(false), mDropUntilNextSync(false) { } @@ -874,6 +891,7 @@ void InputDevice::dump(String8& dump) { dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getName().string()); + dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); 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()); @@ -983,7 +1001,7 @@ void InputDevice::timeoutExpired(nsecs_t when) { } void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mIdentifier.name, mIdentifier.descriptor); + outDeviceInfo->initialize(mId, mGeneration, mIdentifier.name, mIdentifier.descriptor); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { @@ -1054,6 +1072,10 @@ void InputDevice::fadePointer() { } } +void InputDevice::bumpGeneration() { + mGeneration = mContext->bumpGeneration(); +} + void InputDevice::notifyReset(nsecs_t when) { NotifyDeviceResetArgs args(when, mId); mContext->getListener()->notifyDeviceReset(&args); @@ -1728,6 +1750,10 @@ status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axi return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); } +void InputMapper::bumpGeneration() { + mDevice->bumpGeneration(); +} + void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name) { if (axis.valid) { @@ -2137,6 +2163,7 @@ void CursorInputMapper::configure(nsecs_t when, } else { mOrientation = DISPLAY_ORIENTATION_0; } + bumpGeneration(); } } @@ -2998,6 +3025,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { // Inform the dispatcher about the changes. *outResetNeeded = true; + bumpGeneration(); } } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 8ab5905..d29776d 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -209,6 +209,11 @@ public: /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; + + /* Notifies the input reader policy that some input devices have changed + * and provides information about all current input devices. + */ + virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0; }; @@ -240,16 +245,11 @@ public: */ virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 0; - /* Gets information about the specified input device. - * Returns OK if the device information was obtained or NAME_NOT_FOUND if there - * was no such device. + /* Gets information about all input devices. * * This method may be called on any thread (usually by the input manager). */ - virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) = 0; - - /* Gets the list of all registered device ids. */ - virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds) = 0; + virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0; /* Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, @@ -288,6 +288,7 @@ public: virtual void fadePointer() = 0; virtual void requestTimeoutAtTime(nsecs_t when) = 0; + virtual int32_t bumpGeneration() = 0; virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; @@ -319,9 +320,7 @@ public: virtual void loopOnce(); virtual void getInputConfiguration(InputConfiguration* outConfiguration); - - virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo); - virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds); + virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices); virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); @@ -353,6 +352,7 @@ protected: InputDevice* device, int32_t keyCode, int32_t scanCode); virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); + virtual int32_t bumpGeneration(); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); @@ -393,9 +393,14 @@ private: void fadePointerLocked(); + int32_t mGeneration; + int32_t bumpGenerationLocked(); + InputConfiguration mInputConfiguration; void updateInputConfigurationLocked(); + void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices); + nsecs_t mDisableVirtualKeysTimeout; void disableVirtualKeysUntilLocked(nsecs_t time); bool shouldDropVirtualKeyLocked(nsecs_t now, @@ -432,12 +437,13 @@ private: /* Represents the state of a single input device. */ class InputDevice { public: - InputDevice(InputReaderContext* context, int32_t id, + InputDevice(InputReaderContext* context, int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, uint32_t classes); ~InputDevice(); inline InputReaderContext* getContext() { return mContext; } inline int32_t getId() { return mId; } + inline int32_t getGeneration() { return mGeneration; } inline const String8& getName() { return mIdentifier.name; } inline uint32_t getClasses() { return mClasses; } inline uint32_t getSources() { return mSources; } @@ -465,6 +471,8 @@ public: void fadePointer(); + void bumpGeneration(); + void notifyReset(nsecs_t when); inline const PropertyMap& getConfiguration() { return mConfiguration; } @@ -487,6 +495,7 @@ public: private: InputReaderContext* mContext; int32_t mId; + int32_t mGeneration; InputDeviceIdentifier mIdentifier; uint32_t mClasses; @@ -849,6 +858,7 @@ protected: InputReaderContext* mContext; status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); + void bumpGeneration(); static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index eac9a1c..e59af4e 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -127,6 +127,7 @@ private: class FakeInputReaderPolicy : public InputReaderPolicyInterface { InputReaderConfiguration mConfig; KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; + Vector<InputDeviceInfo> mInputDevices; protected: virtual ~FakeInputReaderPolicy() { } @@ -141,10 +142,6 @@ public: mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation); } - virtual nsecs_t getVirtualKeyQuietTime() { - return 0; - } - void addExcludedDeviceName(const String8& deviceName) { mConfig.excludedDeviceNames.push(deviceName); } @@ -157,6 +154,10 @@ public: return &mConfig; } + const Vector<InputDeviceInfo>& getInputDevices() const { + return mInputDevices; + } + private: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; @@ -165,6 +166,10 @@ private: virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { return mPointerControllers.valueFor(deviceId); } + + virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) { + mInputDevices = inputDevices; + } }; @@ -667,6 +672,7 @@ class FakeInputReaderContext : public InputReaderContext { sp<InputListenerInterface> mListener; int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; + int32_t mGeneration; public: FakeInputReaderContext(const sp<EventHubInterface>& eventHub, @@ -722,6 +728,10 @@ private: virtual void requestTimeoutAtTime(nsecs_t when) { } + + virtual int32_t bumpGeneration() { + return ++mGeneration; + } }; @@ -887,7 +897,8 @@ public: InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) { InputDeviceIdentifier identifier; identifier.name = name; - return new InputDevice(&mContext, deviceId, identifier, classes); + int32_t generation = deviceId + 1; + return new InputDevice(&mContext, deviceId, generation, identifier, classes); } protected: @@ -1045,52 +1056,30 @@ TEST_F(InputReaderTest, GetInputConfiguration_WhenDPadPresent_ReturnsDPadNavigat ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen); } -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsValid) { +TEST_F(InputReaderTest, GetInputDevices) { ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), INPUT_DEVICE_CLASS_KEYBOARD, NULL)); - - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(1, &info); - - ASSERT_EQ(OK, result); - ASSERT_EQ(1, info.getId()); - ASSERT_STREQ("keyboard", info.getName().string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, info.getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, info.getSources()); - ASSERT_EQ(size_t(0), info.getMotionRanges().size()); -} - -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsInvalid) { - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(-1, &info); - - ASSERT_EQ(NAME_NOT_FOUND, result); -} - -TEST_F(InputReaderTest, GetInputDeviceInfo_WhenDeviceIdIsIgnored) { - addDevice(1, String8("ignored"), 0, NULL); // no classes so device will be ignored - - InputDeviceInfo info; - status_t result = mReader->getInputDeviceInfo(1, &info); - - ASSERT_EQ(NAME_NOT_FOUND, result); -} - -TEST_F(InputReaderTest, GetInputDeviceIds) { - sp<FakePointerController> controller = new FakePointerController(); - mFakePolicy->setPointerController(2, controller); - - ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY, NULL)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("mouse"), - INPUT_DEVICE_CLASS_CURSOR, NULL)); - - Vector<int32_t> ids; - mReader->getInputDeviceIds(ids); - - ASSERT_EQ(size_t(2), ids.size()); - ASSERT_EQ(1, ids[0]); - ASSERT_EQ(2, ids[1]); + ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"), + 0, NULL)); // no classes so device will be ignored + + Vector<InputDeviceInfo> inputDevices; + mReader->getInputDevices(inputDevices); + + ASSERT_EQ(1U, inputDevices.size()); + ASSERT_EQ(1, inputDevices[0].getId()); + ASSERT_STREQ("keyboard", inputDevices[0].getName().string()); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); + ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); + + // Should also have received a notification describing the new input devices. + inputDevices = mFakePolicy->getInputDevices(); + ASSERT_EQ(1U, inputDevices.size()); + ASSERT_EQ(1, inputDevices[0].getId()); + ASSERT_STREQ("keyboard", inputDevices[0].getName().string()); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); + ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); } TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { @@ -1243,6 +1232,7 @@ class InputDeviceTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; + static const int32_t DEVICE_GENERATION; static const uint32_t DEVICE_CLASSES; sp<FakeEventHub> mFakeEventHub; @@ -1261,7 +1251,8 @@ protected: mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, identifier, DEVICE_CLASSES); + mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, + identifier, DEVICE_CLASSES); } virtual void TearDown() { @@ -1276,6 +1267,7 @@ protected: const char* InputDeviceTest::DEVICE_NAME = "device"; const int32_t InputDeviceTest::DEVICE_ID = 1; +const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK; @@ -1428,6 +1420,7 @@ class InputMapperTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; + static const int32_t DEVICE_GENERATION; static const uint32_t DEVICE_CLASSES; sp<FakeEventHub> mFakeEventHub; @@ -1443,7 +1436,8 @@ protected: mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, identifier, DEVICE_CLASSES); + mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, + identifier, DEVICE_CLASSES); mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); } @@ -1522,6 +1516,7 @@ protected: const char* InputMapperTest::DEVICE_NAME = "device"; const int32_t InputMapperTest::DEVICE_ID = 1; +const int32_t InputMapperTest::DEVICE_GENERATION = 2; const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 2f25df1..ce7671f 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -34,18 +34,23 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.hardware.input.IInputManager; +import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.InputManager; import android.hardware.input.KeyboardLayout; import android.os.Binder; import android.os.Bundle; import android.os.Environment; import android.os.Handler; +import android.os.IBinder; +import android.os.Message; import android.os.MessageQueue; import android.os.Process; +import android.os.RemoteException; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; import android.view.InputChannel; import android.view.InputDevice; @@ -77,12 +82,33 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; + private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; + // Pointer to native input manager service object. private final int mPtr; private final Context mContext; private final Callbacks mCallbacks; - private final Handler mHandler; + private final InputManagerHandler mHandler; + + // Used to simulate a persistent data store for keyboard layouts. + // TODO: Replace with the real thing. + private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>(); + + // List of currently registered input devices changed listeners by process id. + private Object mInputDevicesLock = new Object(); + private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock + private InputDevice[] mInputDevices = new InputDevice[0]; + private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners = + new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock + private final ArrayList<InputDevicesChangedListenerRecord> + mTempInputDevicesChangedListenersToNotify = + new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only + + // State for the currently installed input filter. + final Object mInputFilterLock = new Object(); + InputFilter mInputFilter; // guarded by mInputFilterLock + InputFilterHost mInputFilterHost; // guarded by mInputFilterLock private static native int nativeInit(InputManagerService service, Context context, MessageQueue messageQueue); @@ -111,9 +137,7 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. private static native void nativeSetSystemUiVisibility(int ptr, int visibility); private static native void nativeSetFocusedApplication(int ptr, InputApplicationHandle application); - private static native InputDevice nativeGetInputDevice(int ptr, int deviceId); private static native void nativeGetInputConfiguration(int ptr, Configuration configuration); - private static native int[] nativeGetInputDeviceIds(int ptr); private static native boolean nativeTransferTouchFocus(int ptr, InputChannel fromChannel, InputChannel toChannel); private static native void nativeSetPointerSpeed(int ptr, int speed); @@ -145,19 +169,10 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. /** The key is down but is a virtual key press that is being emulated by the system. */ public static final int KEY_STATE_VIRTUAL = 2; - // Used to simulate a persistent data store for keyboard layouts. - // TODO: Replace with the real thing. - private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>(); - - // State for the currently installed input filter. - final Object mInputFilterLock = new Object(); - InputFilter mInputFilter; - InputFilterHost mInputFilterHost; - public InputManagerService(Context context, Callbacks callbacks) { this.mContext = context; this.mCallbacks = callbacks; - this.mHandler = new Handler(); + this.mHandler = new InputManagerHandler(); Slog.i(TAG, "Initializing input manager"); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); @@ -396,16 +411,98 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. */ @Override // Binder call public InputDevice getInputDevice(int deviceId) { - return nativeGetInputDevice(mPtr, deviceId); + synchronized (mInputDevicesLock) { + final int count = mInputDevices.length; + for (int i = 0; i < count; i++) { + final InputDevice inputDevice = mInputDevices[i]; + if (inputDevice.getId() == deviceId) { + return inputDevice; + } + } + } + return null; } - + /** * Gets the ids of all input devices in the system. * @return The input device ids. */ @Override // Binder call public int[] getInputDeviceIds() { - return nativeGetInputDeviceIds(mPtr); + synchronized (mInputDevicesLock) { + final int count = mInputDevices.length; + int[] ids = new int[count]; + for (int i = 0; i < count; i++) { + ids[i] = mInputDevices[i].getId(); + } + return ids; + } + } + + @Override // Binder call + public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + synchronized (mInputDevicesLock) { + int callingPid = Binder.getCallingPid(); + if (mInputDevicesChangedListeners.get(callingPid) != null) { + throw new SecurityException("The calling process has already " + + "registered an InputDevicesChangedListener."); + } + + InputDevicesChangedListenerRecord record = + new InputDevicesChangedListenerRecord(callingPid, listener); + try { + IBinder binder = listener.asBinder(); + binder.linkToDeath(record, 0); + } catch (RemoteException ex) { + // give up + throw new RuntimeException(ex); + } + + mInputDevicesChangedListeners.put(callingPid, record); + } + } + + private void onInputDevicesChangedListenerDied(int pid) { + synchronized (mInputDevicesLock) { + mInputDevicesChangedListeners.remove(pid); + } + } + + // Must be called on handler. + private void deliverInputDevicesChanged() { + mTempInputDevicesChangedListenersToNotify.clear(); + + final int numListeners; + final int[] deviceIdAndGeneration; + synchronized (mInputDevicesLock) { + if (!mInputDevicesChangedPending) { + return; + } + mInputDevicesChangedPending = false; + + numListeners = mInputDevicesChangedListeners.size(); + for (int i = 0; i < numListeners; i++) { + mTempInputDevicesChangedListenersToNotify.add( + mInputDevicesChangedListeners.valueAt(i)); + } + + final int numDevices = mInputDevices.length; + deviceIdAndGeneration = new int[numDevices * 2]; + for (int i = 0; i < numDevices; i++) { + final InputDevice inputDevice = mInputDevices[i]; + deviceIdAndGeneration[i * 2] = inputDevice.getId(); + deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); + } + } + + for (int i = 0; i < numListeners; i++) { + mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( + deviceIdAndGeneration); + } } @Override // Binder call @@ -741,6 +838,18 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. } // Native callback. + private void notifyInputDevicesChanged(InputDevice[] inputDevices) { + synchronized (mInputDevicesLock) { + mInputDevices = inputDevices; + + if (!mInputDevicesChangedPending) { + mInputDevicesChangedPending = true; + mHandler.sendEmptyMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED); + } + } + } + + // Native callback. private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); } @@ -906,6 +1015,20 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. } /** + * Private handler for the input manager. + */ + private final class InputManagerHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_DELIVER_INPUT_DEVICES_CHANGED: + deliverInputDevicesChanged(); + break; + } + } + } + + /** * Hosting interface for input filters to call back into the input manager. */ private final class InputFilterHost implements InputFilter.Host { @@ -957,4 +1080,32 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. return result; } } + + private final class InputDevicesChangedListenerRecord implements DeathRecipient { + private final int mPid; + private final IInputDevicesChangedListener mListener; + + public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { + mPid = pid; + mListener = listener; + } + + @Override + public void binderDied() { + if (DEBUG) { + Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); + } + onInputDevicesChangedListenerDied(mPid); + } + + public void notifyInputDevicesChanged(int[] info) { + try { + mListener.onInputDevicesChanged(info); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to notify process " + + mPid + " that input devices changed, assuming it died.", ex); + binderDied(); + } + } + } } diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp index 85d6e11..f1536fd 100644 --- a/services/jni/com_android_server_input_InputManagerService.cpp +++ b/services/jni/com_android_server_input_InputManagerService.cpp @@ -59,6 +59,7 @@ static const float POINTER_SPEED_EXPONENT = 1.0f / 4; static struct { jmethodID notifyConfigurationChanged; + jmethodID notifyInputDevicesChanged; jmethodID notifyLidSwitchChanged; jmethodID notifyInputChannelBroken; jmethodID notifyANR; @@ -82,6 +83,10 @@ static struct { static struct { jclass clazz; +} gInputDeviceClassInfo; + +static struct { + jclass clazz; } gKeyEventClassInfo; static struct { @@ -179,6 +184,7 @@ public: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); + virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -486,6 +492,36 @@ void NativeInputManager::ensureSpriteControllerLocked() { } } +void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) { + JNIEnv* env = jniEnv(); + + size_t count = inputDevices.size(); + jobjectArray inputDevicesObjArray = env->NewObjectArray( + count, gInputDeviceClassInfo.clazz, NULL); + if (inputDevicesObjArray) { + bool error = false; + for (size_t i = 0; i < count; i++) { + jobject inputDeviceObj = android_view_InputDevice_create(env, inputDevices.itemAt(i)); + if (!inputDeviceObj) { + error = true; + break; + } + + env->SetObjectArrayElement(inputDevicesObjArray, i, inputDeviceObj); + env->DeleteLocalRef(inputDeviceObj); + } + + if (!error) { + env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputDevicesChanged, + inputDevicesObjArray); + } + + env->DeleteLocalRef(inputDevicesObjArray); + } + + checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged"); +} + void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { #if DEBUG_INPUT_DISPATCHER_POLICY @@ -1147,36 +1183,6 @@ static void nativeSetSystemUiVisibility(JNIEnv* env, im->setSystemUiVisibility(visibility); } -static jobject nativeGetInputDevice(JNIEnv* env, - jclass clazz, jint ptr, jint deviceId) { - NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - - InputDeviceInfo deviceInfo; - status_t status = im->getInputManager()->getReader()->getInputDeviceInfo( - deviceId, & deviceInfo); - if (status) { - return NULL; - } - - return android_view_InputDevice_create(env, deviceInfo); -} - -static jintArray nativeGetInputDeviceIds(JNIEnv* env, - jclass clazz, jint ptr) { - NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - - Vector<int> deviceIds; - im->getInputManager()->getReader()->getInputDeviceIds(deviceIds); - - jintArray deviceIdsObj = env->NewIntArray(deviceIds.size()); - if (! deviceIdsObj) { - return NULL; - } - - env->SetIntArrayRegion(deviceIdsObj, 0, deviceIds.size(), deviceIds.array()); - return deviceIdsObj; -} - static void nativeGetInputConfiguration(JNIEnv* env, jclass clazz, jint ptr, jobject configObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1273,10 +1279,6 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) nativeSetInputDispatchMode }, { "nativeSetSystemUiVisibility", "(II)V", (void*) nativeSetSystemUiVisibility }, - { "nativeGetInputDevice", "(II)Landroid/view/InputDevice;", - (void*) nativeGetInputDevice }, - { "nativeGetInputDeviceIds", "(I)[I", - (void*) nativeGetInputDeviceIds }, { "nativeGetInputConfiguration", "(ILandroid/content/res/Configuration;)V", (void*) nativeGetInputConfiguration }, { "nativeTransferTouchFocus", "(ILandroid/view/InputChannel;Landroid/view/InputChannel;)Z", @@ -1316,6 +1318,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.notifyConfigurationChanged, clazz, "notifyConfigurationChanged", "(J)V"); + GET_METHOD_ID(gServiceClassInfo.notifyInputDevicesChanged, clazz, + "notifyInputDevicesChanged", "([Landroid/view/InputDevice;)V"); + GET_METHOD_ID(gServiceClassInfo.notifyLidSwitchChanged, clazz, "notifyLidSwitchChanged", "(JZ)V"); @@ -1377,6 +1382,11 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz, "getPointerIcon", "()Landroid/view/PointerIcon;"); + // InputDevice + + FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); + gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz)); + // KeyEvent FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); |