Loading libs/gui/tests/EndToEndNativeInputTest.cpp +169 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <memory> #include <android/keycodes.h> #include <android/native_window.h> #include <binder/Binder.h> Loading Loading @@ -120,8 +121,8 @@ public: return std::make_unique<InputSurface>(surfaceControl, width, height); } InputEvent* consumeEvent() { waitForEventAvailable(); InputEvent *consumeEvent(int timeoutMs = 3000) { waitForEventAvailable(timeoutMs); InputEvent *ev; uint32_t seqId; Loading Loading @@ -178,6 +179,24 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } void expectKey(uint32_t keycode) { InputEvent *ev = consumeEvent(); ASSERT_NE(ev, nullptr); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); KeyEvent *keyEvent = static_cast<KeyEvent *>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction()); EXPECT_EQ(keycode, keyEvent->getKeyCode()); EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); ev = consumeEvent(); ASSERT_NE(ev, nullptr); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); keyEvent = static_cast<KeyEvent *>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction()); EXPECT_EQ(keycode, keyEvent->getKeyCode()); EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); } virtual ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); } Loading Loading @@ -215,12 +234,12 @@ public: } private: void waitForEventAvailable() { void waitForEventAvailable(int timeoutMs) { struct pollfd fd; fd.fd = mClientChannel->getFd(); fd.events = POLLIN; poll(&fd, 1, 3000); poll(&fd, 1, timeoutMs); } void populateInputInfo(int width, int height) { Loading Loading @@ -363,6 +382,14 @@ void injectTap(int x, int y) { } } void injectKey(uint32_t keycode) { char *buf1; asprintf(&buf1, "%d", keycode); if (fork() == 0) { execlp("input", "input", "keyevent", buf1, NULL); } } TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); Loading Loading @@ -614,6 +641,9 @@ TEST_F(InputSurfacesTest, can_be_focused) { surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, rotate_surface) { Loading Loading @@ -781,4 +811,139 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { surface->expectTap(1, 1); } TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_NE(surface->consumeEvent(), nullptr); EXPECT_NE(surface->consumeEvent(), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.setMatrix(sc, 2.0, 0, 0, 2.0); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_NE(surface->consumeEvent(), nullptr); EXPECT_NE(surface->consumeEvent(), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->mInputInfo.ownerUid = 11111; surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(100, 100); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->mInputInfo.ownerUid = 11111; surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(190, 190); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) { std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.reparent(sc, parentSurface->mSurfaceControl); t.setAlpha(parentSurface->mSurfaceControl, 0.9f); }); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) { std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.reparent(sc, parentSurface->mSurfaceControl); t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100)); }); surface->showAt(100, 100); injectTap(111, 111); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, drop_input_policy) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } } // namespace android::test services/surfaceflinger/Layer.cpp +69 −0 Original line number Diff line number Diff line Loading @@ -2288,6 +2288,74 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } gui::DropInputMode Layer::getDropInputMode() const { gui::DropInputMode mode = mDrawingState.dropInputMode; if (mode == gui::DropInputMode::ALL) { return mode; } sp<Layer> parent = mDrawingParent.promote(); if (parent) { gui::DropInputMode parentMode = parent->getDropInputMode(); if (parentMode != gui::DropInputMode::NONE) { return parentMode; } } return mode; } void Layer::handleDropInputMode(gui::WindowInfo& info) const { if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { return; } // Check if we need to drop input unconditionally gui::DropInputMode dropInputMode = getDropInputMode(); if (dropInputMode == gui::DropInputMode::ALL) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy.", getDebugName()); return; } // Check if we need to check if the window is obscured by parent if (dropInputMode != gui::DropInputMode::OBSCURED) { return; } // Check if the parent has set an alpha on the layer sp<Layer> parent = mDrawingParent.promote(); if (parent && parent->getAlpha() != 1.0_hf) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast<float>(getAlpha())); } // Check if the parent has cropped the buffer Rect bufferSize = getCroppedBufferSize(getDrawingState()); if (!bufferSize.isValid()) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; return; } // Screenbounds are the layer bounds cropped by parents, transformed to screenspace. // To check if the layer has been cropped, we take the buffer bounds, apply the local // layer crop and apply the same set of transforms to move to screenspace. If the bounds // match then the layer has not been cropped by its parents. Rect bufferInScreenSpace(getTransform().transform(bufferSize)); bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; if (croppedByParent) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", getDebugName()); } else { // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop // input if the window is obscured. This check should be done in surfaceflinger but the // logic currently resides in inputflinger. So pass the if_obscured check to input to only // drop input events if the window is obscured. info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; } } WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); Loading Loading @@ -2315,6 +2383,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); info.alpha = getAlpha(); fillTouchOcclusionMode(info); handleDropInputMode(info); auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { Loading services/surfaceflinger/Layer.h +2 −0 Original line number Diff line number Diff line Loading @@ -1063,6 +1063,8 @@ private: bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp<Layer>& relativeOf); bool isTrustedOverlay() const; gui::DropInputMode getDropInputMode() const; void handleDropInputMode(gui::WindowInfo& info) const; // Find the root of the cloned hierarchy, this means the first non cloned parent. // This will return null if first non cloned parent is not found. Loading Loading
libs/gui/tests/EndToEndNativeInputTest.cpp +169 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <memory> #include <android/keycodes.h> #include <android/native_window.h> #include <binder/Binder.h> Loading Loading @@ -120,8 +121,8 @@ public: return std::make_unique<InputSurface>(surfaceControl, width, height); } InputEvent* consumeEvent() { waitForEventAvailable(); InputEvent *consumeEvent(int timeoutMs = 3000) { waitForEventAvailable(timeoutMs); InputEvent *ev; uint32_t seqId; Loading Loading @@ -178,6 +179,24 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } void expectKey(uint32_t keycode) { InputEvent *ev = consumeEvent(); ASSERT_NE(ev, nullptr); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); KeyEvent *keyEvent = static_cast<KeyEvent *>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction()); EXPECT_EQ(keycode, keyEvent->getKeyCode()); EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); ev = consumeEvent(); ASSERT_NE(ev, nullptr); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); keyEvent = static_cast<KeyEvent *>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction()); EXPECT_EQ(keycode, keyEvent->getKeyCode()); EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); } virtual ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); } Loading Loading @@ -215,12 +234,12 @@ public: } private: void waitForEventAvailable() { void waitForEventAvailable(int timeoutMs) { struct pollfd fd; fd.fd = mClientChannel->getFd(); fd.events = POLLIN; poll(&fd, 1, 3000); poll(&fd, 1, timeoutMs); } void populateInputInfo(int width, int height) { Loading Loading @@ -363,6 +382,14 @@ void injectTap(int x, int y) { } } void injectKey(uint32_t keycode) { char *buf1; asprintf(&buf1, "%d", keycode); if (fork() == 0) { execlp("input", "input", "keyevent", buf1, NULL); } } TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); Loading Loading @@ -614,6 +641,9 @@ TEST_F(InputSurfacesTest, can_be_focused) { surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, rotate_surface) { Loading Loading @@ -781,4 +811,139 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { surface->expectTap(1, 1); } TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_NE(surface->consumeEvent(), nullptr); EXPECT_NE(surface->consumeEvent(), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.setMatrix(sc, 2.0, 0, 0, 2.0); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_NE(surface->consumeEvent(), nullptr); EXPECT_NE(surface->consumeEvent(), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->mInputInfo.ownerUid = 11111; surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(100, 100); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->mInputInfo.ownerUid = 11111; surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100); obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(190, 190); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) { std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->showAt(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.reparent(sc, parentSurface->mSurfaceControl); t.setAlpha(parentSurface->mSurfaceControl, 0.9f); }); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) { std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300); parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction([&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); t.reparent(sc, parentSurface->mSurfaceControl); t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100)); }); surface->showAt(100, 100); injectTap(111, 111); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } TEST_F(InputSurfacesTest, drop_input_policy) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); surface->doTransaction( [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); }); surface->showAt(100, 100); injectTap(101, 101); EXPECT_EQ(surface->consumeEvent(100), nullptr); surface->requestFocus(); surface->assertFocusChange(true); injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } } // namespace android::test
services/surfaceflinger/Layer.cpp +69 −0 Original line number Diff line number Diff line Loading @@ -2288,6 +2288,74 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } gui::DropInputMode Layer::getDropInputMode() const { gui::DropInputMode mode = mDrawingState.dropInputMode; if (mode == gui::DropInputMode::ALL) { return mode; } sp<Layer> parent = mDrawingParent.promote(); if (parent) { gui::DropInputMode parentMode = parent->getDropInputMode(); if (parentMode != gui::DropInputMode::NONE) { return parentMode; } } return mode; } void Layer::handleDropInputMode(gui::WindowInfo& info) const { if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { return; } // Check if we need to drop input unconditionally gui::DropInputMode dropInputMode = getDropInputMode(); if (dropInputMode == gui::DropInputMode::ALL) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy.", getDebugName()); return; } // Check if we need to check if the window is obscured by parent if (dropInputMode != gui::DropInputMode::OBSCURED) { return; } // Check if the parent has set an alpha on the layer sp<Layer> parent = mDrawingParent.promote(); if (parent && parent->getAlpha() != 1.0_hf) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast<float>(getAlpha())); } // Check if the parent has cropped the buffer Rect bufferSize = getCroppedBufferSize(getDrawingState()); if (!bufferSize.isValid()) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; return; } // Screenbounds are the layer bounds cropped by parents, transformed to screenspace. // To check if the layer has been cropped, we take the buffer bounds, apply the local // layer crop and apply the same set of transforms to move to screenspace. If the bounds // match then the layer has not been cropped by its parents. Rect bufferInScreenSpace(getTransform().transform(bufferSize)); bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; if (croppedByParent) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", getDebugName()); } else { // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop // input if the window is obscured. This check should be done in surfaceflinger but the // logic currently resides in inputflinger. So pass the if_obscured check to input to only // drop input events if the window is obscured. info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; } } WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); Loading Loading @@ -2315,6 +2383,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); info.alpha = getAlpha(); fillTouchOcclusionMode(info); handleDropInputMode(info); auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { Loading
services/surfaceflinger/Layer.h +2 −0 Original line number Diff line number Diff line Loading @@ -1063,6 +1063,8 @@ private: bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp<Layer>& relativeOf); bool isTrustedOverlay() const; gui::DropInputMode getDropInputMode() const; void handleDropInputMode(gui::WindowInfo& info) const; // Find the root of the cloned hierarchy, this means the first non cloned parent. // This will return null if first non cloned parent is not found. Loading