diff options
-rw-r--r-- | core/java/android/view/KeyCharacterMap.java | 55 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 29 | ||||
-rw-r--r-- | include/androidfw/Input.h | 2 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 103 | ||||
-rw-r--r-- | services/input/InputDispatcher.cpp | 40 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 3 |
6 files changed, 158 insertions, 74 deletions
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index 5b371eb..2cb724f 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -386,19 +386,19 @@ public class KeyCharacterMap implements Parcelable { * * @param keyCode The key code. * @param metaState The meta key modifier state. - * @param outFallbackAction The fallback action object to populate. - * @return True if a fallback action was found, false otherwise. + * @return The fallback action, or null if none. Remember to recycle the fallback action. * * @hide */ - public boolean getFallbackAction(int keyCode, int metaState, - FallbackAction outFallbackAction) { - if (outFallbackAction == null) { - throw new IllegalArgumentException("fallbackAction must not be null"); - } - + public FallbackAction getFallbackAction(int keyCode, int metaState) { + FallbackAction action = FallbackAction.obtain(); metaState = KeyEvent.normalizeMetaState(metaState); - return nativeGetFallbackAction(mPtr, keyCode, metaState, outFallbackAction); + if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) { + action.metaState = KeyEvent.normalizeMetaState(action.metaState); + return action; + } + action.recycle(); + return null; } /** @@ -727,7 +727,44 @@ public class KeyCharacterMap implements Parcelable { * @hide */ public static final class FallbackAction { + private static final int MAX_RECYCLED = 10; + private static final Object sRecycleLock = new Object(); + private static FallbackAction sRecycleBin; + private static int sRecycledCount; + + private FallbackAction next; + public int keyCode; public int metaState; + + private FallbackAction() { + } + + public static FallbackAction obtain() { + final FallbackAction target; + synchronized (sRecycleLock) { + if (sRecycleBin == null) { + target = new FallbackAction(); + } else { + target = sRecycleBin; + sRecycleBin = target.next; + sRecycledCount--; + target.next = null; + } + } + return target; + } + + public void recycle() { + synchronized (sRecycleLock) { + if (sRecycledCount < MAX_RECYCLED) { + next = sRecycleBin; + sRecycleBin = this; + sRecycledCount += 1; + } else { + next = null; + } + } + } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ec6bd81..e782f71 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -328,8 +328,6 @@ public final class ViewRootImpl implements ViewParent, private final int mDensity; - final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction(); - /** * Consistency verifier for debugging purposes. */ @@ -4446,20 +4444,19 @@ public final class ViewRootImpl implements ViewParent, final int keyCode = event.getKeyCode(); final int metaState = event.getMetaState(); - KeyEvent fallbackEvent = null; - synchronized (mFallbackAction) { - // Check for fallback actions specified by the key character map. - if (kcm.getFallbackAction(keyCode, metaState, mFallbackAction)) { - int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; - fallbackEvent = KeyEvent.obtain( - event.getDownTime(), event.getEventTime(), - event.getAction(), mFallbackAction.keyCode, - event.getRepeatCount(), mFallbackAction.metaState, - event.getDeviceId(), event.getScanCode(), - flags, event.getSource(), null); - } - } - if (fallbackEvent != null) { + // Check for fallback actions specified by the key character map. + KeyCharacterMap.FallbackAction fallbackAction = + kcm.getFallbackAction(keyCode, metaState); + if (fallbackAction != null) { + final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; + KeyEvent fallbackEvent = KeyEvent.obtain( + event.getDownTime(), event.getEventTime(), + event.getAction(), fallbackAction.keyCode, + event.getRepeatCount(), fallbackAction.metaState, + event.getDeviceId(), event.getScanCode(), + flags, event.getSource(), null); + fallbackAction.recycle(); + dispatchKey(fallbackEvent); } } diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h index 601a169..6d03fd6 100644 --- a/include/androidfw/Input.h +++ b/include/androidfw/Input.h @@ -262,6 +262,8 @@ public: inline int32_t getFlags() const { return mFlags; } + inline void setFlags(int32_t flags) { mFlags = flags; } + inline int32_t getKeyCode() const { return mKeyCode; } inline int32_t getScanCode() const { return mScanCode; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 6348d37..794ed15 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -463,8 +463,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent mHomeIntent; Intent mCarDockIntent; Intent mDeskDockIntent; - int mShortcutKeyPressed = -1; - boolean mConsumeShortcutKeyUp; + boolean mSearchKeyShortcutPending; + boolean mConsumeSearchKeyUp; // support for activating the lock screen while the screen is on boolean mAllowLockscreenWhenOn; @@ -509,7 +509,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; - final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction(); + // Fallback actions by key code. + private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions = + new SparseArray<KeyCharacterMap.FallbackAction>(); private static final int MSG_ENABLE_POINTER_LOCATION = 1; private static final int MSG_DISABLE_POINTER_LOCATION = 2; @@ -1709,7 +1711,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (false) { Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount=" - + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); + + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed + + " canceled=" + canceled); } // If we think we might have a volume down & power key chord on the way @@ -1842,13 +1845,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (keyCode == KeyEvent.KEYCODE_SEARCH) { if (down) { if (repeatCount == 0) { - mShortcutKeyPressed = keyCode; - mConsumeShortcutKeyUp = false; + mSearchKeyShortcutPending = true; + mConsumeSearchKeyUp = false; } - } else if (keyCode == mShortcutKeyPressed) { - mShortcutKeyPressed = -1; - if (mConsumeShortcutKeyUp) { - mConsumeShortcutKeyUp = false; + } else { + mSearchKeyShortcutPending = false; + if (mConsumeSearchKeyUp) { + mConsumeSearchKeyUp = false; return -1; } } @@ -1865,10 +1868,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // even if no shortcut was invoked. This prevents text from being // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. - if (mShortcutKeyPressed != -1) { + if (mSearchKeyShortcutPending) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { - mConsumeShortcutKeyUp = true; + mConsumeSearchKeyUp = true; + mSearchKeyShortcutPending = false; if (down && repeatCount == 0 && !keyguardOn) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { @@ -1878,13 +1882,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " - + KeyEvent.keyCodeToString(mShortcutKeyPressed) - + "+" + KeyEvent.keyCodeToString(keyCode), ex); + + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex); } } else { Slog.i(TAG, "Dropping unregistered shortcut key combination: " - + KeyEvent.keyCodeToString(mShortcutKeyPressed) - + "+" + KeyEvent.keyCodeToString(keyCode)); + + "SEARCH+" + KeyEvent.keyCodeToString(keyCode)); } } return -1; @@ -1964,51 +1966,70 @@ public class PhoneWindowManager implements WindowManagerPolicy { + ", policyFlags=" + policyFlags); } + KeyEvent fallbackEvent = null; if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); final int keyCode = event.getKeyCode(); final int metaState = event.getMetaState(); + final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN + && event.getRepeatCount() == 0; // Check for fallback actions specified by the key character map. - if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) { + final FallbackAction fallbackAction; + if (initialDown) { + fallbackAction = kcm.getFallbackAction(keyCode, metaState); + } else { + fallbackAction = mFallbackActions.get(keyCode); + } + + if (fallbackAction != null) { if (DEBUG_FALLBACK) { - Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode - + " metaState=" + Integer.toHexString(mFallbackAction.metaState)); + Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode + + " metaState=" + Integer.toHexString(fallbackAction.metaState)); } - int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; - KeyEvent fallbackEvent = KeyEvent.obtain( + final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; + fallbackEvent = KeyEvent.obtain( event.getDownTime(), event.getEventTime(), - event.getAction(), mFallbackAction.keyCode, - event.getRepeatCount(), mFallbackAction.metaState, + event.getAction(), fallbackAction.keyCode, + event.getRepeatCount(), fallbackAction.metaState, event.getDeviceId(), event.getScanCode(), flags, event.getSource(), null); - int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true); - if ((actions & ACTION_PASS_TO_USER) != 0) { - long delayMillis = interceptKeyBeforeDispatching( - win, fallbackEvent, policyFlags); - if (delayMillis == 0) { - if (DEBUG_FALLBACK) { - Slog.d(TAG, "Performing fallback."); - } - return fallbackEvent; - } + + if (!interceptFallback(win, fallbackEvent, policyFlags)) { + fallbackEvent.recycle(); + fallbackEvent = null; + } + + if (initialDown) { + mFallbackActions.put(keyCode, fallbackAction); + } else if (event.getAction() == KeyEvent.ACTION_UP) { + mFallbackActions.remove(keyCode); + fallbackAction.recycle(); } - fallbackEvent.recycle(); } } if (DEBUG_FALLBACK) { - Slog.d(TAG, "No fallback."); + if (fallbackEvent == null) { + Slog.d(TAG, "No fallback."); + } else { + Slog.d(TAG, "Performing fallback: " + fallbackEvent); + } } - return null; + return fallbackEvent; } - private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState, - FallbackAction outFallbackAction) { - // Consult the key character map for specific fallback actions. - // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed. - return kcm.getFallbackAction(keyCode, metaState, outFallbackAction); + private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) { + int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true); + if ((actions & ACTION_PASS_TO_USER) != 0) { + long delayMillis = interceptKeyBeforeDispatching( + win, fallbackEvent, policyFlags); + if (delayMillis == 0) { + return true; + } + } + return false; } /** diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index ada9d9e..1062d68 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -3354,6 +3354,25 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // generated a fallback or if the window is not a foreground window, // then cancel the associated fallback key, if any. if (fallbackKeyCode != -1) { + // Dispatch the unhandled key to the policy with the cancel flag. +#if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Unhandled key event: Asking policy to cancel fallback action. " + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); +#endif + KeyEvent event; + initializeKeyEvent(&event, keyEntry); + event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); + + mLock.unlock(); + + mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, + &event, keyEntry->policyFlags, &event); + + mLock.lock(); + + // Cancel the fallback key. if (fallbackKeyCode != AKEYCODE_UNKNOWN) { CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "application handled the original non-fallback key " @@ -3374,8 +3393,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("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); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + originalKeyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif return false; } @@ -3383,8 +3403,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); @@ -3426,7 +3447,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con "to send %d instead. Fallback canceled.", event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { - ALOGD("Unhandled key event: Policy did not request fallback for %d," + ALOGD("Unhandled key event: Policy did not request fallback for %d, " "but on the DOWN it had requested to send %d. " "Fallback canceled.", originalKeyCode, fallbackKeyCode); @@ -3903,8 +3924,10 @@ void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t f memento.source = entry->source; memento.keyCode = entry->keyCode; memento.scanCode = entry->scanCode; + memento.metaState = entry->metaState; memento.flags = flags; memento.downTime = entry->downTime; + memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, @@ -3919,6 +3942,7 @@ void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, memento.downTime = entry->downTime; memento.setPointers(entry); memento.hovering = hovering; + memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { @@ -3935,9 +3959,9 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim const KeyMemento& memento = mKeyMementos.itemAt(i); if (shouldCancelKey(memento, options)) { outEvents.push(new KeyEntry(currentTime, - memento.deviceId, memento.source, 0, + memento.deviceId, memento.source, memento.policyFlags, AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); + memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); } } @@ -3945,7 +3969,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim const MotionMemento& memento = mMotionMementos.itemAt(i); if (shouldCancelMotion(memento, options)) { outEvents.push(new MotionEntry(currentTime, - memento.deviceId, memento.source, 0, + memento.deviceId, memento.source, memento.policyFlags, memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 07ca9d5..06b8d64 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -732,8 +732,10 @@ private: uint32_t source; int32_t keyCode; int32_t scanCode; + int32_t metaState; int32_t flags; nsecs_t downTime; + uint32_t policyFlags; }; struct MotionMemento { @@ -747,6 +749,7 @@ private: PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; bool hovering; + uint32_t policyFlags; void setPointers(const MotionEntry* entry); }; |