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

Commit 3e234ba1 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Allow touches to slide out of the navigation bar."

parents fa779317 98db5fab
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,