summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/KeyCharacterMap.java55
-rw-r--r--core/java/android/view/ViewRootImpl.java29
-rw-r--r--include/androidfw/Input.h2
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java103
-rw-r--r--services/input/InputDispatcher.cpp40
-rw-r--r--services/input/InputDispatcher.h3
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);
};