diff options
author | Jeff Brown <jeffbrown@google.com> | 2010-06-15 01:31:58 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2010-06-15 16:43:18 -0700 |
commit | 54bc281639e5ff6955d7a86104f6f21624941aca (patch) | |
tree | b8c1a3094530f39942f26a436cc97e3989c5deaa /libs/ui | |
parent | 4607338eaf2988dc4dc4b0b738098f17878a90ab (diff) | |
download | frameworks_native-54bc281639e5ff6955d7a86104f6f21624941aca.zip frameworks_native-54bc281639e5ff6955d7a86104f6f21624941aca.tar.gz frameworks_native-54bc281639e5ff6955d7a86104f6f21624941aca.tar.bz2 |
More work in progress on native events.
Refactored the code to eliminate potential deadlocks due to re-entrant
calls from the policy into the dispatcher. Also added some plumbing
that will be used to notify the framework about ANRs.
Change-Id: Iba7a10de0cb3c56cd7520d6ce716db52fdcc94ff
Diffstat (limited to 'libs/ui')
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 393 | ||||
-rw-r--r-- | libs/ui/InputManager.cpp | 65 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 203 |
3 files changed, 442 insertions, 219 deletions
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 0ccde0d..f058271 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -19,6 +19,9 @@ // Log debug messages about the dispatch cycle. #define DEBUG_DISPATCH_CYCLE 1 +// Log debug messages about registrations. +#define DEBUG_REGISTRATION 1 + // Log debug messages about performance statistics. #define DEBUG_PERFORMANCE_STATISTICS 1 @@ -42,7 +45,7 @@ static inline bool isMovementKey(int32_t keyCode) { // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) : +InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy) { mPollLoop = new PollLoop(); @@ -55,6 +58,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) mInboundQueue.tail.eventTime = LONG_LONG_MAX; mKeyRepeatState.lastKeyEntry = NULL; + + mCurrentInputTargetsValid = false; } InputDispatcher::~InputDispatcher() { @@ -72,8 +77,9 @@ InputDispatcher::~InputDispatcher() { } void InputDispatcher::dispatchOnce() { - bool allowKeyRepeat = mPolicy->allowKeyRepeat(); + nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); + bool skipPoll = false; nsecs_t currentTime; nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock @@ -84,7 +90,7 @@ void InputDispatcher::dispatchOnce() { // is not a key. This is to ensure that we abort a key repeat if the device is just coming // out of sleep. // XXX we should handle resetting input state coming out of sleep more generally elsewhere - if (! allowKeyRepeat) { + if (keyRepeatTimeout < 0) { resetKeyRepeatLocked(); } @@ -121,8 +127,8 @@ void InputDispatcher::dispatchOnce() { if (mInboundQueue.isEmpty()) { if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { - processKeyRepeatLocked(currentTime); - return; // dispatched once + processKeyRepeatLockedInterruptible(currentTime, keyRepeatTimeout); + skipPoll = true; } else { if (mKeyRepeatState.nextRepeatTime < nextWakeupTime) { nextWakeupTime = mKeyRepeatState.nextRepeatTime; @@ -130,31 +136,30 @@ void InputDispatcher::dispatchOnce() { } } } else { - // Inbound queue has at least one entry. Dequeue it and begin dispatching. - // Note that we do not hold the lock for this process because dispatching may - // involve making many callbacks. - EventEntry* entry = mInboundQueue.dequeueAtHead(); + // Inbound queue has at least one entry. + // Start processing it but leave it on the queue until later so that the + // input reader can keep appending samples onto a motion event between the + // time we started processing it and the time we finally enqueue dispatch + // entries for it. + EventEntry* entry = mInboundQueue.head.next; switch (entry->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast<ConfigurationChangedEntry*>(entry); - processConfigurationChangedLocked(currentTime, typedEntry); - mAllocator.releaseConfigurationChangedEntry(typedEntry); + processConfigurationChangedLockedInterruptible(currentTime, typedEntry); break; } case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(entry); - processKeyLocked(currentTime, typedEntry); - mAllocator.releaseKeyEntry(typedEntry); + processKeyLockedInterruptible(currentTime, typedEntry, keyRepeatTimeout); break; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast<MotionEntry*>(entry); - processMotionLocked(currentTime, typedEntry); - mAllocator.releaseMotionEntry(typedEntry); + processMotionLockedInterruptible(currentTime, typedEntry); break; } @@ -162,30 +167,67 @@ void InputDispatcher::dispatchOnce() { assert(false); break; } - return; // dispatched once + + // Dequeue and release the event entry that we just processed. + mInboundQueue.dequeue(entry); + mAllocator.releaseEventEntry(entry); + skipPoll = true; } } + + // Run any deferred commands. + skipPoll |= runCommandsLockedInterruptible(); } // release lock + // If we dispatched anything, don't poll just now. Wait for the next iteration. + // Contents may have shifted during flight. + if (skipPoll) { + return; + } + // Wait for callback or timeout or wake. nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime); int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0; mPollLoop->pollOnce(timeoutMillis); } -void InputDispatcher::processConfigurationChangedLocked(nsecs_t currentTime, - ConfigurationChangedEntry* entry) { +bool InputDispatcher::runCommandsLockedInterruptible() { + if (mCommandQueue.isEmpty()) { + return false; + } + + do { + CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); + + Command command = commandEntry->command; + (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' + + mAllocator.releaseCommandEntry(commandEntry); + } while (! mCommandQueue.isEmpty()); + return true; +} + +InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { + CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command); + mCommandQueue.enqueueAtTail(commandEntry); + return commandEntry; +} + +void InputDispatcher::processConfigurationChangedLockedInterruptible( + nsecs_t currentTime, ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("processConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, " - "keyboardConfig=%d, navigationConfig=%d", entry->eventTime, - entry->touchScreenConfig, entry->keyboardConfig, entry->navigationConfig); + LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime); #endif - mPolicy->notifyConfigurationChanged(entry->eventTime, entry->touchScreenConfig, - entry->keyboardConfig, entry->navigationConfig); + mLock.unlock(); + + mPolicy->notifyConfigurationChanged(entry->eventTime); + + mLock.lock(); } -void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) { +void InputDispatcher::processKeyLockedInterruptible( + nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) { #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, " "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", @@ -209,7 +251,7 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) { } else { // Not a repeat. Save key down state in case we do see a repeat later. resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + mPolicy->getKeyRepeatTimeout(); + mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; @@ -217,10 +259,11 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) { resetKeyRepeatLocked(); } - identifyInputTargetsAndDispatchKeyLocked(currentTime, entry); + identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry); } -void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) { +void InputDispatcher::processKeyRepeatLockedInterruptible( + nsecs_t currentTime, nsecs_t keyRepeatTimeout) { // TODO Old WindowManagerServer code sniffs the input queue for following key up // events and drops the repeat if one is found. We should do something similar. // One good place to do it is in notifyKey as soon as the key up enters the @@ -252,7 +295,7 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) { entry->downTime = currentTime; entry->policyFlags = 0; - mKeyRepeatState.nextRepeatTime = currentTime + mPolicy->getKeyRepeatTimeout(); + mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout; #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, " @@ -263,10 +306,11 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) { entry->repeatCount, entry->downTime); #endif - identifyInputTargetsAndDispatchKeyLocked(currentTime, entry); + identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry); } -void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entry) { +void InputDispatcher::processMotionLockedInterruptible( + nsecs_t currentTime, MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, " "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", @@ -296,15 +340,19 @@ void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entr } #endif - identifyInputTargetsAndDispatchMotionLocked(currentTime, entry); + identifyInputTargetsAndDispatchMotionLockedInterruptible(currentTime, entry); } -void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked( +void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible( nsecs_t currentTime, KeyEntry* entry) { #if DEBUG_DISPATCH_CYCLE LOGD("identifyInputTargetsAndDispatchKey"); #endif + entry->dispatchInProgress = true; + mCurrentInputTargetsValid = false; + mLock.unlock(); + mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, entry->downTime, entry->eventTime); @@ -313,15 +361,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked( mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags, mCurrentInputTargets); + mLock.lock(); + mCurrentInputTargetsValid = true; + dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false); } -void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked( +void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible( nsecs_t currentTime, MotionEntry* entry) { #if DEBUG_DISPATCH_CYCLE LOGD("identifyInputTargetsAndDispatchMotion"); #endif + entry->dispatchInProgress = true; + mCurrentInputTargetsValid = false; + mLock.unlock(); + mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->edgeFlags, entry->metaState, entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y, @@ -333,17 +388,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked( mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags, mCurrentInputTargets); + mLock.lock(); + mCurrentInputTargetsValid = true; + dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false); } void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, EventEntry* eventEntry, bool resumeWithAppendedMotionSample) { #if DEBUG_DISPATCH_CYCLE - LOGD("dispatchEventToCurrentInputTargets, " + LOGD("dispatchEventToCurrentInputTargets - " "resumeWithAppendedMotionSample=%s", resumeWithAppendedMotionSample ? "true" : "false"); #endif + assert(eventEntry->dispatchInProgress); // should already have been set to true + for (size_t i = 0; i < mCurrentInputTargets.size(); i++) { const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i); @@ -365,7 +425,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection EventEntry* eventEntry, const InputTarget* inputTarget, bool resumeWithAppendedMotionSample) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ prepareDispatchCycle, flags=%d, timeout=%lldns, " + LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, " "xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s", connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout, inputTarget->xOffset, inputTarget->yOffset, @@ -377,7 +437,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection // not responding. if (connection->status != Connection::STATUS_NORMAL) { LOGV("channel '%s' ~ Dropping event because the channel status is %s", - connection->status == Connection::STATUS_BROKEN ? "BROKEN" : "NOT RESPONDING"); + connection->getStatusLabel()); return; } @@ -631,14 +691,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Connection* void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ finishDispatchCycle: %01.1fms since event, " + LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, " "%01.1fms since dispatch", connection->getInputChannelName(), connection->getEventLatencyMillis(currentTime), connection->getDispatchLatencyMillis(currentTime)); #endif - if (connection->status == Connection::STATUS_BROKEN) { + if (connection->status == Connection::STATUS_BROKEN + || connection->status == Connection::STATUS_ZOMBIE) { return; } @@ -722,34 +783,37 @@ bool InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime, Connection bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection, bool broken) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ abortDispatchCycle, broken=%s", + LOGD("channel '%s' ~ abortDispatchCycle - broken=%s", connection->getInputChannelName(), broken ? "true" : "false"); #endif - if (connection->status == Connection::STATUS_BROKEN) { - return false; - } - // Clear the pending timeout. connection->nextTimeoutTime = LONG_LONG_MAX; // Clear the outbound queue. - while (! connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead(); - mAllocator.releaseDispatchEntry(dispatchEntry); - } + bool deactivated = ! connection->outboundQueue.isEmpty(); + if (deactivated) { + do { + DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead(); + mAllocator.releaseDispatchEntry(dispatchEntry); + } while (! connection->outboundQueue.isEmpty()); - // Outbound queue is empty, deactivate the connection. - deactivateConnectionLocked(connection); + deactivateConnectionLocked(connection); + } // Handle the case where the connection appears to be unrecoverably broken. + // Ignore already broken or zombie connections. if (broken) { - connection->status = Connection::STATUS_BROKEN; + if (connection->status == Connection::STATUS_NORMAL + || connection->status == Connection::STATUS_NOT_RESPONDING) { + connection->status = Connection::STATUS_BROKEN; - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); + // Notify other system components. + onDispatchCycleBrokenLocked(currentTime, connection); + } } - return true; /*deactivated*/ + + return deactivated; } bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) { @@ -772,6 +836,7 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. " "events=0x%x", connection->getInputChannelName(), events); d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); + d->runCommandsLockedInterruptible(); return false; // remove the callback } @@ -786,20 +851,19 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat LOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); + d->runCommandsLockedInterruptible(); return false; // remove the callback } d->finishDispatchCycleLocked(currentTime, connection.get()); + d->runCommandsLockedInterruptible(); return true; } // release lock } -void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touchScreenConfig, - int32_t keyboardConfig, int32_t navigationConfig) { +void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) { #if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, " - "keyboardConfig=%d, navigationConfig=%d", eventTime, - touchScreenConfig, keyboardConfig, navigationConfig); + LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime); #endif bool wasEmpty; @@ -808,9 +872,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry(); newEntry->eventTime = eventTime; - newEntry->touchScreenConfig = touchScreenConfig; - newEntry->keyboardConfig = keyboardConfig; - newEntry->navigationConfig = navigationConfig; wasEmpty = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(newEntry); @@ -821,16 +882,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc } } -void InputDispatcher::notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) { -#if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyLidSwitchChanged - eventTime=%lld, open=%s", eventTime, - lidOpen ? "true" : "false"); -#endif - - // Send lid switch notification immediately and synchronously. - mPolicy->notifyLidSwitchChanged(eventTime, lidOpen); -} - void InputDispatcher::notifyAppSwitchComing(nsecs_t eventTime) { #if DEBUG_INBOUND_EVENT_DETAILS LOGD("notifyAppSwitchComing - eventTime=%lld", eventTime); @@ -949,13 +1000,25 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t } // The last motion event is a move and is compatible for appending. - // Do the batching magic and exit. + // Do the batching magic. mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords); #if DEBUG_BATCHING LOGD("Appended motion sample onto batch for most recent " "motion event for this device in the inbound queue."); #endif - return; // done + + // Sanity check for special case because dispatch is interruptible. + // The dispatch logic is partially interruptible and releases its lock while + // identifying targets. However, as soon as the targets have been identified, + // the dispatcher proceeds to write a dispatch entry into all relevant outbound + // queues and then promptly removes the motion entry from the queue. + // + // Consequently, we should never observe the case where the inbound queue contains + // an in-progress motion entry unless the current input targets are invalid + // (currently being computed). Check for this! + assert(! (motionEntry->dispatchInProgress && mCurrentInputTargetsValid)); + + return; // done! } // STREAMING CASE @@ -977,34 +1040,38 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t // Note: This code crucially depends on the invariant that an outbound queue always // contains at most one synchronous event and it is always last (but it might // not be first!). - for (size_t i = 0; i < mActiveConnections.size(); i++) { - Connection* connection = mActiveConnections.itemAt(i); - if (! connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev; - if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) { - if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) { - goto NoBatchingOrStreaming; - } - - MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>( - dispatchEntry->eventEntry); - if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE - || syncedMotionEntry->deviceId != deviceId - || syncedMotionEntry->pointerCount != pointerCount) { - goto NoBatchingOrStreaming; + if (mCurrentInputTargetsValid) { + for (size_t i = 0; i < mActiveConnections.size(); i++) { + Connection* connection = mActiveConnections.itemAt(i); + if (! connection->outboundQueue.isEmpty()) { + DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev; + if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) { + if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) { + goto NoBatchingOrStreaming; + } + + MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>( + dispatchEntry->eventEntry); + if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE + || syncedMotionEntry->deviceId != deviceId + || syncedMotionEntry->pointerCount != pointerCount) { + goto NoBatchingOrStreaming; + } + + // Found synced move entry. Append sample and resume dispatch. + mAllocator.appendMotionSample(syncedMotionEntry, eventTime, + pointerCount, pointerCoords); + #if DEBUG_BATCHING + LOGD("Appended motion sample onto batch for most recent synchronously " + "dispatched motion event for this device in the outbound queues."); + #endif + nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); + dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry, + true /*resumeWithAppendedMotionSample*/); + + runCommandsLockedInterruptible(); + return; // done! } - - // Found synced move entry. Append sample and resume dispatch. - mAllocator.appendMotionSample(syncedMotionEntry, eventTime, - pointerCount, pointerCoords); -#if DEBUG_BATCHING - LOGD("Appended motion sample onto batch for most recent synchronously " - "dispatched motion event for this device in the outbound queues."); -#endif - nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); - dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry, - true /*resumeWithAppendedMotionSample*/); - return; // done! } } } @@ -1049,6 +1116,10 @@ void InputDispatcher::resetKeyRepeatLocked() { } status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) { +#if DEBUG_REGISTRATION + LOGD("channel '%s' - Registered", inputChannel->getName().string()); +#endif + int receiveFd; { // acquire lock AutoMutex _l(mLock); @@ -1069,6 +1140,8 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan } mConnectionsByReceiveFd.add(receiveFd, connection); + + runCommandsLockedInterruptible(); } // release lock mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this); @@ -1076,6 +1149,10 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan } status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { +#if DEBUG_REGISTRATION + LOGD("channel '%s' - Unregistered", inputChannel->getName().string()); +#endif + int32_t receiveFd; { // acquire lock AutoMutex _l(mLock); @@ -1095,6 +1172,8 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/); + + runCommandsLockedInterruptible(); } // release lock mPollLoop->removeCallback(receiveFd); @@ -1123,11 +1202,12 @@ void InputDispatcher::deactivateConnectionLocked(Connection* connection) { } } -void InputDispatcher::onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleStartedLocked( + nsecs_t currentTime, Connection* connection) { } -void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, - Connection* connection, bool recoveredFromANR) { +void InputDispatcher::onDispatchCycleFinishedLocked( + nsecs_t currentTime, Connection* connection, bool recoveredFromANR) { if (recoveredFromANR) { LOGI("channel '%s' ~ Recovered from ANR. %01.1fms since event, " "%01.1fms since dispatch, %01.1fms since ANR", @@ -1136,26 +1216,65 @@ void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, connection->getDispatchLatencyMillis(currentTime), connection->getANRLatencyMillis(currentTime)); - // TODO tell framework + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible); + commandEntry->inputChannel = connection->inputChannel; } } -void InputDispatcher::onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleANRLocked( + nsecs_t currentTime, Connection* connection) { LOGI("channel '%s' ~ Not responding! %01.1fms since event, %01.1fms since dispatch", connection->getInputChannelName(), connection->getEventLatencyMillis(currentTime), connection->getDispatchLatencyMillis(currentTime)); - // TODO tell framework + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyInputChannelANRLockedInterruptible); + commandEntry->inputChannel = connection->inputChannel; } -void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) { +void InputDispatcher::onDispatchCycleBrokenLocked( + nsecs_t currentTime, Connection* connection) { LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", connection->getInputChannelName()); - // TODO tell framework + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); + commandEntry->inputChannel = connection->inputChannel; } +void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( + CommandEntry* commandEntry) { + mLock.unlock(); + + mPolicy->notifyInputChannelBroken(commandEntry->inputChannel); + commandEntry->inputChannel.clear(); + + mLock.lock(); +} + +void InputDispatcher::doNotifyInputChannelANRLockedInterruptible( + CommandEntry* commandEntry) { + mLock.unlock(); + + mPolicy->notifyInputChannelANR(commandEntry->inputChannel); + commandEntry->inputChannel.clear(); + + mLock.lock(); +} + +void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible( + CommandEntry* commandEntry) { + mLock.unlock(); + + mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel); + commandEntry->inputChannel.clear(); + + mLock.lock(); +} + + // --- InputDispatcher::Allocator --- InputDispatcher::Allocator::Allocator() { @@ -1166,6 +1285,7 @@ InputDispatcher::Allocator::obtainConfigurationChangedEntry() { ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc(); entry->refCount = 1; entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED; + entry->dispatchInProgress = false; return entry; } @@ -1173,6 +1293,7 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry() { KeyEntry* entry = mKeyEntryPool.alloc(); entry->refCount = 1; entry->type = EventEntry::TYPE_KEY; + entry->dispatchInProgress = false; return entry; } @@ -1181,6 +1302,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry() { entry->refCount = 1; entry->type = EventEntry::TYPE_MOTION; entry->firstSample.next = NULL; + entry->dispatchInProgress = false; return entry; } @@ -1192,6 +1314,12 @@ InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry( return entry; } +InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) { + CommandEntry* entry = mCommandEntryPool.alloc(); + entry->command = command; + return entry; +} + void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) { switch (entry->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: @@ -1231,7 +1359,11 @@ void InputDispatcher::Allocator::releaseKeyEntry(KeyEntry* entry) { void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) { entry->refCount -= 1; if (entry->refCount == 0) { - freeMotionSampleList(entry->firstSample.next); + for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) { + MotionSample* next = sample->next; + mMotionSamplePool.free(sample); + sample = next; + } mMotionEntryPool.free(entry); } else { assert(entry->refCount > 0); @@ -1243,6 +1375,10 @@ void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) { mDispatchEntryPool.free(entry); } +void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) { + mCommandEntryPool.free(entry); +} + void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) { MotionSample* sample = mMotionSamplePool.alloc(); @@ -1256,18 +1392,6 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, motionEntry->lastSample = sample; } -void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) { - mMotionSamplePool.free(sample); -} - -void InputDispatcher::Allocator::freeMotionSampleList(MotionSample* head) { - while (head) { - MotionSample* next = head->next; - mMotionSamplePool.free(head); - head = next; - } -} - // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : @@ -1284,6 +1408,25 @@ status_t InputDispatcher::Connection::initialize() { return inputPublisher.initialize(); } +const char* InputDispatcher::Connection::getStatusLabel() const { + switch (status) { + case STATUS_NORMAL: + return "NORMAL"; + + case STATUS_BROKEN: + return "BROKEN"; + + case STATUS_NOT_RESPONDING: + return "NOT_RESPONDING"; + + case STATUS_ZOMBIE: + return "ZOMBIE"; + + default: + return "UNKNOWN"; + } +} + InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent( const EventEntry* eventEntry) const { for (DispatchEntry* dispatchEntry = outboundQueue.tail.prev; @@ -1295,6 +1438,14 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchE return NULL; } +// --- InputDispatcher::CommandEntry --- + +InputDispatcher::CommandEntry::CommandEntry() { +} + +InputDispatcher::CommandEntry::~CommandEntry() { +} + // --- InputDispatcherThread --- diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp index ab354a5..7538dd0 100644 --- a/libs/ui/InputManager.cpp +++ b/libs/ui/InputManager.cpp @@ -14,29 +14,30 @@ namespace android { -InputManager::InputManager(const sp<EventHubInterface>& eventHub, - const sp<InputDispatchPolicyInterface>& policy) : - mEventHub(eventHub), mPolicy(policy) { - mDispatcher = new InputDispatcher(policy); - mReader = new InputReader(eventHub, policy, mDispatcher); - - mDispatcherThread = new InputDispatcherThread(mDispatcher); - mReaderThread = new InputReaderThread(mReader); +InputManager::InputManager( + const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& readerPolicy, + const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { + mDispatcher = new InputDispatcher(dispatcherPolicy); + mReader = new InputReader(eventHub, readerPolicy, mDispatcher); + initialize(); +} - configureExcludedDevices(); +InputManager::InputManager( + const sp<InputReaderInterface>& reader, + const sp<InputDispatcherInterface>& dispatcher) : + mReader(reader), + mDispatcher(dispatcher) { + initialize(); } InputManager::~InputManager() { stop(); } -void InputManager::configureExcludedDevices() { - Vector<String8> excludedDeviceNames; - mPolicy->getExcludedDeviceNames(excludedDeviceNames); - - for (size_t i = 0; i < excludedDeviceNames.size(); i++) { - mEventHub->addExcludedDevice(excludedDeviceNames[i]); - } +void InputManager::initialize() { + mReaderThread = new InputReaderThread(mReader); + mDispatcherThread = new InputDispatcherThread(mDispatcher); } status_t InputManager::start() { @@ -79,36 +80,26 @@ status_t InputManager::unregisterInputChannel(const sp<InputChannel>& inputChann return mDispatcher->unregisterInputChannel(inputChannel); } -int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses, int32_t scanCode) - const { - int32_t vkKeyCode, vkScanCode; - if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) { - if (vkScanCode == scanCode) { - return KEY_STATE_VIRTUAL; - } - } - - return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode); +void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const { + mReader->getCurrentInputConfiguration(outConfiguration); } -int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses, int32_t keyCode) - const { - int32_t vkKeyCode, vkScanCode; - if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) { - if (vkKeyCode == keyCode) { - return KEY_STATE_VIRTUAL; - } - } +int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const { + return mReader->getCurrentScanCodeState(deviceId, deviceClasses, scanCode); +} - return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode); +int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const { + return mReader->getCurrentKeyCodeState(deviceId, deviceClasses, keyCode); } int32_t InputManager::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const { - return mEventHub->getSwitchState(deviceId, deviceClasses, sw); + return mReader->getCurrentSwitchState(deviceId, deviceClasses, sw); } bool InputManager::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { - return mEventHub->hasKeys(numCodes, keyCodes, outFlags); + return mReader->hasKeys(numCodes, keyCodes, outFlags); } } // namespace android diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 796abd0..62b5f28 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -27,6 +27,22 @@ #include <errno.h> #include <limits.h> +/** Amount that trackball needs to move in order to generate a key event. */ +#define TRACKBALL_MOVEMENT_THRESHOLD 6 + +/* Slop distance for jumpy pointer detection. + * The vertical range of the screen divided by this is our epsilon value. */ +#define JUMPY_EPSILON_DIVISOR 212 + +/* Number of jumpy points to drop for touchscreens that need it. */ +#define JUMPY_TRANSITION_DROPS 3 +#define JUMPY_DROP_LIMIT 3 + +/* Maximum squared distance for averaging. + * If moving farther than this, turn of averaging to avoid lag in response. */ +#define AVERAGING_DISTANCE_LIMIT (75 * 75) + + namespace android { // --- Static Functions --- @@ -89,7 +105,7 @@ static const int keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - if (orientation != InputDispatchPolicyInterface::ROTATION_0) { + if (orientation != InputReaderPolicyInterface::ROTATION_0) { for (int i = 0; i < keyCodeRotationMapSize; i++) { if (keyCode == keyCodeRotationMap[i][0]) { return keyCodeRotationMap[i][orientation]; @@ -677,12 +693,13 @@ void InputDevice::MultiTouchScreenState::reset() { // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputDispatchPolicyInterface>& policy, + const sp<InputReaderPolicyInterface>& policy, const sp<InputDispatcherInterface>& dispatcher) : mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) { + configureExcludedDevices(); resetGlobalMetaState(); resetDisplayProperties(); - updateGlobalVirtualKeyState(); + updateExportedVirtualKeyState(); } InputReader::~InputReader() { @@ -925,7 +942,7 @@ void InputReader::handleSwitch(const RawEvent* rawEvent) { InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId); if (! device) return; - onSwitch(rawEvent->when, device, rawEvent->value != 0, rawEvent->scanCode); + onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value); } void InputReader::onKey(nsecs_t when, InputDevice* device, @@ -974,7 +991,7 @@ void InputReader::onKey(nsecs_t when, InputDevice* device, } int32_t keyEventFlags = KEY_EVENT_FLAG_FROM_SYSTEM; - if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) { + if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) { keyEventFlags = keyEventFlags | KEY_EVENT_FLAG_WOKE_HERE; } @@ -984,12 +1001,12 @@ void InputReader::onKey(nsecs_t when, InputDevice* device, device->keyboard.current.downTime); } -void InputReader::onSwitch(nsecs_t when, InputDevice* device, bool down, - int32_t code) { - switch (code) { - case SW_LID: - mDispatcher->notifyLidSwitchChanged(when, ! down); - } +void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, + int32_t switchValue) { + int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue); + + uint32_t policyFlags = 0; + applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags); } void InputReader::onMultiTouchScreenStateChanged(nsecs_t when, @@ -1256,7 +1273,7 @@ void InputReader::dispatchVirtualKey(nsecs_t when, nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime; int32_t metaState = globalMetaState(); - updateGlobalVirtualKeyState(); + updateExportedVirtualKeyState(); mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); @@ -1333,8 +1350,8 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli int32_t motionEventAction) { int32_t orientedWidth, orientedHeight; switch (mDisplayOrientation) { - case InputDispatchPolicyInterface::ROTATION_90: - case InputDispatchPolicyInterface::ROTATION_270: + case InputReaderPolicyInterface::ROTATION_90: + case InputReaderPolicyInterface::ROTATION_270: orientedWidth = mDisplayHeight; orientedHeight = mDisplayWidth; break; @@ -1369,18 +1386,18 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli * device->touchScreen.precalculated.sizeScale; switch (mDisplayOrientation) { - case InputDispatchPolicyInterface::ROTATION_90: { + case InputReaderPolicyInterface::ROTATION_90: { float xTemp = x; x = y; y = mDisplayHeight - xTemp; break; } - case InputDispatchPolicyInterface::ROTATION_180: { + case InputReaderPolicyInterface::ROTATION_180: { x = mDisplayWidth - x; y = mDisplayHeight - y; break; } - case InputDispatchPolicyInterface::ROTATION_270: { + case InputReaderPolicyInterface::ROTATION_270: { float xTemp = x; x = mDisplayWidth - y; y = xTemp; @@ -1483,18 +1500,18 @@ void InputReader::onTrackballStateChanged(nsecs_t when, float temp; switch (mDisplayOrientation) { - case InputDispatchPolicyInterface::ROTATION_90: + case InputReaderPolicyInterface::ROTATION_90: temp = pointerCoords.x; pointerCoords.x = pointerCoords.y; pointerCoords.y = - temp; break; - case InputDispatchPolicyInterface::ROTATION_180: + case InputReaderPolicyInterface::ROTATION_180: pointerCoords.x = - pointerCoords.x; pointerCoords.y = - pointerCoords.y; break; - case InputDispatchPolicyInterface::ROTATION_270: + case InputReaderPolicyInterface::ROTATION_270: temp = pointerCoords.x; pointerCoords.x = - pointerCoords.y; pointerCoords.y = temp; @@ -1514,51 +1531,30 @@ void InputReader::onConfigurationChanged(nsecs_t when) { resetGlobalMetaState(); // Reset virtual keys, just in case. - updateGlobalVirtualKeyState(); + updateExportedVirtualKeyState(); - // Enqueue configuration changed. - // XXX This stuff probably needs to be tracked elsewhere in an input device registry - // of some kind that can be asynchronously updated and queried. (Same as above?) - int32_t touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_NOTOUCH; - int32_t keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_NOKEYS; - int32_t navigationConfig = InputDispatchPolicyInterface::NAVIGATION_NONAV; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - int32_t deviceClasses = device->classes; - - if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) { - touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_FINGER; - } - if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_QWERTY; - } - if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) { - navigationConfig = InputDispatchPolicyInterface::NAVIGATION_TRACKBALL; - } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) { - navigationConfig = InputDispatchPolicyInterface::NAVIGATION_DPAD; - } - } + // Update input configuration. + updateExportedInputConfiguration(); - mDispatcher->notifyConfigurationChanged(when, touchScreenConfig, - keyboardConfig, navigationConfig); + // Enqueue configuration changed. + mDispatcher->notifyConfigurationChanged(when); } bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when, int32_t policyActions, uint32_t* policyFlags) { - if (policyActions & InputDispatchPolicyInterface::ACTION_APP_SWITCH_COMING) { + if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) { mDispatcher->notifyAppSwitchComing(when); } - if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) { + if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) { *policyFlags |= POLICY_FLAG_WOKE_HERE; } - if (policyActions & InputDispatchPolicyInterface::ACTION_BRIGHT_HERE) { + if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) { *policyFlags |= POLICY_FLAG_BRIGHT_HERE; } - return policyActions & InputDispatchPolicyInterface::ACTION_DISPATCH; + return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH; } void InputReader::resetDisplayProperties() { @@ -1706,7 +1702,7 @@ void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) { void InputReader::configureVirtualKeys(InputDevice* device) { device->touchScreen.virtualKeys.clear(); - Vector<InputDispatchPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions; + Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions; mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions); if (virtualKeyDefinitions.size() == 0) { return; @@ -1720,7 +1716,7 @@ void InputReader::configureVirtualKeys(InputDevice* device) { int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range; for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const InputDispatchPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = + const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; device->touchScreen.virtualKeys.add(); @@ -1779,6 +1775,15 @@ void InputReader::configureAbsoluteAxisInfo(InputDevice* device, LOGI(" %s: unknown axis values, setting to zero", name); } +void InputReader::configureExcludedDevices() { + Vector<String8> excludedDeviceNames; + mPolicy->getExcludedDeviceNames(excludedDeviceNames); + + for (size_t i = 0; i < excludedDeviceNames.size(); i++) { + mEventHub->addExcludedDevice(excludedDeviceNames[i]); + } +} + void InputReader::resetGlobalMetaState() { mGlobalMetaState = -1; } @@ -1796,7 +1801,7 @@ int32_t InputReader::globalMetaState() { return mGlobalMetaState; } -void InputReader::updateGlobalVirtualKeyState() { +void InputReader::updateExportedVirtualKeyState() { int32_t keyCode = -1, scanCode = -1; for (size_t i = 0; i < mDevices.size(); i++) { @@ -1809,20 +1814,96 @@ void InputReader::updateGlobalVirtualKeyState() { } } - { + { // acquire exported state lock AutoMutex _l(mExportedStateLock); - mGlobalVirtualKeyCode = keyCode; - mGlobalVirtualScanCode = scanCode; - } + mExportedVirtualKeyCode = keyCode; + mExportedVirtualScanCode = scanCode; + } // release exported state lock } bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const { - AutoMutex _l(mExportedStateLock); + { // acquire exported state lock + AutoMutex _l(mExportedStateLock); + + *outKeyCode = mExportedVirtualKeyCode; + *outScanCode = mExportedVirtualScanCode; + return mExportedVirtualKeyCode != -1; + } // release exported state lock +} + +void InputReader::updateExportedInputConfiguration() { + int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH; + int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS; + int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV; + + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + int32_t deviceClasses = device->classes; + + if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) { + touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER; + } + if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) { + keyboardConfig = InputConfiguration::KEYBOARD_QWERTY; + } + if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) { + navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL; + } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) { + navigationConfig = InputConfiguration::NAVIGATION_DPAD; + } + } + + { // acquire exported state lock + AutoMutex _l(mExportedStateLock); + + mExportedInputConfiguration.touchScreen = touchScreenConfig; + mExportedInputConfiguration.keyboard = keyboardConfig; + mExportedInputConfiguration.navigation = navigationConfig; + } // release exported state lock +} + +void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const { + { // acquire exported state lock + AutoMutex _l(mExportedStateLock); + + *outConfiguration = mExportedInputConfiguration; + } // release exported state lock +} + +int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const { + { // acquire exported state lock + AutoMutex _l(mExportedStateLock); + + if (mExportedVirtualScanCode == scanCode) { + return KEY_STATE_VIRTUAL; + } + } // release exported state lock + + return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode); +} + +int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const { + { // acquire exported state lock + AutoMutex _l(mExportedStateLock); + + if (mExportedVirtualKeyCode == keyCode) { + return KEY_STATE_VIRTUAL; + } + } // release exported state lock + + return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode); +} + +int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const { + return mEventHub->getSwitchState(deviceId, deviceClasses, sw); +} - *outKeyCode = mGlobalVirtualKeyCode; - *outScanCode = mGlobalVirtualScanCode; - return mGlobalVirtualKeyCode != -1; +bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { + return mEventHub->hasKeys(numCodes, keyCodes, outFlags); } |