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

Commit 4aee9c5f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Crop bounds sent to input by screen bounds."

parents f7dcb569 39cfa2e0
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -153,6 +153,24 @@ public:
        EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
    }

    void expectTapWithFlag(int x, int y, int32_t flags) {
        InputEvent *ev = consumeEvent();
        ASSERT_NE(ev, nullptr);
        ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
        MotionEvent *mev = static_cast<MotionEvent *>(ev);
        EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
        EXPECT_EQ(x, mev->getX(0));
        EXPECT_EQ(y, mev->getY(0));
        EXPECT_EQ(flags, mev->getFlags() & flags);

        ev = consumeEvent();
        ASSERT_NE(ev, nullptr);
        ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
        mev = static_cast<MotionEvent *>(ev);
        EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
        EXPECT_EQ(flags, mev->getFlags() & flags);
    }

    ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); }

    void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
@@ -602,4 +620,68 @@ TEST_F(InputSurfacesTest, rotate_surface_with_scale_and_insets) {
    surface->expectTap(5, 10);
}

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

    // Add non touchable window to fully cover touchable window. Window behind gets touch, but
    // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
    std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
    nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
    nonTouchableSurface->mInputInfo.ownerUid = 22222;
    nonTouchableSurface->showAt(100, 100);

    injectTap(190, 199);
    surface->expectTapWithFlag(90, 99, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED);
}

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

    // Add non touchable window to cover touchable window, but parent is cropped to not cover area
    // that will be tapped. Window behind gets touch, but with flag
    // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
    std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
    std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
    nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
    parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
    nonTouchableSurface->mInputInfo.ownerUid = 22222;
    parentSurface->mInputInfo.ownerUid = 22222;
    nonTouchableSurface->showAt(0, 0);
    parentSurface->showAt(100, 100);

    nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
        t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
        t.reparent(sc, parentSurface->mSurfaceControl);
    });

    injectTap(190, 199);
    surface->expectTapWithFlag(90, 99, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
}

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

    // Add non touchable window to cover touchable window, but parent is cropped to avoid covering
    // the touchable window. Window behind gets touch with no obscured flags.
    std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
    std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
    nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
    parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
    nonTouchableSurface->mInputInfo.ownerUid = 22222;
    parentSurface->mInputInfo.ownerUid = 22222;
    nonTouchableSurface->showAt(0, 0);
    parentSurface->showAt(50, 50);

    nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
        t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
        t.reparent(sc, parentSurface->mSurfaceControl);
    });

    injectTap(101, 110);
    surface->expectTap(1, 10);
}

} // namespace android::test
+10 −6
Original line number Diff line number Diff line
@@ -2495,12 +2495,6 @@ InputWindowInfo Layer::fillInputInfo() {
        transformedLayerBounds.bottom = tmp;
    }

    // Input coordinates should be in display coordinate space.
    info.frameLeft = transformedLayerBounds.left;
    info.frameTop = transformedLayerBounds.top;
    info.frameRight = transformedLayerBounds.right;
    info.frameBottom = transformedLayerBounds.bottom;

    // Compute the correct transform to send to input. This will allow it to transform the
    // input coordinates from display space into window space. Therefore, it needs to use the
    // final layer frame to create the inverse transform. Since surface insets are added later,
@@ -2522,6 +2516,16 @@ InputWindowInfo Layer::fillInputInfo() {
    inputTransform.set(translation.x, translation.y);
    info.transform = inputTransform.inverse();

    // We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
    // The frame should be the area the user sees on screen since it's used for occlusion
    // detection.
    Rect screenBounds = Rect{mScreenBounds};
    transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
    info.frameLeft = transformedLayerBounds.left;
    info.frameTop = transformedLayerBounds.top;
    info.frameRight = transformedLayerBounds.right;
    info.frameBottom = transformedLayerBounds.bottom;

    // Position the touchable region relative to frame screen location and restrict it to frame
    // bounds.
    info.touchableRegion = inputTransform.transform(info.touchableRegion);