Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e923274 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Support chorded fallback keys."

parents 5c8eff33 da3d5a91
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -646,11 +646,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     * Create (if necessary) and launch the recent apps dialog
     */
    void showRecentAppsDialog() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mRecentAppsDialog == null) {
                    mRecentAppsDialog = new RecentApplicationsDialog(mContext);
                }
                mRecentAppsDialog.show();
            }
        });
    }

    /** {@inheritDoc} */
    public void init(Context context, IWindowManager windowManager,
@@ -1386,7 +1391,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
            return false;
        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
            if (!down) {
            if (down && repeatCount == 0) {
                showRecentAppsDialog();
            }
            return true;
+179 −86
Original line number Diff line number Diff line
@@ -563,18 +563,19 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR
    }

    switch (entry->type) {
    case EventEntry::TYPE_KEY:
        synthesizeCancelationEventsForAllConnectionsLocked(
                InputState::CANCEL_NON_POINTER_EVENTS, reason);
    case EventEntry::TYPE_KEY: {
        CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
        synthesizeCancelationEventsForAllConnectionsLocked(options);
        break;
    }
    case EventEntry::TYPE_MOTION: {
        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
            synthesizeCancelationEventsForAllConnectionsLocked(
                    InputState::CANCEL_POINTER_EVENTS, reason);
            CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
            synthesizeCancelationEventsForAllConnectionsLocked(options);
        } else {
            synthesizeCancelationEventsForAllConnectionsLocked(
                    InputState::CANCEL_NON_POINTER_EVENTS, reason);
            CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
            synthesizeCancelationEventsForAllConnectionsLocked(options);
        }
        break;
    }
@@ -903,8 +904,9 @@ bool InputDispatcher::dispatchMotionLocked(

    // Dispatch the motion.
    if (conflictingPointerActions) {
        synthesizeCancelationEventsForAllConnectionsLocked(
                InputState::CANCEL_POINTER_EVENTS, "Conflicting pointer actions.");
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                "conflicting pointer actions");
        synthesizeCancelationEventsForAllConnectionsLocked(options);
    }
    dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
    return true;
@@ -1070,9 +1072,9 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout
            if (connectionIndex >= 0) {
                sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
                if (connection->status == Connection::STATUS_NORMAL) {
                    synthesizeCancelationEventsForConnectionLocked(
                            connection, InputState::CANCEL_ALL_EVENTS,
                    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
                            "application not responding");
                    synthesizeCancelationEventsForConnectionLocked(connection, options);
                }
            }
        }
@@ -2169,26 +2171,24 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data
}

void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
        InputState::CancelationOptions options, const char* reason) {
        const CancelationOptions& options) {
    for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
        synthesizeCancelationEventsForConnectionLocked(
                mConnectionsByReceiveFd.valueAt(i), options, reason);
                mConnectionsByReceiveFd.valueAt(i), options);
    }
}

void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
        const sp<InputChannel>& channel, InputState::CancelationOptions options,
        const char* reason) {
        const sp<InputChannel>& channel, const CancelationOptions& options) {
    ssize_t index = getConnectionIndexLocked(channel);
    if (index >= 0) {
        synthesizeCancelationEventsForConnectionLocked(
                mConnectionsByReceiveFd.valueAt(index), options, reason);
                mConnectionsByReceiveFd.valueAt(index), options);
    }
}

void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
        const sp<Connection>& connection, InputState::CancelationOptions options,
        const char* reason) {
        const sp<Connection>& connection, const CancelationOptions& options) {
    nsecs_t currentTime = now();

    mTempCancelationEvents.clear();
@@ -2199,8 +2199,9 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
            && connection->status != Connection::STATUS_BROKEN) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
        LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
                "with reality: %s, options=%d.",
                connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
                "with reality: %s, mode=%d.",
                connection->getInputChannelName(), mTempCancelationEvents.size(),
                options.reason, options.mode);
#endif
        for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
            EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
@@ -2870,8 +2871,9 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
                LOGD("Focus left window: %s",
                        oldFocusedWindowChannel->getName().string());
#endif
                synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
                        InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
                CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                        "focus left window");
                synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
                oldFocusedWindowChannel.clear();
            }
        }
@@ -2892,8 +2894,9 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
#if DEBUG_FOCUS
                LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
#endif
                synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
                        InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
                CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                        "touched window was removed");
                synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
                mTouchState.windows.removeAt(i);
            }
        }
@@ -3036,9 +3039,9 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
            sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);

            fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
            synthesizeCancelationEventsForConnectionLocked(fromConnection,
                    InputState::CANCEL_POINTER_EVENTS,
            CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                    "transferring touch focus from this window to another window");
            synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
        }

#if DEBUG_FOCUS
@@ -3056,7 +3059,8 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
    LOGD("Resetting and dropping all events (%s).", reason);
#endif

    synthesizeCancelationEventsForAllConnectionsLocked(InputState::CANCEL_ALL_EVENTS, reason);
    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason);
    synthesizeCancelationEventsForAllConnectionsLocked(options);

    resetKeyRepeatLocked();
    releasePendingEventLocked();
