Merge "Fix bug #1776278 (consider supplying our own (unique) eid for calendar entries created on the device)"
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index a5591ba..d09ff41 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -304,6 +304,10 @@
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
+ /* Allows the policy a chance to perform default processing for an unhandled key. */
+ virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+ const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
+
/* Notifies the policy about switch events.
*/
virtual void notifySwitch(nsecs_t when,
@@ -609,6 +613,7 @@
sp<InputChannel> inputChannel;
sp<InputApplicationHandle> inputApplicationHandle;
int32_t userActivityEventType;
+ bool handled;
};
// Generic queue implementation.
@@ -1030,7 +1035,8 @@
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
+ bool handled);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void drainOutboundQueueLocked(Connection* connection);
@@ -1061,7 +1067,7 @@
void onDispatchCycleStartedLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection);
+ nsecs_t currentTime, const sp<Connection>& connection, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
@@ -1073,7 +1079,9 @@
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
+ void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
+ void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
// Statistics gathering.
void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index dc9e27a..7efb6cc 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -250,12 +250,13 @@
status_t sendDispatchSignal();
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
+ * Returns whether the consumer handled the message.
*
* Returns OK on success.
* Returns WOULD_BLOCK if there is no signal present.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal();
+ status_t receiveFinishedSignal(bool& outHandled);
private:
sp<InputChannel> mChannel;
@@ -305,12 +306,12 @@
status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
/* Sends a finished signal to the publisher to inform it that the current message is
- * finished processing.
+ * finished processing and specifies whether the message was handled by the consumer.
*
* Returns OK on success.
* Errors probably indicate that the channel is broken.
*/
- status_t sendFinishedSignal();
+ status_t sendFinishedSignal(bool handled);
/* Receives the dispatched signal from the publisher.
*
diff --git a/include/ui/PowerManager.h b/include/ui/PowerManager.h
index 5434b4f..dd80318 100644
--- a/include/ui/PowerManager.h
+++ b/include/ui/PowerManager.h
@@ -22,14 +22,10 @@
enum {
POWER_MANAGER_OTHER_EVENT = 0,
- POWER_MANAGER_CHEEK_EVENT = 1,
- POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
- // up events or LONG_TOUCH events.
- POWER_MANAGER_LONG_TOUCH_EVENT = 3,
- POWER_MANAGER_TOUCH_UP_EVENT = 4,
- POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
+ POWER_MANAGER_BUTTON_EVENT = 1,
+ POWER_MANAGER_TOUCH_EVENT = 2,
- POWER_MANAGER_LAST_EVENT = POWER_MANAGER_BUTTON_EVENT, // Last valid event code.
+ POWER_MANAGER_LAST_EVENT = POWER_MANAGER_TOUCH_EVENT, // Last valid event code.
};
} // namespace android
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index f9c0b91..7ddb3c7 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -51,9 +51,6 @@
namespace android {
-// Delay before reporting long touch events to the power manager.
-const nsecs_t LONG_TOUCH_DELAY = 300 * 1000000LL; // 300 ms
-
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
@@ -1416,21 +1413,7 @@
}
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
- switch (motionEntry->action) {
- case AMOTION_EVENT_ACTION_DOWN:
- eventType = POWER_MANAGER_TOUCH_EVENT;
- break;
- case AMOTION_EVENT_ACTION_UP:
- eventType = POWER_MANAGER_TOUCH_UP_EVENT;
- break;
- default:
- if (motionEntry->eventTime - motionEntry->downTime < LONG_TOUCH_DELAY) {
- eventType = POWER_MANAGER_TOUCH_EVENT;
- } else {
- eventType = POWER_MANAGER_LONG_TOUCH_EVENT;
- }
- break;
- }
+ eventType = POWER_MANAGER_TOUCH_EVENT;
}
break;
}
@@ -1770,13 +1753,14 @@
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
+ const sp<Connection>& connection, bool handled) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
- "%01.1fms since dispatch",
+ "%01.1fms since dispatch, handled=%s",
connection->getInputChannelName(),
connection->getEventLatencyMillis(currentTime),
- connection->getDispatchLatencyMillis(currentTime));
+ connection->getDispatchLatencyMillis(currentTime),
+ toString(handled));
#endif
if (connection->status == Connection::STATUS_BROKEN
@@ -1784,9 +1768,6 @@
return;
}
- // Notify other system components.
- onDispatchCycleFinishedLocked(currentTime, connection);
-
// Reset the publisher since the event has been consumed.
// We do this now so that the publisher can release some of its internal resources
// while waiting for the next dispatch cycle to begin.
@@ -1798,7 +1779,8 @@
return;
}
- startNextDispatchCycleLocked(currentTime, connection);
+ // Notify other system components and prepare to start the next dispatch cycle.
+ onDispatchCycleFinishedLocked(currentTime, connection, handled);
}
void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
@@ -1898,7 +1880,8 @@
return 1;
}
- status_t status = connection->inputPublisher.receiveFinishedSignal();
+ bool handled = false;
+ status_t status = connection->inputPublisher.receiveFinishedSignal(handled);
if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
@@ -1907,7 +1890,7 @@
return 0; // remove the callback
}
- d->finishDispatchCycleLocked(currentTime, connection);
+ d->finishDispatchCycleLocked(currentTime, connection, handled);
d->runCommandsLockedInterruptible();
return 1;
} // release lock
@@ -2945,7 +2928,11 @@
}
void InputDispatcher::onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection) {
+ nsecs_t currentTime, const sp<Connection>& connection, bool handled) {
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ commandEntry->connection = connection;
+ commandEntry->handled = handled;
}
void InputDispatcher::onDispatchCycleBrokenLocked(
@@ -3014,9 +3001,7 @@
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
- mReusableKeyEvent.initialize(entry->deviceId, entry->source, entry->action, entry->flags,
- entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
- entry->downTime, entry->eventTime);
+ initializeKeyEvent(&mReusableKeyEvent, entry);
mLock.unlock();
@@ -3031,6 +3016,31 @@
mAllocator.releaseKeyEntry(entry);
}
+void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
+ CommandEntry* commandEntry) {
+ sp<Connection> connection = commandEntry->connection;
+ bool handled = commandEntry->handled;
+
+ if (!handled && !connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
+ if (dispatchEntry->inProgress
+ && dispatchEntry->hasForegroundTarget()
+ && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ initializeKeyEvent(&mReusableKeyEvent, keyEntry);
+
+ mLock.unlock();
+
+ mPolicy->dispatchUnhandledKey(connection->inputChannel,
+ & mReusableKeyEvent, keyEntry->policyFlags);
+
+ mLock.lock();
+ }
+ }
+
+ startNextDispatchCycleLocked(now(), connection);
+}
+
void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
mLock.unlock();
@@ -3039,6 +3049,12 @@
mLock.lock();
}
+void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
+ event->initialize(entry->deviceId, entry->source, entry->action, entry->flags,
+ entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
+ entry->downTime, entry->eventTime);
+}
+
void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
// TODO Write some statistics about how long we spend waiting.
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 120222c..b91e93a 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -129,11 +129,11 @@
case AKEYCODE_META_RIGHT:
return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
case AKEYCODE_CAPS_LOCK:
- return toggleLockedMetaState(AMETA_CAPS_LOCK_LATCHED, down, oldMetaState);
+ return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
case AKEYCODE_NUM_LOCK:
- return toggleLockedMetaState(AMETA_NUM_LOCK_LATCHED, down, oldMetaState);
+ return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
case AKEYCODE_SCROLL_LOCK:
- return toggleLockedMetaState(AMETA_SCROLL_LOCK_LATCHED, down, oldMetaState);
+ return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
default:
return oldMetaState;
}
@@ -966,8 +966,8 @@
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
if (mAssociatedDisplayId >= 0) {
int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
+ if (!getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
}
keyCode = rotateKeyCode(keyCode, orientation);
@@ -1058,11 +1058,11 @@
void KeyboardInputMapper::updateLedStateLocked(bool reset) {
updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL,
- AMETA_CAPS_LOCK_LATCHED, reset);
+ AMETA_CAPS_LOCK_ON, reset);
updateLedStateForModifierLocked(mLocked.numLockLedState, LED_NUML,
- AMETA_NUM_LOCK_LATCHED, reset);
+ AMETA_NUM_LOCK_ON, reset);
updateLedStateForModifierLocked(mLocked.scrollLockLedState, LED_SCROLLL,
- AMETA_SCROLL_LOCK_LATCHED, reset);
+ AMETA_SCROLL_LOCK_ON, reset);
}
void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& ledState,
@@ -1228,7 +1228,7 @@
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
int32_t orientation;
if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
- return;
+ orientation = InputReaderPolicyInterface::ROTATION_0;
}
float temp;
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 2c6346e..1885691 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -35,8 +35,12 @@
static const char INPUT_SIGNAL_DISPATCH = 'D';
// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message.
-static const char INPUT_SIGNAL_FINISHED = 'f';
+// consuming the most recent message and it handled it.
+static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
+
+// Signal sent by the consumer to the producer to inform it that it has finished
+// consuming the most recent message but it did not handle it.
+static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
// --- InputChannel ---
@@ -497,7 +501,7 @@
return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
}
-status_t InputPublisher::receiveFinishedSignal() {
+status_t InputPublisher::receiveFinishedSignal(bool& outHandled) {
#if DEBUG_TRANSPORT_ACTIONS
LOGD("channel '%s' publisher ~ receiveFinishedSignal",
mChannel->getName().string());
@@ -506,9 +510,14 @@
char signal;
status_t result = mChannel->receiveSignal(& signal);
if (result) {
+ outHandled = false;
return result;
}
- if (signal != INPUT_SIGNAL_FINISHED) {
+ if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
+ outHandled = true;
+ } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
+ outHandled = false;
+ } else {
LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
mChannel->getName().string(), signal);
return UNKNOWN_ERROR;
@@ -626,13 +635,15 @@
return OK;
}
-status_t InputConsumer::sendFinishedSignal() {
+status_t InputConsumer::sendFinishedSignal(bool handled) {
#if DEBUG_TRANSPORT_ACTIONS
- LOGD("channel '%s' consumer ~ sendFinishedSignal",
- mChannel->getName().string());
+ LOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
+ mChannel->getName().string(), handled);
#endif
- return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);
+ return mChannel->sendSignal(handled
+ ? INPUT_SIGNAL_FINISHED_HANDLED
+ : INPUT_SIGNAL_FINISHED_UNHANDLED);
}
status_t InputConsumer::receiveDispatchSignal() {
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp
index 8874dfe..f352dbf 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/libs/ui/tests/InputDispatcher_test.cpp
@@ -67,6 +67,11 @@
return false;
}
+ virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
+ const KeyEvent* keyEvent, uint32_t policyFlags) {
+ return false;
+ }
+
virtual void notifySwitch(nsecs_t when,
int32_t switchCode, int32_t switchValue, uint32_t policyFlags) {
}
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 952b974..c6eac25 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -118,13 +118,16 @@
EXPECT_EQ(downTime, keyEvent->getDownTime());
EXPECT_EQ(eventTime, keyEvent->getEventTime());
- status = mConsumer->sendFinishedSignal();
+ status = mConsumer->sendFinishedSignal(true);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- status = mPublisher->receiveFinishedSignal();
+ bool handled = false;
+ status = mPublisher->receiveFinishedSignal(handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_TRUE(handled)
+ << "publisher receiveFinishedSignal should have set handled to consumer's reply";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
@@ -279,13 +282,16 @@
EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
}
- status = mConsumer->sendFinishedSignal();
+ status = mConsumer->sendFinishedSignal(false);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- status = mPublisher->receiveFinishedSignal();
+ bool handled = true;
+ status = mPublisher->receiveFinishedSignal(handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_FALSE(handled)
+ << "publisher receiveFinishedSignal should have set handled to consumer's reply";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp
index c19147f..ded0225 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/libs/ui/tests/InputReader_test.cpp
@@ -376,6 +376,7 @@
KeyedVector<int32_t, int32_t> scanCodeStates;
KeyedVector<int32_t, int32_t> switchStates;
KeyedVector<int32_t, KeyInfo> keys;
+ KeyedVector<int32_t, bool> leds;
Device(const String8& name, uint32_t classes) :
name(name), classes(classes) {
@@ -450,6 +451,16 @@
device->keys.add(scanCode, info);
}
+ void addLed(int32_t deviceId, int32_t led, bool initialState) {
+ Device* device = getDevice(deviceId);
+ device->leds.add(led, initialState);
+ }
+
+ bool getLedState(int32_t deviceId, int32_t led) {
+ Device* device = getDevice(deviceId);
+ return device->leds.valueFor(led);
+ }
+
Vector<String8>& getExcludedDevices() {
return mExcludedDevices;
}
@@ -584,10 +595,22 @@
}
virtual bool hasLed(int32_t deviceId, int32_t led) const {
- return false;
+ Device* device = getDevice(deviceId);
+ return device && device->leds.indexOfKey(led) >= 0;
}
virtual void setLedState(int32_t deviceId, int32_t led, bool on) {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ ssize_t index = device->leds.indexOfKey(led);
+ if (index >= 0) {
+ device->leds.replaceValueAt(led, on);
+ } else {
+ ADD_FAILURE()
+ << "Attempted to set the state of an LED that the EventHub declared "
+ "was not present. led=" << led;
+ }
+ }
}
virtual void dump(String8& dump) {
@@ -1703,6 +1726,81 @@
ASSERT_FALSE(flags[1]);
}
+TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
+ mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/);
+
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addMapperAndConfigure(mapper);
+
+ // Initialization should have turned all of the lights off.
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+
+ // Toggle caps lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState());
+
+ // Toggle num lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0);
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState());
+
+ // Toggle caps lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState());
+
+ // Toggle scroll lock on.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+
+ // Toggle num lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_NUMLOCK, AKEYCODE_NUM_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState());
+
+ // Toggle scroll lock off.
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 1, 0);
+ process(mapper, ARBITRARY_TIME, DEVICE_ID,
+ EV_KEY, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0, 0);
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
+}
+
// --- TrackballInputMapperTest ---