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

Commit 85b8c5ed authored by Tiger Huang's avatar Tiger Huang
Browse files

Introduce new portal window which transports touch to another display

It enables the user to directly touch on a window of a display
embedded on another one. The embedded displays can be nested.

The monitoring channels of the embedded display can also receive touch
events.

Bug: 120675821
Test: Manual test with ActivityViewTest
Test: atest -a inputflinger_tests
Test: atest CtsActivityManagerDeviceTestCases:ActivityViewTest
Change-Id: I773c7efb1b048080020aadd45156261a10095fcb
parent 6d50dff2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ struct InputWindowInfo {
    int32_t ownerUid;
    int32_t inputFeatures;
    int32_t displayId;
    int32_t portalToDisplayId = ADISPLAY_ID_NONE;
    InputApplicationInfo applicationInfo;

    void addTouchableRegion(const Rect& region);
+2 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ status_t InputWindowInfo::write(Parcel& output) const {
    output.writeInt32(ownerUid);
    output.writeInt32(inputFeatures);
    output.writeInt32(displayId);
    output.writeInt32(portalToDisplayId);
    applicationInfo.write(output);
    output.write(touchableRegion);

@@ -136,6 +137,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) {
    ret.ownerUid = from.readInt32();
    ret.inputFeatures = from.readInt32();
    ret.displayId = from.readInt32();
    ret.portalToDisplayId = from.readInt32();
    ret.applicationInfo = InputApplicationInfo::read(from);
    from.read(ret.touchableRegion);

+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ TEST(InputWindowInfo, Parcelling) {
    i.ownerUid = 24;
    i.inputFeatures = 29;
    i.displayId = 34;
    i.portalToDisplayId = 2;

    Parcel p;
    i.write(p);
@@ -90,6 +91,7 @@ TEST(InputWindowInfo, Parcelling) {
    ASSERT_EQ(i.ownerUid, i2.ownerUid);
    ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
    ASSERT_EQ(i.displayId, i2.displayId);
    ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId);
}

} // namespace test
+62 −37
Original line number Diff line number Diff line
@@ -525,7 +525,7 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
}

sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
        int32_t x, int32_t y) {
        int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {
    // Traverse windows from front to back to find touched window.
    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
    size_t numWindows = windowHandles.size();
@@ -540,10 +540,25 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display
                    bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        int32_t portalToDisplayId = windowInfo->portalToDisplayId;
                        if (portalToDisplayId != ADISPLAY_ID_NONE
                                && portalToDisplayId != displayId) {
                            if (addPortalWindows) {
                                // For the monitoring channels of the display.
                                mTempTouchState.addPortalWindow(windowHandle);
                            }
                            return findTouchedWindowAtLocked(
                                    portalToDisplayId, x, y, addOutsideTargets, addPortalWindows);
                        }
                        // Found window.
                        return windowHandle;
                    }
                }

                if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    mTempTouchState.addOrUpdateWindow(
                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
                }
            }
        }
    }
@@ -930,6 +945,22 @@ bool InputDispatcher::dispatchMotionLocked(
    // Add monitor channels from event's or focused display.
    addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));

    if (isPointerEvent) {
        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
        if (stateIndex >= 0) {
            const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
            if (!state.portalWindows.isEmpty()) {
                // The event has gone through these portal windows, so we add monitoring targets of
                // the corresponding displays as well.
                for (size_t i = 0; i < state.portalWindows.size(); i++) {
                    const InputWindowInfo* windowInfo = state.portalWindows.itemAt(i)->getInfo();
                    addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
                            -windowInfo->frameLeft, -windowInfo->frameTop);
                }
            }
        }
    }

    // Dispatch the motion.
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -1297,37 +1328,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
                getAxisValue(AMOTION_EVENT_AXIS_X));
        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
                getAxisValue(AMOTION_EVENT_AXIS_Y));
        sp<InputWindowHandle> newTouchedWindowHandle;
        bool isTouchModal = false;

        // Traverse windows from front to back to find touched window and outside targets.
        const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
        size_t numWindows = windowHandles.size();
        for (size_t i = 0; i < numWindows; i++) {
            sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
            const InputWindowInfo* windowInfo = windowHandle->getInfo();
            if (windowInfo->displayId != displayId) {
                continue; // wrong display
            }

            int32_t flags = windowInfo->layoutParamsFlags;
            if (windowInfo->visible) {
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        newTouchedWindowHandle = windowHandle;
                        break; // found touched window, exit window loop
                    }
                }

                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                        && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    mTempTouchState.addOrUpdateWindow(
                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
                }
            }
        }
        sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(
                displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true);

        // Figure out whether splitting will be allowed for this window.
        if (newTouchedWindowHandle != nullptr
@@ -1689,7 +1691,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH
}

