Add support for fallback keycodes.

This change enables the framework to synthesize key events to implement
default behavior when an application does not handle a key.
For example, this change enables numeric keypad keys to perform
their associated special function when numlock is off.

The application is informed that it is processing a fallback keypress
so it can choose to ignore it.

Added a new keycode for switching applications.

Added ALT key deadkeys.

New default key mappings:
- ESC -> BACK
- Meta+ESC -> HOME
- Alt+ESC -> MENU
- Meta+Space -> SEARCH
- Meta+Tab -> APP_SWITCH

Fixed some comments.
Fixed some tests.

Change-Id: Id7f3b6645f3a350275e624547822f72652f3defe
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index f1223f1..1f6a920 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -1884,7 +1884,7 @@
         }
 
         bool handled = false;
-        status_t status = connection->inputPublisher.receiveFinishedSignal(handled);
+        status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
         if (status) {
             LOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
                     connection->getInputChannelName(), status);
@@ -3039,21 +3039,57 @@
     sp<Connection> connection = commandEntry->connection;
     bool handled = commandEntry->handled;
 
-    if (!handled && !connection->outboundQueue.isEmpty()) {
+    if (!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);
-            KeyEvent event;
-            initializeKeyEvent(&event, keyEntry);
+            if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
+                if (handled) {
+                    // If the application handled a non-fallback key, then immediately
+                    // cancel all fallback keys previously dispatched to the application.
+                    // This behavior will prevent chording with fallback keys (so they cannot
+                    // be used as modifiers) but it will ensure that fallback keys do not
+                    // get stuck.  This takes care of the case where the application does not handle
+                    // the original DOWN so we generate a fallback DOWN but it does handle
+                    // the original UP in which case we would not generate the fallback UP.
+                    synthesizeCancelationEventsForConnectionLocked(connection,
+                            InputState::CANCEL_FALLBACK_EVENTS,
+                            "Application handled a non-fallback event.");
+                } else {
+                    // If the application did not handle a non-fallback key, then ask
+                    // the policy what to do with it.  We might generate a fallback key
+                    // event here.
+                    KeyEvent event;
+                    initializeKeyEvent(&event, keyEntry);
 
-            mLock.unlock();
+                    mLock.unlock();
 
-            mPolicy->dispatchUnhandledKey(connection->inputChannel,
-                    &event, keyEntry->policyFlags);
+                    bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel,
+                            &event, keyEntry->policyFlags, &event);
 
-            mLock.lock();
+                    mLock.lock();
+
+                    if (fallback) {
+                        // Restart the dispatch cycle using the fallback key.
+                        keyEntry->eventTime = event.getEventTime();
+                        keyEntry->deviceId = event.getDeviceId();
+                        keyEntry->source = event.getSource();
+                        keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
+                        keyEntry->keyCode = event.getKeyCode();
+                        keyEntry->scanCode = event.getScanCode();
+                        keyEntry->metaState = event.getMetaState();
+                        keyEntry->repeatCount = event.getRepeatCount();
+                        keyEntry->downTime = event.getDownTime();
+                        keyEntry->syntheticRepeat = false;
+
+                        dispatchEntry->inProgress = false;
+                        startDispatchCycleLocked(now(), connection);
+                        return;
+                    }
+                }
+            }
         }
     }
 
@@ -3371,6 +3407,7 @@
         memento.source = entry->source;
         memento.keyCode = entry->keyCode;
         memento.scanCode = entry->scanCode;
+        memento.flags = entry->flags;
         memento.downTime = entry->downTime;
         return CONSISTENT;
     }
