summaryrefslogtreecommitdiffstats
path: root/services/input/InputDispatcher.cpp
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-06-08 15:37:10 -0700
committerJeff Brown <jeffbrown@google.com>2011-06-13 18:05:18 -0700
commit98db5fabdad86dca379740d8050697950b9f026c (patch)
treed73d51bed473f165d74eb6cac1aee571fce3b183 /services/input/InputDispatcher.cpp
parentb3a2d1330716812784aee91b6d6275764b5e4210 (diff)
downloadframeworks_base-98db5fabdad86dca379740d8050697950b9f026c.zip
frameworks_base-98db5fabdad86dca379740d8050697950b9f026c.tar.gz
frameworks_base-98db5fabdad86dca379740d8050697950b9f026c.tar.bz2
Allow touches to slide out of the navigation bar.
Change-Id: I73cabba3d62f47829bf6217700ace56a27c42b1d
Diffstat (limited to 'services/input/InputDispatcher.cpp')
-rw-r--r--services/input/InputDispatcher.cpp81
1 files changed, 77 insertions, 4 deletions
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index eff65c2..28df3fb 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -1412,6 +1412,50 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
+
+ // Check whether touches should slip outside of the current foreground window.
+ if (maskedAction == AMOTION_EVENT_ACTION_MOVE
+ && entry->pointerCount == 1
+ && mTempTouchState.isSlippery()) {
+ const MotionSample* sample = &entry->firstSample;
+ int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
+ int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+
+ const InputWindow* oldTouchedWindow = mTempTouchState.getFirstForegroundWindow();
+ const InputWindow* newTouchedWindow = findTouchedWindowAtLocked(x, y);
+ if (oldTouchedWindow != newTouchedWindow && newTouchedWindow) {
+#if DEBUG_FOCUS
+ LOGD("Touch is slipping out of window %s into window %s.",
+ oldTouchedWindow->name.string(), newTouchedWindow->name.string());
+#endif
+ // Make a slippery exit from the old window.
+ mTempTouchState.addOrUpdateWindow(oldTouchedWindow,
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
+
+ // Make a slippery entrance into the new window.
+ if (newTouchedWindow->supportsSplitTouch()) {
+ isSplit = true;
+ }
+
+ int32_t targetFlags = InputTarget::FLAG_FOREGROUND
+ | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
+ if (isSplit) {
+ targetFlags |= InputTarget::FLAG_SPLIT;
+ }
+ if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ }
+
+ BitSet32 pointerIds;
+ if (isSplit) {
+ pointerIds.markBit(entry->pointerProperties[0].id);
+ }
+ mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+
+ // Split the batch here so we send exactly one sample.
+ *outSplitBatchAfterSample = &entry->firstSample;
+ }
+ }
}
if (newHoverWindow != mLastHoverWindow) {
@@ -1884,6 +1928,10 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
@@ -1985,6 +2033,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
action = AMOTION_EVENT_ACTION_HOVER_EXIT;
} else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
action = AMOTION_EVENT_ACTION_HOVER_ENTER;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
+ action = AMOTION_EVENT_ACTION_CANCEL;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
+ action = AMOTION_EVENT_ACTION_DOWN;
}
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -4386,6 +4438,9 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
TouchedWindow& touchedWindow = windows.editItemAt(i);
if (touchedWindow.window == window) {
touchedWindow.targetFlags |= targetFlags;
+ if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
+ touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
+ }
touchedWindow.pointerIds.value |= pointerIds.value;
return;
}
@@ -4403,7 +4458,8 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0 ; i < windows.size(); ) {
TouchedWindow& window = windows.editItemAt(i);
- if (window.targetFlags & InputTarget::FLAG_DISPATCH_AS_IS) {
+ if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS
+ | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
i += 1;
@@ -4413,15 +4469,32 @@ void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
}
}
-const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() {
+const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() const {
for (size_t i = 0; i < windows.size(); i++) {
- if (windows[i].targetFlags & InputTarget::FLAG_FOREGROUND) {
- return windows[i].window;
+ const TouchedWindow& window = windows.itemAt(i);
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ return window.window;
}
}
return NULL;
}
+bool InputDispatcher::TouchState::isSlippery() const {
+ // Must have exactly one foreground window.
+ bool haveSlipperyForegroundWindow = false;
+ for (size_t i = 0; i < windows.size(); i++) {
+ const TouchedWindow& window = windows.itemAt(i);
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (haveSlipperyForegroundWindow
+ || !(window.window->layoutParamsFlags & InputWindow::FLAG_SLIPPERY)) {
+ return false;
+ }
+ haveSlipperyForegroundWindow = true;
+ }
+ }
+ return haveSlipperyForegroundWindow;
+}
+
// --- InputDispatcherThread ---