void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
        int32_t displayId) {
        int32_t displayId, float xOffset, float yOffset) {
    std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
            mMonitoringChannelsByDisplay.find(displayId);

@@ -1702,8 +1704,8 @@ void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTarge
            InputTarget& target = inputTargets.editTop();
            target.inputChannel = monitoringChannels[i];
            target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
            target.xOffset = 0;
            target.yOffset = 0;
            target.xOffset = xOffset;
            target.yOffset = yOffset;
            target.pointerIds.clear();
            target.globalScaleFactor = 1.0f;
        }
@@ -3107,7 +3109,8 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input
            Vector<sp<InputWindowHandle>> newHandles;
            for (size_t i = 0; i < numWindows; i++) {
                const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
                if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) {
                if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr
                        && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) {
                    ALOGE("Window handle %s has no registered input channel",
                            handle->getName().c_str());
                    continue;
@@ -3542,6 +3545,14 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
            } else {
                dump += INDENT3 "Windows: <none>\n";
            }
            if (!state.portalWindows.isEmpty()) {
                dump += INDENT3 "Portal windows:\n";
                for (size_t i = 0; i < state.portalWindows.size(); i++) {
                    const sp<InputWindowHandle> portalWindowHandle = state.portalWindows.itemAt(i);
                    dump += StringPrintf(INDENT4 "%zu: name='%s'\n",
                            i, portalWindowHandle->getName().c_str());
                }
            }
        }
    } else {
        dump += INDENT "TouchStates: <no displays touched>\n";
@@ -3558,11 +3569,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
                    const InputWindowInfo* windowInfo = windowHandle->getInfo();

                    dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
                            "paused=%s, hasFocus=%s, hasWallpaper=%s, "
                            "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, "
                            "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                            "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), "
                            "touchableRegion=",
                            i, windowInfo->name.c_str(), windowInfo->displayId,
                            windowInfo->portalToDisplayId,
                            toString(windowInfo->paused),
                            toString(windowInfo->hasFocus),
                            toString(windowInfo->hasWallpaper),
@@ -4911,6 +4923,7 @@ void InputDispatcher::TouchState::reset() {
    source = 0;
    displayId = ADISPLAY_ID_NONE;
    windows.clear();
    portalWindows.clear();
}

void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
@@ -4920,6 +4933,7 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
    source = other.source;
    displayId = other.displayId;
    windows = other.windows;
    portalWindows = other.portalWindows;
}

void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
@@ -4948,6 +4962,17 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>&
    touchedWindow.pointerIds = pointerIds;
}

void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
    size_t numWindows = portalWindows.size();
    for (size_t i = 0; i < numWindows; i++) {
        sp<InputWindowHandle> portalWindowHandle = portalWindows.itemAt(i);
        if (portalWindowHandle == windowHandle) {
            return;
        }
    }
    portalWindows.push_back(windowHandle);
}

void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
    for (size_t i = 0; i < windows.size(); i++) {
        if (windows.itemAt(i).windowHandle == windowHandle) {
+10 −2
Original line number Diff line number Diff line
@@ -921,7 +921,8 @@ private:
    // to transfer focus to a new application.
    EventEntry* mNextUnblockedEvent;

    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y);
    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
            bool addOutsideTargets = false, bool addPortalWindows = false);

    // All registered connections mapped by channel file descriptor.
    KeyedVector<int, sp<Connection> > mConnectionsByFd;
@@ -1016,12 +1017,18 @@ private:
        int32_t displayId; // id to the display that currently has a touch, others are rejected
        Vector<TouchedWindow> windows;

        // This collects the portal windows that the touch has gone through. Each portal window
        // targets a display (embedded display for most cases). With this info, we can add the
        // monitoring channels of the displays touched.
        Vector<sp<InputWindowHandle>> portalWindows;

        TouchState();
        ~TouchState();
        void reset();
        void copyFrom(const TouchState& other);
        void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
                int32_t targetFlags, BitSet32 pointerIds);
        void addPortalWindow(const sp<InputWindowHandle>& windowHandle);
        void removeWindow(const sp<InputWindowHandle>& windowHandle);
        void removeWindowByToken(const sp<IBinder>& token);
        void filterNonAsIsTouchWindows();
@@ -1096,7 +1103,8 @@ private:

    void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
    void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId);
    void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
            float xOffset = 0, float yOffset = 0);

    void pokeUserActivityLocked(const EventEntry* eventEntry);
    bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
Loading