@@ -3386,58 +3390,49 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
    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);
            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 want to send a fallback CANCEL.
                    synthesizeCancelationEventsForConnectionLocked(connection,
                            InputState::CANCEL_FALLBACK_EVENTS,
                            "application handled a non-fallback event, "
                            "canceling all fallback events");
                    connection->originalKeyCodeForFallback = -1;
                } else {
                    // If the application did not handle a non-fallback key, first check
                    // that we are in a good state to handle the fallback key.  Then ask
                    // the policy what to do with it.
                    if (connection->originalKeyCodeForFallback < 0) {
                        if (keyEntry->action != AKEY_EVENT_ACTION_DOWN
                                || keyEntry->repeatCount != 0) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
                            LOGD("Unhandled key event: Skipping fallback since this "
                                    "is not an initial down.  "
                                    "keyCode=%d, action=%d, repeatCount=%d",
                                    keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
#endif
                            goto SkipFallback;
                // Get the fallback key state.
                // Clear it out after dispatching the UP.
                int32_t originalKeyCode = keyEntry->keyCode;
                int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
                if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                    connection->inputState.removeFallbackKey(originalKeyCode);
                }

                        // Start handling the fallback key on DOWN.
                        connection->originalKeyCodeForFallback = keyEntry->keyCode;
                if (handled || !dispatchEntry->hasForegroundTarget()) {
                    // If the application handles the original key for which we previously
                    // generated a fallback or if the window is not a foreground window,
                    // then cancel the associated fallback key, if any.
                    if (fallbackKeyCode != -1) {
                        if (fallbackKeyCode != AKEYCODE_UNKNOWN) {
                            CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
                                    "application handled the original non-fallback key "
                                    "or is no longer a foreground target, "
                                    "canceling previously dispatched fallback key");
                            options.keyCode = fallbackKeyCode;
                            synthesizeCancelationEventsForConnectionLocked(connection, options);
                        }
                        connection->inputState.removeFallbackKey(originalKeyCode);
                    }
                } else {
                        if (keyEntry->keyCode != connection->originalKeyCodeForFallback) {
                    // If the application did not handle a non-fallback key, first check
                    // that we are in a good state to perform unhandled key event processing
                    // Then ask the policy what to do with it.
                    bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN
                            && keyEntry->repeatCount == 0;
                    if (fallbackKeyCode == -1 && !initialDown) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
                            LOGD("Unhandled key event: Skipping fallback since there is "
                                    "already a different fallback in progress.  "
                                    "keyCode=%d, originalKeyCodeForFallback=%d",
                                    keyEntry->keyCode, connection->originalKeyCodeForFallback);
                        LOGD("Unhandled key event: Skipping unhandled key event processing "
                                "since this is not an initial down.  "
                                "keyCode=%d, action=%d, repeatCount=%d",
                                originalKeyCode, keyEntry->action, keyEntry->repeatCount);
#endif
                        goto SkipFallback;
                    }

                        // Finish handling the fallback key on UP.
                        if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                            connection->originalKeyCodeForFallback = -1;
                        }
                    }

                    // Dispatch the unhandled key to the policy.
#if DEBUG_OUTBOUND_EVENT_DETAILS
                    LOGD("Unhandled key event: Asking policy to perform fallback action.  "
                            "keyCode=%d, action=%d, repeatCount=%d",
@@ -3454,18 +3449,78 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
                    mLock.lock();

                    if (connection->status != Connection::STATUS_NORMAL) {
                        connection->inputState.removeFallbackKey(originalKeyCode);
                        return;
                    }

                    assert(connection->outboundQueue.headSentinel.next == dispatchEntry);

                    // Latch the fallback keycode for this key on an initial down.
                    // The fallback keycode cannot change at any other point in the lifecycle.
                    if (initialDown) {
                        if (fallback) {
                            fallbackKeyCode = event.getKeyCode();
                        } else {
                            fallbackKeyCode = AKEYCODE_UNKNOWN;
                        }
                        connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode);
                    }

                    assert(fallbackKeyCode != -1);

                    // Cancel the fallback key if the policy decides not to send it anymore.
                    // We will continue to dispatch the key to the policy but we will no
                    // longer dispatch a fallback key to the application.
                    if (fallbackKeyCode != AKEYCODE_UNKNOWN
                            && (!fallback || fallbackKeyCode != event.getKeyCode())) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
                        if (fallback) {
                            LOGD("Unhandled key event: Policy requested to send key %d"
                                    "as a fallback for %d, but on the DOWN it had requested "
                                    "to send %d instead.  Fallback canceled.",
                                    event.getKeyCode(), originalKeyCode, fallbackKeyCode);
                        } else {
                            LOGD("Unhandled key event: Policy did not request fallback for %d,"
                                    "but on the DOWN it had requested to send %d.  "
                                    "Fallback canceled.",
                                    originalKeyCode, fallbackKeyCode);
                        }
