am 36001a9f
: Merge "Support chorded fallback keys. (DO NOT MERGE)" into honeycomb-mr2
* commit '36001a9f48a1ff70504db4d2d8039f4a5f385caa': Support chorded fallback keys. (DO NOT MERGE)
This commit is contained in:
@ -643,10 +643,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
* Create (if necessary) and launch the recent apps dialog
|
* Create (if necessary) and launch the recent apps dialog
|
||||||
*/
|
*/
|
||||||
void showRecentAppsDialog() {
|
void showRecentAppsDialog() {
|
||||||
if (mRecentAppsDialog == null) {
|
mHandler.post(new Runnable() {
|
||||||
mRecentAppsDialog = new RecentApplicationsDialog(mContext);
|
@Override
|
||||||
}
|
public void run() {
|
||||||
mRecentAppsDialog.show();
|
if (mRecentAppsDialog == null) {
|
||||||
|
mRecentAppsDialog = new RecentApplicationsDialog(mContext);
|
||||||
|
}
|
||||||
|
mRecentAppsDialog.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@ -1427,7 +1432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
|
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
|
||||||
if (!down) {
|
if (down && repeatCount == 0) {
|
||||||
showRecentAppsDialog();
|
showRecentAppsDialog();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -565,18 +565,19 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (entry->type) {
|
switch (entry->type) {
|
||||||
case EventEntry::TYPE_KEY:
|
case EventEntry::TYPE_KEY: {
|
||||||
synthesizeCancelationEventsForAllConnectionsLocked(
|
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
|
||||||
InputState::CANCEL_NON_POINTER_EVENTS, reason);
|
synthesizeCancelationEventsForAllConnectionsLocked(options);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case EventEntry::TYPE_MOTION: {
|
case EventEntry::TYPE_MOTION: {
|
||||||
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
|
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
|
||||||
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
|
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
|
||||||
synthesizeCancelationEventsForAllConnectionsLocked(
|
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);
|
||||||
InputState::CANCEL_POINTER_EVENTS, reason);
|
synthesizeCancelationEventsForAllConnectionsLocked(options);
|
||||||
} else {
|
} else {
|
||||||
synthesizeCancelationEventsForAllConnectionsLocked(
|
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);
|
||||||
InputState::CANCEL_NON_POINTER_EVENTS, reason);
|
synthesizeCancelationEventsForAllConnectionsLocked(options);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -869,8 +870,9 @@ bool InputDispatcher::dispatchMotionLocked(
|
|||||||
|
|
||||||
// Dispatch the motion.
|
// Dispatch the motion.
|
||||||
if (conflictingPointerActions) {
|
if (conflictingPointerActions) {
|
||||||
synthesizeCancelationEventsForAllConnectionsLocked(
|
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
|
||||||
InputState::CANCEL_POINTER_EVENTS, "Conflicting pointer actions.");
|
"conflicting pointer actions");
|
||||||
|
synthesizeCancelationEventsForAllConnectionsLocked(options);
|
||||||
}
|
}
|
||||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||||
return true;
|
return true;
|
||||||
@ -1036,9 +1038,9 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout
|
|||||||
if (connectionIndex >= 0) {
|
if (connectionIndex >= 0) {
|
||||||
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
|
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
|
||||||
if (connection->status == Connection::STATUS_NORMAL) {
|
if (connection->status == Connection::STATUS_NORMAL) {
|
||||||
synthesizeCancelationEventsForConnectionLocked(
|
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
|
||||||
connection, InputState::CANCEL_ALL_EVENTS,
|
|
||||||
"application not responding");
|
"application not responding");
|
||||||
|
synthesizeCancelationEventsForConnectionLocked(connection, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2080,26 +2082,24 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
|
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
|
||||||
InputState::CancelationOptions options, const char* reason) {
|
const CancelationOptions& options) {
|
||||||
for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
|
for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
|
||||||
synthesizeCancelationEventsForConnectionLocked(
|
synthesizeCancelationEventsForConnectionLocked(
|
||||||
mConnectionsByReceiveFd.valueAt(i), options, reason);
|
mConnectionsByReceiveFd.valueAt(i), options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
|
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
|
||||||
const sp<InputChannel>& channel, InputState::CancelationOptions options,
|
const sp<InputChannel>& channel, const CancelationOptions& options) {
|
||||||
const char* reason) {
|
|
||||||
ssize_t index = getConnectionIndexLocked(channel);
|
ssize_t index = getConnectionIndexLocked(channel);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
synthesizeCancelationEventsForConnectionLocked(
|
synthesizeCancelationEventsForConnectionLocked(
|
||||||
mConnectionsByReceiveFd.valueAt(index), options, reason);
|
mConnectionsByReceiveFd.valueAt(index), options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
|
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
|
||||||
const sp<Connection>& connection, InputState::CancelationOptions options,
|
const sp<Connection>& connection, const CancelationOptions& options) {
|
||||||
const char* reason) {
|
|
||||||
nsecs_t currentTime = now();
|
nsecs_t currentTime = now();
|
||||||
|
|
||||||
mTempCancelationEvents.clear();
|
mTempCancelationEvents.clear();
|
||||||
@ -2110,8 +2110,9 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
|
|||||||
&& connection->status != Connection::STATUS_BROKEN) {
|
&& connection->status != Connection::STATUS_BROKEN) {
|
||||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||||
LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
|
LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
|
||||||
"with reality: %s, options=%d.",
|
"with reality: %s, mode=%d.",
|
||||||
connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
|
connection->getInputChannelName(), mTempCancelationEvents.size(),
|
||||||
|
options.reason, options.mode);
|
||||||
#endif
|
#endif
|
||||||
for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
|
for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
|
||||||
EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
|
EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
|
||||||
@ -2751,8 +2752,9 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
|
|||||||
LOGD("Focus left window: %s",
|
LOGD("Focus left window: %s",
|
||||||
oldFocusedWindowChannel->getName().string());
|
oldFocusedWindowChannel->getName().string());
|
||||||
#endif
|
#endif
|
||||||
synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
|
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
|
||||||
InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
|
"focus left window");
|
||||||
|
synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
|
||||||
oldFocusedWindowChannel.clear();
|
oldFocusedWindowChannel.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2773,8 +2775,9 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
|
|||||||
#if DEBUG_FOCUS
|
#if DEBUG_FOCUS
|
||||||
LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
|
LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
|
||||||
#endif
|
#endif
|
||||||
synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
|
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
|
||||||
InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
|
"touched window was removed");
|
||||||
|
synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
|
||||||
mTouchState.windows.removeAt(i);
|
mTouchState.windows.removeAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2910,9 +2913,9 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
|
|||||||
sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
|
sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
|
||||||
|
|
||||||
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
|
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
|
||||||
synthesizeCancelationEventsForConnectionLocked(fromConnection,
|
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
|
||||||
InputState::CANCEL_POINTER_EVENTS,
|
|
||||||
"transferring touch focus from this window to another window");
|
"transferring touch focus from this window to another window");
|
||||||
|
synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_FOCUS
|
#if DEBUG_FOCUS
|
||||||
@ -2930,7 +2933,8 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
|
|||||||
LOGD("Resetting and dropping all events (%s).", reason);
|
LOGD("Resetting and dropping all events (%s).", reason);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
synthesizeCancelationEventsForAllConnectionsLocked(InputState::CANCEL_ALL_EVENTS, reason);
|
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason);
|
||||||
|
synthesizeCancelationEventsForAllConnectionsLocked(options);
|
||||||
|
|
||||||
resetKeyRepeatLocked();
|
resetKeyRepeatLocked();
|
||||||
releasePendingEventLocked();
|
releasePendingEventLocked();
|
||||||
@ -3261,58 +3265,49 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
|
|||||||
if (!connection->outboundQueue.isEmpty()) {
|
if (!connection->outboundQueue.isEmpty()) {
|
||||||
DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
|
DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
|
||||||
if (dispatchEntry->inProgress
|
if (dispatchEntry->inProgress
|
||||||
&& dispatchEntry->hasForegroundTarget()
|
|
||||||
&& dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
|
&& dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
|
||||||
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
|
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
|
||||||
if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
|
if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
|
||||||
if (handled) {
|
// Get the fallback key state.
|
||||||
// If the application handled a non-fallback key, then immediately
|
// Clear it out after dispatching the UP.
|
||||||
// cancel all fallback keys previously dispatched to the application.
|
int32_t originalKeyCode = keyEntry->keyCode;
|
||||||
// This behavior will prevent chording with fallback keys (so they cannot
|
int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
|
||||||
// be used as modifiers) but it will ensure that fallback keys do not
|
if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
|
||||||
// get stuck. This takes care of the case where the application does not handle
|
connection->inputState.removeFallbackKey(originalKeyCode);
|
||||||
// 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,
|
if (handled || !dispatchEntry->hasForegroundTarget()) {
|
||||||
InputState::CANCEL_FALLBACK_EVENTS,
|
// If the application handles the original key for which we previously
|
||||||
"application handled a non-fallback event, "
|
// generated a fallback or if the window is not a foreground window,
|
||||||
"canceling all fallback events");
|
// then cancel the associated fallback key, if any.
|
||||||
connection->originalKeyCodeForFallback = -1;
|
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 {
|
} else {
|
||||||
// If the application did not handle a non-fallback key, first check
|
// 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
|
// that we are in a good state to perform unhandled key event processing
|
||||||
// the policy what to do with it.
|
// Then ask the policy what to do with it.
|
||||||
if (connection->originalKeyCodeForFallback < 0) {
|
bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN
|
||||||
if (keyEntry->action != AKEY_EVENT_ACTION_DOWN
|
&& keyEntry->repeatCount == 0;
|
||||||
|| keyEntry->repeatCount != 0) {
|
if (fallbackKeyCode == -1 && !initialDown) {
|
||||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||||
LOGD("Unhandled key event: Skipping fallback since this "
|
LOGD("Unhandled key event: Skipping unhandled key event processing "
|
||||||
"is not an initial down. "
|
"since this is not an initial down. "
|
||||||
"keyCode=%d, action=%d, repeatCount=%d",
|
"keyCode=%d, action=%d, repeatCount=%d",
|
||||||
keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
|
originalKeyCode, keyEntry->action, keyEntry->repeatCount);
|
||||||
#endif
|
#endif
|
||||||
goto SkipFallback;
|
goto SkipFallback;
|
||||||
}
|
|
||||||
|
|
||||||
// Start handling the fallback key on DOWN.
|
|
||||||
connection->originalKeyCodeForFallback = keyEntry->keyCode;
|
|
||||||
} else {
|
|
||||||
if (keyEntry->keyCode != connection->originalKeyCodeForFallback) {
|
|
||||||
#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);
|
|
||||||
#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
|
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||||
LOGD("Unhandled key event: Asking policy to perform fallback action. "
|
LOGD("Unhandled key event: Asking policy to perform fallback action. "
|
||||||
"keyCode=%d, action=%d, repeatCount=%d",
|
"keyCode=%d, action=%d, repeatCount=%d",
|
||||||
@ -3329,18 +3324,78 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
|
|||||||
mLock.lock();
|
mLock.lock();
|
||||||
|
|
||||||
if (connection->status != Connection::STATUS_NORMAL) {
|
if (connection->status != Connection::STATUS_NORMAL) {
|
||||||
|
connection->inputState.removeFallbackKey(originalKeyCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(connection->outboundQueue.headSentinel.next == dispatchEntry);
|
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) {
|
if (fallback) {
|
||||||
// Restart the dispatch cycle using the fallback key.
|
// Restart the dispatch cycle using the fallback key.
|
||||||
keyEntry->eventTime = event.getEventTime();
|
keyEntry->eventTime = event.getEventTime();
|
||||||
keyEntry->deviceId = event.getDeviceId();
|
keyEntry->deviceId = event.getDeviceId();
|
||||||
keyEntry->source = event.getSource();
|
keyEntry->source = event.getSource();
|
||||||
keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
|
keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
|
||||||
keyEntry->keyCode = event.getKeyCode();
|
keyEntry->keyCode = fallbackKeyCode;
|
||||||
keyEntry->scanCode = event.getScanCode();
|
keyEntry->scanCode = event.getScanCode();
|
||||||
keyEntry->metaState = event.getMetaState();
|
keyEntry->metaState = event.getMetaState();
|
||||||
keyEntry->repeatCount = event.getRepeatCount();
|
keyEntry->repeatCount = event.getRepeatCount();
|
||||||
@ -3349,13 +3404,17 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
|
|||||||
|
|
||||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||||
LOGD("Unhandled key event: Dispatching fallback key. "
|
LOGD("Unhandled key event: Dispatching fallback key. "
|
||||||
"fallbackKeyCode=%d, fallbackMetaState=%08x",
|
"originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
|
||||||
keyEntry->keyCode, keyEntry->metaState);
|
originalKeyCode, fallbackKeyCode, keyEntry->metaState);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dispatchEntry->inProgress = false;
|
dispatchEntry->inProgress = false;
|
||||||
startDispatchCycleLocked(now(), connection);
|
startDispatchCycleLocked(now(), connection);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||||
|
LOGD("Unhandled key event: No fallback key.");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3649,6 +3708,17 @@ void InputDispatcher::InputState::trackEvent(
|
|||||||
void InputDispatcher::InputState::trackKey(
|
void InputDispatcher::InputState::trackKey(
|
||||||
const KeyEntry* entry) {
|
const KeyEntry* entry) {
|
||||||
int32_t action = entry->action;
|
int32_t action = entry->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++) {
|
for (size_t i = 0; i < mKeyMementos.size(); i++) {
|
||||||
KeyMemento& memento = mKeyMementos.editItemAt(i);
|
KeyMemento& memento = mKeyMementos.editItemAt(i);
|
||||||
if (memento.deviceId == entry->deviceId
|
if (memento.deviceId == entry->deviceId
|
||||||
@ -3736,7 +3806,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*
|
|||||||
|
|
||||||
void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
|
void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
|
||||||
Allocator* allocator, Vector<EventEntry*>& outEvents,
|
Allocator* allocator, Vector<EventEntry*>& outEvents,
|
||||||
CancelationOptions options) {
|
const CancelationOptions& options) {
|
||||||
for (size_t i = 0; i < mKeyMementos.size(); ) {
|
for (size_t i = 0; i < mKeyMementos.size(); ) {
|
||||||
const KeyMemento& memento = mKeyMementos.itemAt(i);
|
const KeyMemento& memento = mKeyMementos.itemAt(i);
|
||||||
if (shouldCancelKey(memento, options)) {
|
if (shouldCancelKey(memento, options)) {
|
||||||
@ -3768,6 +3838,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim
|
|||||||
void InputDispatcher::InputState::clear() {
|
void InputDispatcher::InputState::clear() {
|
||||||
mKeyMementos.clear();
|
mKeyMementos.clear();
|
||||||
mMotionMementos.clear();
|
mMotionMementos.clear();
|
||||||
|
mFallbackKeys.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
|
void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
|
||||||
@ -3788,13 +3859,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,
|
bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
|
||||||
CancelationOptions options) {
|
const CancelationOptions& options) {
|
||||||
switch (options) {
|
if (options.keyCode != -1 && memento.keyCode != options.keyCode) {
|
||||||
case CANCEL_ALL_EVENTS:
|
return false;
|
||||||
case CANCEL_NON_POINTER_EVENTS:
|
}
|
||||||
|
|
||||||
|
switch (options.mode) {
|
||||||
|
case CancelationOptions::CANCEL_ALL_EVENTS:
|
||||||
|
case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
|
||||||
return true;
|
return true;
|
||||||
case CANCEL_FALLBACK_EVENTS:
|
case CancelationOptions::CANCEL_FALLBACK_EVENTS:
|
||||||
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
|
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -3802,13 +3896,13 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
|
bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
|
||||||
CancelationOptions options) {
|
const CancelationOptions& options) {
|
||||||
switch (options) {
|
switch (options.mode) {
|
||||||
case CANCEL_ALL_EVENTS:
|
case CancelationOptions::CANCEL_ALL_EVENTS:
|
||||||
return true;
|
return true;
|
||||||
case CANCEL_POINTER_EVENTS:
|
case CancelationOptions::CANCEL_POINTER_EVENTS:
|
||||||
return memento.source & AINPUT_SOURCE_CLASS_POINTER;
|
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);
|
return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -3822,8 +3916,7 @@ InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
|
|||||||
const sp<InputWindowHandle>& inputWindowHandle) :
|
const sp<InputWindowHandle>& inputWindowHandle) :
|
||||||
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
|
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
|
||||||
inputPublisher(inputChannel),
|
inputPublisher(inputChannel),
|
||||||
lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX),
|
lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
|
||||||
originalKeyCodeForFallback(-1) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDispatcher::Connection::~Connection() {
|
InputDispatcher::Connection::~Connection() {
|
||||||
|
@ -594,18 +594,32 @@ private:
|
|||||||
void releaseEventEntryInjectionState(EventEntry* entry);
|
void releaseEventEntryInjectionState(EventEntry* entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Tracks dispatched key and motion event state so that cancelation events can be
|
/* Specifies which events are to be canceled and why. */
|
||||||
* synthesized when events are dropped. */
|
struct CancelationOptions {
|
||||||
class InputState {
|
enum Mode {
|
||||||
public:
|
|
||||||
// Specifies the sources to cancel.
|
|
||||||
enum CancelationOptions {
|
|
||||||
CANCEL_ALL_EVENTS = 0,
|
CANCEL_ALL_EVENTS = 0,
|
||||||
CANCEL_POINTER_EVENTS = 1,
|
CANCEL_POINTER_EVENTS = 1,
|
||||||
CANCEL_NON_POINTER_EVENTS = 2,
|
CANCEL_NON_POINTER_EVENTS = 2,
|
||||||
CANCEL_FALLBACK_EVENTS = 3,
|
CANCEL_FALLBACK_EVENTS = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The criterion to use to determine which events should be canceled.
|
||||||
|
Mode mode;
|
||||||
|
|
||||||
|
// Descriptive reason for the cancelation.
|
||||||
|
const char* reason;
|
||||||
|
|
||||||
|
// The specific keycode of the key event to cancel, or -1 to cancel any key event.
|
||||||
|
int32_t keyCode;
|
||||||
|
|
||||||
|
CancelationOptions(Mode mode, const char* reason) :
|
||||||
|
mode(mode), reason(reason), keyCode(-1) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Tracks dispatched key and motion event state so that cancelation events can be
|
||||||
|
* synthesized when events are dropped. */
|
||||||
|
class InputState {
|
||||||
|
public:
|
||||||
InputState();
|
InputState();
|
||||||
~InputState();
|
~InputState();
|
||||||
|
|
||||||
@ -623,7 +637,7 @@ private:
|
|||||||
|
|
||||||
// Synthesizes cancelation events for the current state and resets the tracked state.
|
// Synthesizes cancelation events for the current state and resets the tracked state.
|
||||||
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
|
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
|
||||||
Vector<EventEntry*>& outEvents, CancelationOptions options);
|
Vector<EventEntry*>& outEvents, const CancelationOptions& options);
|
||||||
|
|
||||||
// Clears the current state.
|
// Clears the current state.
|
||||||
void clear();
|
void clear();
|
||||||
@ -631,6 +645,21 @@ private:
|
|||||||
// Copies pointer-related parts of the input state to another instance.
|
// Copies pointer-related parts of the input state to another instance.
|
||||||
void copyPointerStateTo(InputState& other) const;
|
void copyPointerStateTo(InputState& other) const;
|
||||||
|
|
||||||
|
// Gets the fallback key associated with a keycode.
|
||||||
|
// Returns -1 if none.
|
||||||
|
// Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy.
|
||||||
|
int32_t getFallbackKey(int32_t originalKeyCode);
|
||||||
|
|
||||||
|
// Sets the fallback key for a particular keycode.
|
||||||
|
void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode);
|
||||||
|
|
||||||
|
// Removes the fallback key for a particular keycode.
|
||||||
|
void removeFallbackKey(int32_t originalKeyCode);
|
||||||
|
|
||||||
|
inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const {
|
||||||
|
return mFallbackKeys;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct KeyMemento {
|
struct KeyMemento {
|
||||||
int32_t deviceId;
|
int32_t deviceId;
|
||||||
@ -656,11 +685,12 @@ private:
|
|||||||
|
|
||||||
Vector<KeyMemento> mKeyMementos;
|
Vector<KeyMemento> mKeyMementos;
|
||||||
Vector<MotionMemento> mMotionMementos;
|
Vector<MotionMemento> mMotionMementos;
|
||||||
|
KeyedVector<int32_t, int32_t> mFallbackKeys;
|
||||||
|
|
||||||
static bool shouldCancelKey(const KeyMemento& memento,
|
static bool shouldCancelKey(const KeyMemento& memento,
|
||||||
CancelationOptions options);
|
const CancelationOptions& options);
|
||||||
static bool shouldCancelMotion(const MotionMemento& memento,
|
static bool shouldCancelMotion(const MotionMemento& memento,
|
||||||
CancelationOptions options);
|
const CancelationOptions& options);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Manages the dispatch state associated with a single input channel. */
|
/* Manages the dispatch state associated with a single input channel. */
|
||||||
@ -687,7 +717,6 @@ private:
|
|||||||
|
|
||||||
nsecs_t lastEventTime; // the time when the event was originally captured
|
nsecs_t lastEventTime; // the time when the event was originally captured
|
||||||
nsecs_t lastDispatchTime; // the time when the last event was dispatched
|
nsecs_t lastDispatchTime; // the time when the last event was dispatched
|
||||||
int32_t originalKeyCodeForFallback; // original keycode for fallback in progress, -1 if none
|
|
||||||
|
|
||||||
explicit Connection(const sp<InputChannel>& inputChannel,
|
explicit Connection(const sp<InputChannel>& inputChannel,
|
||||||
const sp<InputWindowHandle>& inputWindowHandle);
|
const sp<InputWindowHandle>& inputWindowHandle);
|
||||||
@ -929,11 +958,11 @@ private:
|
|||||||
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
||||||
|
|
||||||
void synthesizeCancelationEventsForAllConnectionsLocked(
|
void synthesizeCancelationEventsForAllConnectionsLocked(
|
||||||
InputState::CancelationOptions options, const char* reason);
|
const CancelationOptions& options);
|
||||||
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
|
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
|
||||||
InputState::CancelationOptions options, const char* reason);
|
const CancelationOptions& options);
|
||||||
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
|
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
|
||||||
InputState::CancelationOptions options, const char* reason);
|
const CancelationOptions& options);
|
||||||
|
|
||||||
// Splitting motion events across windows.
|
// Splitting motion events across windows.
|
||||||
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
|
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
|
||||||
|
@ -795,7 +795,9 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& input
|
|||||||
jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj,
|
jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj,
|
||||||
gCallbacksClassInfo.dispatchUnhandledKey,
|
gCallbacksClassInfo.dispatchUnhandledKey,
|
||||||
inputWindowHandleObj, keyEventObj, policyFlags);
|
inputWindowHandleObj, keyEventObj, policyFlags);
|
||||||
checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
|
if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
|
||||||
|
fallbackKeyEventObj = NULL;
|
||||||
|
}
|
||||||
android_view_KeyEvent_recycle(env, keyEventObj);
|
android_view_KeyEvent_recycle(env, keyEventObj);
|
||||||
env->DeleteLocalRef(keyEventObj);
|
env->DeleteLocalRef(keyEventObj);
|
||||||
|
|
||||||
@ -826,7 +828,9 @@ bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
|
|||||||
JNIEnv* env = jniEnv();
|
JNIEnv* env = jniEnv();
|
||||||
jboolean result = env->CallBooleanMethod(mCallbacksObj,
|
jboolean result = env->CallBooleanMethod(mCallbacksObj,
|
||||||
gCallbacksClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
|
gCallbacksClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
|
||||||
checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission");
|
if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user