@@ -117,8 +117,12 @@ static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
117117// An arbitrary pid of the gesture monitor window
118118static constexpr gui::Pid MONITOR_PID{2001};
119119
120+ static constexpr int32_t FLAG_WINDOW_IS_OBSCURED = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
121+ static constexpr int32_t FLAG_WINDOW_IS_PARTIALLY_OBSCURED =
122+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
123+
120124static constexpr int EXPECTED_WALLPAPER_FLAGS =
121- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED ;
125+ FLAG_WINDOW_IS_OBSCURED | FLAG_WINDOW_IS_PARTIALLY_OBSCURED ;
122126
123127using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID;
124128
@@ -14684,4 +14688,219 @@ TEST_F(InputDispatcherTest, FocusedDisplayChangeIsNotified) {
1468414688 mFakePolicy->assertFocusedDisplayNotified(SECOND_DISPLAY_ID);
1468514689}
1468614690
14691+ class InputDispatcherObscuredFlagTest : public InputDispatcherTest {
14692+ protected:
14693+ std::shared_ptr<FakeApplicationHandle> mApplication;
14694+ std::shared_ptr<FakeApplicationHandle> mOcclusionApplication;
14695+ sp<FakeWindowHandle> mWindow;
14696+ sp<FakeWindowHandle> mOcclusionWindow;
14697+
14698+ void SetUp() override {
14699+ InputDispatcherTest::SetUp();
14700+ mDispatcher->setMaximumObscuringOpacityForTouch(0.8f);
14701+ mApplication = std::make_shared<FakeApplicationHandle>();
14702+ mOcclusionApplication = std::make_shared<FakeApplicationHandle>();
14703+ mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Window", DISPLAY_ID);
14704+ mWindow->setOwnerInfo(WINDOW_PID, WINDOW_UID);
14705+
14706+ mOcclusionWindow = sp<FakeWindowHandle>::make(mOcclusionApplication, mDispatcher,
14707+ "Occlusion Window", DISPLAY_ID);
14708+
14709+ mOcclusionWindow->setTouchable(false);
14710+ mOcclusionWindow->setTouchOcclusionMode(TouchOcclusionMode::USE_OPACITY);
14711+ mOcclusionWindow->setAlpha(0.7f);
14712+ mOcclusionWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
14713+ }
14714+ };
14715+
14716+ /**
14717+ * Two windows. An untouchable window partially occludes a touchable region below it.
14718+ * Use a finger to touch the bottom window.
14719+ * When the finger touches down in the obscured area, the motion event should always have the
14720+ * FLAG_WINDOW_IS_OBSCURED flag, regardless of where it is moved to. If it starts from a
14721+ * non-obscured area, the motion event should always with a FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag,
14722+ * regardless of where it is moved to.
14723+ */
14724+ TEST_F(InputDispatcherObscuredFlagTest, TouchObscuredTest) {
14725+ mWindow->setFrame({0, 0, 100, 100});
14726+ mOcclusionWindow->setFrame({0, 0, 100, 50});
14727+
14728+ mDispatcher->onWindowInfosChanged(
14729+ {{*mOcclusionWindow->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
14730+
14731+ // If the finger touch goes down in the region that is obscured.
14732+ // Expect the entire stream to use FLAG_WINDOW_IS_OBSCURED.
14733+ mDispatcher->notifyMotion(
14734+ MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14735+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(10))
14736+ .build());
14737+
14738+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
14739+ WithFlags(FLAG_WINDOW_IS_OBSCURED),
14740+ WithDisplayId(DISPLAY_ID)));
14741+
14742+ mDispatcher->notifyMotion(
14743+ MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
14744+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(60))
14745+ .build());
14746+
14747+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
14748+ WithFlags(FLAG_WINDOW_IS_OBSCURED),
14749+ WithDisplayId(DISPLAY_ID)));
14750+
14751+ mDispatcher->notifyMotion(
14752+ MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
14753+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(110))
14754+ .build());
14755+
14756+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP),
14757+ WithFlags(FLAG_WINDOW_IS_OBSCURED),
14758+ WithDisplayId(DISPLAY_ID)));
14759+ }
14760+
14761+ /**
14762+ * Two windows. An untouchable window partially occludes a touchable region below it.
14763+ * Use a finger to touch the bottom window.
14764+ * When the finger starts from a non-obscured area, the motion event should always have the
14765+ * FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag, regardless of where it is moved to.
14766+ */
14767+ TEST_F(InputDispatcherObscuredFlagTest, TouchPartiallyObscuredTest) {
14768+ mWindow->setFrame({0, 0, 100, 100});
14769+ mOcclusionWindow->setFrame({0, 0, 100, 50});
14770+
14771+ mDispatcher->onWindowInfosChanged(
14772+ {{*mOcclusionWindow->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
14773+
14774+ // If the finger touch goes down in the region that is not directly obscured by the overlay.
14775+ // Expect the entire stream to use FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
14776+ mDispatcher->notifyMotion(
14777+ MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
14778+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(60))
14779+ .build());
14780+
14781+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
14782+ WithFlags(FLAG_WINDOW_IS_PARTIALLY_OBSCURED),
14783+ WithDisplayId(DISPLAY_ID)));
14784+
14785+ mDispatcher->notifyMotion(
14786+ MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
14787+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(80))
14788+ .build());
14789+
14790+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE),
14791+ WithFlags(FLAG_WINDOW_IS_PARTIALLY_OBSCURED),
14792+ WithDisplayId(DISPLAY_ID)));
14793+
14794+ mDispatcher->notifyMotion(
14795+ MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
14796+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(110))
14797+ .build());
14798+
14799+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP),
14800+ WithFlags(FLAG_WINDOW_IS_PARTIALLY_OBSCURED),
14801+ WithDisplayId(DISPLAY_ID)));
14802+ }
14803+
14804+ /**
14805+ * Two windows. An untouchable window partially occludes a touchable region below it.
14806+ * Use the mouse to hover over the bottom window.
14807+ * When the hover happens over the occluded area, the window below should receive a motion
14808+ * event with the FLAG_WINDOW_IS_OBSCURED flag. When the hover event moves to the non-occluded area,
14809+ * the window below should receive a motion event with the FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag.
14810+ */
14811+ TEST_F(InputDispatcherObscuredFlagTest, MouseHoverObscuredTest) {
14812+ mWindow->setFrame({0, 0, 100, 100});
14813+ mOcclusionWindow->setFrame({0, 0, 100, 40});
14814+
14815+ mDispatcher->onWindowInfosChanged(
14816+ {{*mOcclusionWindow->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
14817+
14818+ // TODO(b/328160937): The window should receive a motion event with the FLAG_WINDOW_IS_OBSCURED
14819+ // flag.
14820+ mDispatcher->notifyMotion(
14821+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14822+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(20))
14823+ .build());
14824+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithFlags(0)));
14825+
14826+ mDispatcher->notifyMotion(
14827+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14828+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(30))
14829+ .build());
14830+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14831+
14832+ // TODO(b/328160937): The window should receive a motion event with the
14833+ // FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag.
14834+ mDispatcher->notifyMotion(
14835+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14836+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
14837+ .build());
14838+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14839+
14840+ mDispatcher->notifyMotion(
14841+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14842+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(60))
14843+ .build());
14844+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14845+
14846+ mDispatcher->notifyMotion(
14847+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
14848+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(110))
14849+ .build());
14850+
14851+ // TODO(b/328160937): The window should receive a HOVER_EXIT with the
14852+ // FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag. The cause of the current issue is that we moved the
14853+ // mouse to a location where there are no windows, so the HOVER_EXIT event cannot be generated.
14854+ mWindow->assertNoEvents();
14855+ }
14856+
14857+ /**
14858+ * Two windows. An untouchable window partially occludes a touchable region below it.
14859+ * Use the stylus to hover over the bottom window.
14860+ * When the hover happens over the occluded area, the window below should receive a motion
14861+ * event with the FLAG_WINDOW_IS_OBSCURED flag. When the hover event moves to the non-occluded area,
14862+ * the window below should receive a motion event with the FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag.
14863+ */
14864+ TEST_F(InputDispatcherObscuredFlagTest, StylusHoverObscuredTest) {
14865+ mWindow->setFrame({0, 0, 100, 100});
14866+ mOcclusionWindow->setFrame({0, 0, 100, 40});
14867+
14868+ mDispatcher->onWindowInfosChanged(
14869+ {{*mOcclusionWindow->getInfo(), *mWindow->getInfo()}, {}, 0, 0});
14870+
14871+ // TODO(b/328160937): The window should receive a motion event with the FLAG_WINDOW_IS_OBSCURED
14872+ // flag.
14873+ mDispatcher->notifyMotion(
14874+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
14875+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(20))
14876+ .build());
14877+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithFlags(0)));
14878+
14879+ mDispatcher->notifyMotion(
14880+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
14881+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(30))
14882+ .build());
14883+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14884+
14885+ // TODO(b/328160937): The window should receive a motion event with the
14886+ // FLAG_WINDOW_IS_PARTIALLY_OBSCURED flag.
14887+ mDispatcher->notifyMotion(
14888+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
14889+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
14890+ .build());
14891+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14892+
14893+ mDispatcher->notifyMotion(
14894+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
14895+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(60))
14896+ .build());
14897+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithFlags(0)));
14898+
14899+ mDispatcher->notifyMotion(
14900+ MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
14901+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(70))
14902+ .build());
14903+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithFlags(0)));
14904+ }
14905+
1468714906} // namespace android::inputdispatcher
0 commit comments