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,12 +643,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
* Create (if necessary) and launch the recent apps dialog
|
||||
*/
|
||||
void showRecentAppsDialog() {
|
||||
if (mRecentAppsDialog == null) {
|
||||
mRecentAppsDialog = new RecentApplicationsDialog(mContext);
|
||||
}
|
||||
mRecentAppsDialog.show();
|
||||
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,
|
||||
LocalPowerManager powerManager) {
|
||||
@ -1427,7 +1432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
return false;
|
||||
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
|
||||
if (!down) {
|
||||
if (down && repeatCount == 0) {
|
||||
showRecentAppsDialog();
|
||||
}
|
||||
return true;
|
||||
|
@ -565,18 +565,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;
|
||||
}
|
||||
@ -869,8 +870,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;
|
||||
@ -1036,9 +1038,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2080,26 +2082,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();
|
||||
@ -2110,8 +2110,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);
|
||||
@ -2751,8 +2752,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();
|
||||
}
|
||||
}
|
||||
@ -2773,8 +2775,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);
|
||||
}
|
||||
}
|
||||
@ -2910,9 +2913,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
|
||||
@ -2930,7 +2933,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();
|
||||
@ -3261,58 +3265,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;
|
||||
// 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);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
// 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 this "
|
||||
"is not an initial down. "
|
||||
"keyCode=%d, action=%d, repeatCount=%d",
|
||||
keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
goto SkipFallback;
|
||||
}
|
||||
|
||||
// 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",
|
||||
@ -3329,18 +3324,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();
|
||||
@ -3349,13 +3404,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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3649,6 +3708,17 @@ void InputDispatcher::InputState::trackEvent(
|
||||
void InputDispatcher::InputState::trackKey(
|
||||
const KeyEntry* entry) {
|
||||
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++) {
|
||||
KeyMemento& memento = mKeyMementos.editItemAt(i);
|
||||
if (memento.deviceId == entry->deviceId
|
||||
@ -3736,7 +3806,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)) {
|
||||
@ -3768,6 +3838,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 {
|
||||
@ -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,
|
||||
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;
|
||||
@ -3802,13 +3896,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;
|
||||
@ -3822,8 +3916,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() {
|
||||
|
@ -594,18 +594,32 @@ private:
|
||||
void releaseEventEntryInjectionState(EventEntry* entry);
|
||||
};
|
||||
|
||||
/* Tracks dispatched key and motion event state so that cancelation events can be
|
||||
* synthesized when events are dropped. */
|
||||
class InputState {
|
||||
public:
|
||||
// Specifies the sources to cancel.
|
||||
enum CancelationOptions {
|
||||
/* Specifies which events are to be canceled and why. */
|
||||
struct CancelationOptions {
|
||||
enum Mode {
|
||||
CANCEL_ALL_EVENTS = 0,
|
||||
CANCEL_POINTER_EVENTS = 1,
|
||||
CANCEL_NON_POINTER_EVENTS = 2,
|
||||
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();
|
||||
|
||||
@ -623,7 +637,7 @@ private:
|
||||
|
||||
// Synthesizes cancelation events for the current state and resets the tracked state.
|
||||
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
|
||||
Vector<EventEntry*>& outEvents, CancelationOptions options);
|
||||
Vector<EventEntry*>& outEvents, const CancelationOptions& options);
|
||||
|
||||
// Clears the current state.
|
||||
void clear();
|
||||
@ -631,6 +645,21 @@ private:
|
||||
// Copies pointer-related parts of the input state to another instance.
|
||||
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:
|
||||
struct KeyMemento {
|
||||
int32_t deviceId;
|
||||
@ -656,11 +685,12 @@ private:
|
||||
|
||||
Vector<KeyMemento> mKeyMementos;
|
||||
Vector<MotionMemento> mMotionMementos;
|
||||
KeyedVector<int32_t, int32_t> mFallbackKeys;
|
||||
|
||||
static bool shouldCancelKey(const KeyMemento& memento,
|
||||
CancelationOptions options);
|
||||
const CancelationOptions& options);
|
||||
static bool shouldCancelMotion(const MotionMemento& memento,
|
||||
CancelationOptions options);
|
||||
const CancelationOptions& options);
|
||||
};
|
||||
|
||||
/* 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 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,
|
||||
const sp<InputWindowHandle>& inputWindowHandle);
|
||||
@ -929,11 +958,11 @@ private:
|
||||
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
||||
|
||||
void synthesizeCancelationEventsForAllConnectionsLocked(
|
||||
InputState::CancelationOptions options, const char* reason);
|
||||
const CancelationOptions& options);
|
||||
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
|
||||
InputState::CancelationOptions options, const char* reason);
|
||||
const CancelationOptions& options);
|
||||
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
|
||||
InputState::CancelationOptions options, const char* reason);
|
||||
const CancelationOptions& options);
|
||||
|
||||
// Splitting motion events across windows.
|
||||
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
|
||||
|
@ -795,7 +795,9 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& input
|
||||
jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.dispatchUnhandledKey,
|
||||
inputWindowHandleObj, keyEventObj, policyFlags);
|
||||
checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
|
||||
if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
|
||||
fallbackKeyEventObj = NULL;
|
||||
}
|
||||
android_view_KeyEvent_recycle(env, keyEventObj);
|
||||
env->DeleteLocalRef(keyEventObj);
|
||||
|
||||
@ -826,7 +828,9 @@ bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
|
||||
JNIEnv* env = jniEnv();
|
||||
jboolean result = env->CallBooleanMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
|
||||
checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission");
|
||||
if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user