Loading core/java/android/view/WindowManager.java +13 −1 Original line number Diff line number Diff line Loading @@ -686,6 +686,18 @@ 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 Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +2 −1 Original line number Diff line number Diff line Loading @@ -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"); Loading services/input/InputDispatcher.cpp +77 −4 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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()) { Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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 --- Loading services/input/InputDispatcher.h +16 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -952,7 +964,8 @@ private: void copyFrom(const TouchState& other); void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds); void filterNonAsIsTouchWindows(); const InputWindow* getFirstForegroundWindow(); const InputWindow* getFirstForegroundWindow() const; bool isSlippery() const; }; TouchState mTouchState; Loading services/input/InputWindow.h +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading
core/java/android/view/WindowManager.java +13 −1 Original line number Diff line number Diff line Loading @@ -686,6 +686,18 @@ 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 Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +2 −1 Original line number Diff line number Diff line Loading @@ -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"); Loading
services/input/InputDispatcher.cpp +77 −4 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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()) { Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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 --- Loading
services/input/InputDispatcher.h +16 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -952,7 +964,8 @@ private: void copyFrom(const TouchState& other); void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds); void filterNonAsIsTouchWindows(); const InputWindow* getFirstForegroundWindow(); const InputWindow* getFirstForegroundWindow() const; bool isSlippery() const; }; TouchState mTouchState; Loading
services/input/InputWindow.h +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading