am 571d4cbe: Merge "Fix bugs in fallback key handling." into jb-dev

* commit '571d4cbeec4adad050b8e188770e7e7dedc558f1':
  Fix bugs in fallback key handling.
This commit is contained in:
Jeff Brown
2012-05-10 09:25:36 -07:00
committed by Android Git Automerger
6 changed files with 158 additions and 74 deletions

View File

@@ -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;
}
}
}
}
}

View File

@@ -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.
*/
@@ -4481,20 +4479,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);
}
}

View File

@@ -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; }

View File

@@ -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;
}
/**

View File

@@ -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,

View File

@@ -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);
};