#endif

                        CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
                                "canceling fallback, policy no longer desires it");
                        options.keyCode = fallbackKeyCode;
                        synthesizeCancelationEventsForConnectionLocked(connection, options);

                        fallback = false;
                        fallbackKeyCode = AKEYCODE_UNKNOWN;
                        if (keyEntry->action != AKEY_EVENT_ACTION_UP) {
                            connection->inputState.setFallbackKey(originalKeyCode,
                                    fallbackKeyCode);
                        }
                    }

#if DEBUG_OUTBOUND_EVENT_DETAILS
                    {
                        String8 msg;
                        const KeyedVector<int32_t, int32_t>& fallbackKeys =
                                connection->inputState.getFallbackKeys();
                        for (size_t i = 0; i < fallbackKeys.size(); i++) {
                            msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
                                    fallbackKeys.valueAt(i));
                        }
                        LOGD("Unhandled key event: %d currently tracked fallback keys%s.",
                                fallbackKeys.size(), msg.string());
                    }
#endif

                    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->keyCode = fallbackKeyCode;
                        keyEntry->scanCode = event.getScanCode();
                        keyEntry->metaState = event.getMetaState();
                        keyEntry->repeatCount = event.getRepeatCount();
@@ -3474,13 +3529,17 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(

#if DEBUG_OUTBOUND_EVENT_DETAILS
                        LOGD("Unhandled key event: Dispatching fallback key.  "
                                "fallbackKeyCode=%d, fallbackMetaState=%08x",
                                keyEntry->keyCode, keyEntry->metaState);
                                "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
                                originalKeyCode, fallbackKeyCode, keyEntry->metaState);
#endif

                        dispatchEntry->inProgress = false;
                        startDispatchCycleLocked(now(), connection);
                        return;
                    } else {
#if DEBUG_OUTBOUND_EVENT_DETAILS
                        LOGD("Unhandled key event: No fallback key.");
#endif
                    }
                }
            }
@@ -3774,6 +3833,17 @@ void InputDispatcher::InputState::trackEvent(const EventEntry* entry, int32_t ac
}

void InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action) {
    if (action == AKEY_EVENT_ACTION_UP
            && (entry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
        for (size_t i = 0; i < mFallbackKeys.size(); ) {
            if (mFallbackKeys.valueAt(i) == entry->keyCode) {
                mFallbackKeys.removeItemsAt(i);
            } else {
                i += 1;
            }
        }
    }

    for (size_t i = 0; i < mKeyMementos.size(); i++) {
        KeyMemento& memento = mKeyMementos.editItemAt(i);
        if (memento.deviceId == entry->deviceId
@@ -3867,7 +3937,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*

void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
        Allocator* allocator, Vector<EventEntry*>& outEvents,
        CancelationOptions options) {
        const CancelationOptions& options) {
    for (size_t i = 0; i < mKeyMementos.size(); ) {
        const KeyMemento& memento = mKeyMementos.itemAt(i);
        if (shouldCancelKey(memento, options)) {
@@ -3902,6 +3972,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim
void InputDispatcher::InputState::clear() {
    mKeyMementos.clear();
    mMotionMementos.clear();
    mFallbackKeys.clear();
}

void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
@@ -3922,13 +3993,36 @@ void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
    }
}

int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) {
    ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
    return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
}

void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode,
        int32_t fallbackKeyCode) {
    ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
    if (index >= 0) {
        mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
    } else {
        mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
    }
}

void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) {
    mFallbackKeys.removeItem(originalKeyCode);
}

bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
        CancelationOptions options) {
    switch (options) {
    case CANCEL_ALL_EVENTS:
    case CANCEL_NON_POINTER_EVENTS:
        const CancelationOptions& options) {
    if (options.keyCode != -1 && memento.keyCode != options.keyCode) {
        return false;
    }

    switch (options.mode) {
    case CancelationOptions::CANCEL_ALL_EVENTS:
    case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
        return true;
    case CANCEL_FALLBACK_EVENTS:
    case CancelationOptions::CANCEL_FALLBACK_EVENTS:
        return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
    default:
        return false;
@@ -3936,13 +4030,13 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
}

bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
        CancelationOptions options) {
    switch (options) {
    case CANCEL_ALL_EVENTS:
        const CancelationOptions& options) {
    switch (options.mode) {
    case CancelationOptions::CANCEL_ALL_EVENTS:
        return true;
    case CANCEL_POINTER_EVENTS:
    case CancelationOptions::CANCEL_POINTER_EVENTS:
        return memento.source & AINPUT_SOURCE_CLASS_POINTER;
    case CANCEL_NON_POINTER_EVENTS:
    case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
        return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
    default:
        return false;
@@ -3956,8 +4050,7 @@ InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle) :
        status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
        inputPublisher(inputChannel),
        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX),
        originalKeyCodeForFallback(-1) {
        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
}

InputDispatcher::Connection::~Connection() {