@@ -3453,10 +3490,10 @@
         CancelationOptions options) {
     for (size_t i = 0; i < mKeyMementos.size(); ) {
         const KeyMemento& memento = mKeyMementos.itemAt(i);
-        if (shouldCancelEvent(memento.source, options)) {
+        if (shouldCancelKey(memento, options)) {
             outEvents.push(allocator->obtainKeyEntry(currentTime,
                     memento.deviceId, memento.source, 0,
-                    AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
+                    AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
                     memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
             mKeyMementos.removeAt(i);
         } else {
@@ -3466,7 +3503,7 @@
 
     for (size_t i = 0; i < mMotionMementos.size(); ) {
         const MotionMemento& memento = mMotionMementos.itemAt(i);
-        if (shouldCancelEvent(memento.source, options)) {
+        if (shouldCancelMotion(memento, options)) {
             outEvents.push(allocator->obtainMotionEntry(currentTime,
                     memento.deviceId, memento.source, 0,
                     AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
@@ -3502,15 +3539,30 @@
     }
 }
 
-bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
+bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
         CancelationOptions options) {
     switch (options) {
-    case CANCEL_POINTER_EVENTS:
-        return eventSource & AINPUT_SOURCE_CLASS_POINTER;
+    case CANCEL_ALL_EVENTS:
     case CANCEL_NON_POINTER_EVENTS:
-        return !(eventSource & AINPUT_SOURCE_CLASS_POINTER);
-    default:
         return true;
+    case CANCEL_FALLBACK_EVENTS:
+        return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
+    default:
+        return false;
+    }
+}
+
+bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
+        CancelationOptions options) {
+    switch (options) {
+    case CANCEL_ALL_EVENTS:
+        return true;
+    case CANCEL_POINTER_EVENTS:
+        return memento.source & AINPUT_SOURCE_CLASS_POINTER;
+    case CANCEL_NON_POINTER_EVENTS:
+        return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+    default:
+        return false;
     }
 }
 
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 9cc96ad..51ed09f 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -745,17 +745,6 @@
 void KeyboardInputMapper::initializeLocked() {
     mLocked.metaState = AMETA_NONE;
     mLocked.downTime = 0;
-
-    initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL);
-    initializeLedStateLocked(mLocked.numLockLedState, LED_NUML);
-    initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL);
-
-    updateLedStateLocked(true);
-}
-
-void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) {
-    ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
-    ledState.on = false;
 }
 
 uint32_t KeyboardInputMapper::getSources() {
@@ -786,6 +775,12 @@
 
     // Configure basic parameters.
     configureParameters();
+
+    // Reset LEDs.
+    {
+        AutoMutex _l(mLock);
+        resetLedStateLocked();
+    }
 }
 
 void KeyboardInputMapper::configureParameters() {
@@ -813,6 +808,7 @@
             // Synthesize key up event on reset if keys are currently down.
             if (mLocked.keyDowns.isEmpty()) {
                 initializeLocked();
+                resetLedStateLocked();
                 break; // done
             }
 
@@ -953,6 +949,19 @@
     } // release lock
 }
 
+void KeyboardInputMapper::resetLedStateLocked() {
+    initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL);
+    initializeLedStateLocked(mLocked.numLockLedState, LED_NUML);
+    initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL);
+
+    updateLedStateLocked(true);
+}
+
+void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) {
+    ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
+    ledState.on = false;
+}
+
 void KeyboardInputMapper::updateLedStateLocked(bool reset) {
     updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL,
             AMETA_CAPS_LOCK_ON, reset);
