Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98db5fab authored by Jeff Brown's avatar Jeff Brown
Browse files

Allow touches to slide out of the navigation bar.

Change-Id: I73cabba3d62f47829bf6217700ace56a27c42b1d
parent b3a2d133
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -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
+2 −1
Original line number Diff line number Diff line
@@ -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");
+77 −4
Original line number Diff line number Diff line
@@ -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 ---

+16 −3
Original line number Diff line number Diff line
@@ -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.
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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,