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

Commit d20b2707 authored by Arthur Hung's avatar Arthur Hung
Browse files

Fix touch event would be offset by crop

SurfaceFlinger overwrite the input frame info by the layer
bounds, and the input coordinate should match the active buffer bounds.
The touch region should intersect the active buffer and screen bounds.

Bug: 120641923
Bug: 120781892
Test: atest com.android.server.wm
Test: atest libgui_test
Test: use landscape mode, split screen, touch on secondary window.
Test: create legacy application (<N), no title bar,
      window flags=FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR

Change-Id: Idc3b5bb707ce733c77ee700821bde5786594e430
parent d231c6ad
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -489,5 +489,13 @@ TEST_F(InputSurfacesTest, transfer_touch_focus) {
    toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
    fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
}

TEST_F(InputSurfacesTest, input_respects_outscreen) {
    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
    surface->showAt(-1, -1);

    injectTap(0, 0);
    surface->expectTap(1, 1);
}
}
}
+10 −12
Original line number Diff line number Diff line
@@ -2135,7 +2135,7 @@ bool Layer::isRemovedFromCurrentState() const {
    return mRemovedFromCurrentState;
}

InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
InputWindowInfo Layer::fillInputInfo() {
    InputWindowInfo info = mDrawingState.inputInfo;

    ui::Transform t = getTransform();
@@ -2148,20 +2148,18 @@ InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
    }

    // Transform layer size to screen space and inset it by surface insets.
    Rect layerBounds = getCroppedBufferSize(getDrawingState());
    Rect layerBounds = getBufferSize(getDrawingState());
    if (!layerBounds.isValid()) {
        layerBounds = getCroppedBufferSize(getDrawingState());
    }
    layerBounds = t.transform(layerBounds);
    layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset);

    // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets
    // are not set on the screen bounds directly since the surface inset region may already be
    // cropped by a parent layer.
    Rect frame;
    screenBounds.intersect(layerBounds, &frame);

    info.frameLeft = frame.left;
    info.frameTop = frame.top;
    info.frameRight = frame.right;
    info.frameBottom = frame.bottom;
    // Input coordinate should match the layer bounds.
    info.frameLeft = layerBounds.left;
    info.frameTop = layerBounds.top;
    info.frameRight = layerBounds.right;
    info.frameBottom = layerBounds.bottom;

    // Position the touchable region relative to frame screen location and restrict it to frame
    // bounds.
+1 −1
Original line number Diff line number Diff line
@@ -773,7 +773,7 @@ public:
    bool mPendingHWCDestroy{false};
    void setInputInfo(const InputWindowInfo& info);

    InputWindowInfo fillInputInfo(const Rect& screenBounds);
    InputWindowInfo fillInputInfo();
    bool hasInput() const;

protected:
+1 −2
Original line number Diff line number Diff line
@@ -2944,8 +2944,7 @@ void SurfaceFlinger::updateInputWindows() {
        if (layer->hasInput()) {
            // When calculating the screen bounds we ignore the transparent region since it may
            // result in an unwanted offset.
            inputHandles.add(layer->fillInputInfo(
                    layer->computeScreenBounds(false /* reduceTransparentRegion */)));
            inputHandles.add(layer->fillInputInfo());
        }
    });
    mInputFlinger->setInputWindows(inputHandles);