diff options
| -rw-r--r-- | core/java/android/view/WindowManager.java | 14 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java | 3 | ||||
| -rw-r--r-- | services/input/InputDispatcher.cpp | 81 | ||||
| -rw-r--r-- | services/input/InputDispatcher.h | 19 | ||||
| -rw-r--r-- | services/input/InputWindow.h | 4 |
5 files changed, 112 insertions, 9 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index b0181bbc3de0..6b6aee3c37d0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -685,7 +685,19 @@ public interface WindowManager extends ViewManager { // ----- HIDDEN FLAGS. // These start at the high bit and go down. - + + /** Window flag: Enable touches to slide out of a window into neighboring + * windows in mid-gesture instead of being captured for the duration of + * the gesture. + * + * This flag changes the behavior of touch focus for this window only. + * Touches can slide out of the window but they cannot necessarily slide + * back in (unless the other window with touch focus permits it). + * + * {@hide} + */ + public static final int FLAG_SLIPPERY = 0x04000000; + /** * Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU} * and therefore needs a Menu key. For devices where Menu is a physical button this flag is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 3d15a1d18fc5..687de0750efd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -349,7 +349,8 @@ public class PhoneStatusBar extends StatusBar { | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); lp.setTitle("NavigationBar"); diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index eff65c2c6965..28df3fb46594 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 --- diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 39d4aeb7fb4f..676d162daaac 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -121,11 +121,23 @@ struct InputTarget { * The event is transmuted into ACTION_HOVER_ENTER. */ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, + /* This flag indicates that the event should be canceled. + * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips + * outside of a window. */ + FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, + + /* This flag indicates that the event should be dispatched as an initial down. + * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips + * into a new window. */ + FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, + /* Mask for all dispatch modes. */ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE | FLAG_DISPATCH_AS_HOVER_ENTER - | FLAG_DISPATCH_AS_HOVER_EXIT, + | FLAG_DISPATCH_AS_HOVER_EXIT + | FLAG_DISPATCH_AS_SLIPPERY_EXIT + | FLAG_DISPATCH_AS_SLIPPERY_ENTER, }; // The input channel to be targeted. @@ -950,9 +962,10 @@ private: ~TouchState(); void reset(); void copyFrom(const TouchState& other); - void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds); + void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds); void filterNonAsIsTouchWindows(); - const InputWindow* getFirstForegroundWindow(); + const InputWindow* getFirstForegroundWindow() const; + bool isSlippery() const; }; TouchState mTouchState; diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index d7d819debed8..93c9b5f268b0 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -80,6 +80,10 @@ struct InputWindow { FLAG_TURN_SCREEN_ON = 0x00200000, FLAG_DISMISS_KEYGUARD = 0x00400000, FLAG_SPLIT_TOUCH = 0x00800000, + FLAG_HARDWARE_ACCELERATED = 0x01000000, + FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000, + FLAG_SLIPPERY = 0x04000000, + FLAG_NEEDS_MENU_KEY = 0x08000000, FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, FLAG_COMPATIBLE_WINDOW = 0x20000000, FLAG_SYSTEM_ERROR = 0x40000000, |