@@ -966,7 +975,7 @@
         int32_t led, int32_t modifier, bool reset) {
     if (ledState.avail) {
         bool desiredState = (mLocked.metaState & modifier) != 0;
-        if (ledState.on != desiredState) {
+        if (reset || ledState.on != desiredState) {
             getEventHub()->setLedState(getDeviceId(), led, desiredState);
             ledState.on = desiredState;
         }
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 1885691..83d9556 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -501,7 +501,7 @@
     return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
 }
 
-status_t InputPublisher::receiveFinishedSignal(bool& outHandled) {
+status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
 #if DEBUG_TRANSPORT_ACTIONS
     LOGD("channel '%s' publisher ~ receiveFinishedSignal",
             mChannel->getName().string());
@@ -510,13 +510,13 @@
     char signal;
     status_t result = mChannel->receiveSignal(& signal);
     if (result) {
-        outHandled = false;
+        *outHandled = false;
         return result;
     }
     if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
-        outHandled = true;
+        *outHandled = true;
     } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
-        outHandled = false;
+        *outHandled = false;
     } else {
         LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
                 mChannel->getName().string(), signal);
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index e689c4b..9bfa8f6 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -141,9 +141,8 @@
 
 char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
     char16_t result = 0;
-    ssize_t index = mKeys.indexOfKey(keyCode);
-    if (index >= 0) {
-        const Key* key = mKeys.valueAt(index);
+    const Key* key;
+    if (getKey(keyCode, &key)) {
         result = key->label;
     }
 #if DEBUG_MAPPING
@@ -154,9 +153,8 @@
 
 char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
     char16_t result = 0;
-    ssize_t index = mKeys.indexOfKey(keyCode);
-    if (index >= 0) {
-        const Key* key = mKeys.valueAt(index);
+    const Key* key;
+    if (getKey(keyCode, &key)) {
         result = key->number;
     }
 #if DEBUG_MAPPING
@@ -167,15 +165,10 @@
 
 char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
     char16_t result = 0;
-    ssize_t index = mKeys.indexOfKey(keyCode);
-    if (index >= 0) {
-        const Key* key = mKeys.valueAt(index);
-        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
-            if ((behavior->metaState & metaState) == behavior->metaState) {
-                result = behavior->character;
-                break;
-            }
-        }
+    const Key* key;
+    const Behavior* behavior;
+    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+        result = behavior->character;
     }
 #if DEBUG_MAPPING
     LOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
@@ -183,13 +176,33 @@
     return result;
 }
 
+bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
+        FallbackAction* outFallbackAction) const {
+    outFallbackAction->keyCode = 0;
+    outFallbackAction->metaState = 0;
+
+    bool result = false;
+    const Key* key;
+    const Behavior* behavior;
+    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+        outFallbackAction->keyCode = behavior->fallbackKeyCode;
+        outFallbackAction->metaState = metaState & ~behavior->metaState;
+        result = true;
+    }
+#if DEBUG_MAPPING
+    LOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
+            "fallback keyCode=%d, fallback metaState=0x%08x.",
+            keyCode, metaState, result ? "true" : "false",
+            outFallbackAction->keyCode, outFallbackAction->metaState);
+#endif
+    return result;
+}
+
 char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
         int32_t metaState) const {
     char16_t result = 0;
-    ssize_t index = mKeys.indexOfKey(keyCode);
-    if (index >= 0) {
-        const Key* key = mKeys.valueAt(index);
-
+    const Key* key;
+    if (getKey(keyCode, &key)) {
         // Try to find the most general behavior that maps to this character.
         // For example, the base key behavior will usually be last in the list.
         // However, if we find a perfect meta state match for one behavior then use that one.
@@ -238,7 +251,7 @@
     }
 #if DEBUG_MAPPING
     LOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
-            deviceId, toString(chars, numChars).string(), outEvents.size());
+            deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
     for (size_t i = 0; i < outEvents.size(); i++) {
         LOGD("  Key: keyCode=%d, metaState=0x%08x, %s.",
                 outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
@@ -248,6 +261,32 @@
     return true;
 }
 
+bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
+    ssize_t index = mKeys.indexOfKey(keyCode);
+    if (index >= 0) {
+        *outKey = mKeys.valueAt(index);
+        return true;
+    }
+    return false;
+}
+
+bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
+        const Key** outKey, const Behavior** outBehavior) const {
+    const Key* key;
+    if (getKey(keyCode, &key)) {
+        const Behavior* behavior = key->firstBehavior;
+        while (behavior) {
+            if ((behavior->metaState & metaState) == behavior->metaState) {
+                *outKey = key;
+                *outBehavior = behavior;
+                return true;
+            }
+            behavior = behavior->next;
+        }
+    }
+    return false;
+}
+
 bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
     if (!ch) {
         return false;
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp
index 68f9037..7e17c57 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/libs/ui/tests/InputDispatcher_test.cpp
@@ -66,7 +66,7 @@
     }
 
     virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
-            const KeyEvent* keyEvent, uint32_t policyFlags) {
+            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
         return false;
     }
 
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index c6eac25..903fcaf 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -123,7 +123,7 @@
             << "consumer sendFinishedSignal should return OK";
 
     bool handled = false;
-    status = mPublisher->receiveFinishedSignal(handled);
+    status = mPublisher->receiveFinishedSignal(&handled);
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
     ASSERT_TRUE(handled)
@@ -287,7 +287,7 @@
             << "consumer sendFinishedSignal should return OK";
 
     bool handled = true;
-    status = mPublisher->receiveFinishedSignal(handled);
+    status = mPublisher->receiveFinishedSignal(&handled);
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
     ASSERT_FALSE(handled)
diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp
index d6c2cbd..97cbc25 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/libs/ui/tests/InputReader_test.cpp
@@ -1137,6 +1137,7 @@
         mFakeDispatcher = new FakeInputDispatcher();
         mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher);
 
+        mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
     }
 
@@ -1753,7 +1754,7 @@
     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);
+            EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 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));
@@ -2225,19 +2226,19 @@
 }
 
 
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchPad_ReturnsTouchPad) {
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     prepareAxes(POSITION);
-    addConfigurationProperty("touch.displayType", "touchPad");
+    addConfigurationProperty("touch.deviceType", "touchPad");
     addMapperAndConfigure(mapper);
 
     ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
 }
 
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchScreen_ReturnsTouchScreen) {
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     prepareAxes(POSITION);
-    addConfigurationProperty("touch.displayType", "touchScreen");
+    addConfigurationProperty("touch.deviceType", "touchScreen");
     addMapperAndConfigure(mapper);
 
     ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());