Loading services/inputflinger/InputDispatcher.cpp +13 −4 Original line number Diff line number Diff line Loading @@ -2055,7 +2055,7 @@ void InputDispatcher::enqueueDispatchEntryLocked( return; // skip the inconsistent event } dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source, dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); break; Loading @@ -2073,10 +2073,11 @@ void InputDispatcher::enqueueDispatchEntryLocked( } void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { return; } Loading @@ -2095,7 +2096,9 @@ void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source return; } // Dispatch onPointerDownOutsideFocus to the policy. CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); commandEntry->newToken = newToken; } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Loading Loading @@ -3997,6 +4000,12 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( entry->release(); } void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->onPointerDownOutsideFocus(commandEntry->newToken); mLock.lock(); } void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; Loading services/inputflinger/InputDispatcher.h +10 −1 Original line number Diff line number Diff line Loading @@ -272,6 +272,13 @@ public: */ virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid) = 0; /* Notifies the policy that a pointer down event has occurred outside the current focused * window. * * The touchedToken passed as an argument is the window that received the input event. */ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0; }; Loading Loading @@ -1149,7 +1156,7 @@ private: void releaseDispatchEntry(DispatchEntry* dispatchEntry); static int handleReceiveCallback(int fd, int events, void* data); // The action sent should only be of type AMOTION_EVENT_* void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) REQUIRES(mLock); void synthesizeCancelationEventsForAllConnectionsLocked( Loading Loading @@ -1204,6 +1211,8 @@ private: DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); // Statistics gathering. void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, Loading services/inputflinger/tests/InputDispatcher_test.cpp +129 −12 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ public: mTime = -1; mAction = -1; mDisplayId = -1; mOnPointerDownToken.clear(); } void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) { Loading Loading @@ -87,11 +88,18 @@ public: << "Expected filterInputEvent() to not have been called."; } void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) { ASSERT_EQ(mOnPointerDownToken, touchedToken) << "Expected token from onPointerDownOutsideFocus was not matched"; reset(); } private: bool mInputEventFiltered; nsecs_t mTime; int32_t mAction; int32_t mDisplayId; sp<IBinder> mOnPointerDownToken; virtual void notifyConfigurationChanged(nsecs_t) { } Loading Loading @@ -161,11 +169,16 @@ private: return false; } virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) { mOnPointerDownToken = newToken; } void reset() { mInputEventFiltered = false; mTime = -1; mAction = -1; mDisplayId = -1; mOnPointerDownToken.clear(); } }; Loading Loading @@ -432,7 +445,7 @@ public: FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId), mFocused(false) { mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) { mServerChannel->setToken(new BBinder()); mDispatcher->registerInputChannel(mServerChannel, displayId); Loading @@ -443,15 +456,15 @@ public: virtual bool updateInfo() { mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr; mInfo.name = mName; mInfo.layoutParamsFlags = 0; mInfo.layoutParamsFlags = mLayoutParamFlags; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.frameLeft = 0; mInfo.frameTop = 0; mInfo.frameRight = WIDTH; mInfo.frameBottom = HEIGHT; mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; mInfo.frameRight = mFrame.right; mInfo.frameBottom = mFrame.bottom; mInfo.globalScaleFactor = 1.0; mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); mInfo.addTouchableRegion(mFrame); mInfo.visible = true; mInfo.canReceiveKeys = true; mInfo.hasFocus = mFocused; Loading @@ -470,6 +483,14 @@ public: mFocused = true; } void setFrame(const Rect& frame) { mFrame.set(frame); } void setLayoutParamFlags(int32_t flags) { mLayoutParamFlags = flags; } void releaseChannel() { mServerChannel.clear(); InputWindowHandle::releaseChannel(); Loading @@ -480,6 +501,8 @@ protected: } bool mFocused; Rect mFrame; int32_t mLayoutParamFlags; }; static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, Loading @@ -500,7 +523,7 @@ static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, } static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source, int32_t displayId) { int32_t displayId, int32_t x = 100, int32_t y = 200) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; Loading @@ -510,8 +533,8 @@ static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t s pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. Loading Loading @@ -907,4 +930,98 @@ TEST_F(InputFilterTest, KeyEvent_InputFilter) { testNotifyKey(/*expectToBeFiltered*/ false); } class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { virtual void SetUp() { InputDispatcherTest::SetUp(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); mWindowFocused = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mWindowFocused->setFrame(Rect(50, 50, 100, 100)); mWindowFocused->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); mWindowFocusedTouchPoint = 60; // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mWindowFocused->setFocus(); // Expect one focus window exist in display. std::vector<sp<InputWindowHandle>> inputWindowHandles; inputWindowHandles.push_back(mUnfocusedWindow); inputWindowHandles.push_back(mWindowFocused); mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); } virtual void TearDown() { InputDispatcherTest::TearDown(); mUnfocusedWindow.clear(); mWindowFocused.clear(); } protected: sp<FakeWindowHandle> mUnfocusedWindow; sp<FakeWindowHandle> mWindowFocused; int32_t mWindowFocusedTouchPoint; }; // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received // the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken()); } // Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action // DOWN on the window that doesn't have focus. Ensure no window received the // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } // Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't // have focus. Ensure no window received the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action // DOWN on the window that already has focus. Ensure no window received the // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, mWindowFocusedTouchPoint, mWindowFocusedTouchPoint)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } } // namespace android Loading
services/inputflinger/InputDispatcher.cpp +13 −4 Original line number Diff line number Diff line Loading @@ -2055,7 +2055,7 @@ void InputDispatcher::enqueueDispatchEntryLocked( return; // skip the inconsistent event } dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source, dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); break; Loading @@ -2073,10 +2073,11 @@ void InputDispatcher::enqueueDispatchEntryLocked( } void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { return; } Loading @@ -2095,7 +2096,9 @@ void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source return; } // Dispatch onPointerDownOutsideFocus to the policy. CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); commandEntry->newToken = newToken; } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Loading Loading @@ -3997,6 +4000,12 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( entry->release(); } void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->onPointerDownOutsideFocus(commandEntry->newToken); mLock.lock(); } void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; Loading
services/inputflinger/InputDispatcher.h +10 −1 Original line number Diff line number Diff line Loading @@ -272,6 +272,13 @@ public: */ virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid) = 0; /* Notifies the policy that a pointer down event has occurred outside the current focused * window. * * The touchedToken passed as an argument is the window that received the input event. */ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0; }; Loading Loading @@ -1149,7 +1156,7 @@ private: void releaseDispatchEntry(DispatchEntry* dispatchEntry); static int handleReceiveCallback(int fd, int events, void* data); // The action sent should only be of type AMOTION_EVENT_* void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action, void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, const sp<IBinder>& newToken) REQUIRES(mLock); void synthesizeCancelationEventsForAllConnectionsLocked( Loading Loading @@ -1204,6 +1211,8 @@ private: DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); // Statistics gathering. void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, Loading
services/inputflinger/tests/InputDispatcher_test.cpp +129 −12 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ public: mTime = -1; mAction = -1; mDisplayId = -1; mOnPointerDownToken.clear(); } void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) { Loading Loading @@ -87,11 +88,18 @@ public: << "Expected filterInputEvent() to not have been called."; } void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) { ASSERT_EQ(mOnPointerDownToken, touchedToken) << "Expected token from onPointerDownOutsideFocus was not matched"; reset(); } private: bool mInputEventFiltered; nsecs_t mTime; int32_t mAction; int32_t mDisplayId; sp<IBinder> mOnPointerDownToken; virtual void notifyConfigurationChanged(nsecs_t) { } Loading Loading @@ -161,11 +169,16 @@ private: return false; } virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) { mOnPointerDownToken = newToken; } void reset() { mInputEventFiltered = false; mTime = -1; mAction = -1; mDisplayId = -1; mOnPointerDownToken.clear(); } }; Loading Loading @@ -432,7 +445,7 @@ public: FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId), mFocused(false) { mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) { mServerChannel->setToken(new BBinder()); mDispatcher->registerInputChannel(mServerChannel, displayId); Loading @@ -443,15 +456,15 @@ public: virtual bool updateInfo() { mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr; mInfo.name = mName; mInfo.layoutParamsFlags = 0; mInfo.layoutParamsFlags = mLayoutParamFlags; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.frameLeft = 0; mInfo.frameTop = 0; mInfo.frameRight = WIDTH; mInfo.frameBottom = HEIGHT; mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; mInfo.frameRight = mFrame.right; mInfo.frameBottom = mFrame.bottom; mInfo.globalScaleFactor = 1.0; mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); mInfo.addTouchableRegion(mFrame); mInfo.visible = true; mInfo.canReceiveKeys = true; mInfo.hasFocus = mFocused; Loading @@ -470,6 +483,14 @@ public: mFocused = true; } void setFrame(const Rect& frame) { mFrame.set(frame); } void setLayoutParamFlags(int32_t flags) { mLayoutParamFlags = flags; } void releaseChannel() { mServerChannel.clear(); InputWindowHandle::releaseChannel(); Loading @@ -480,6 +501,8 @@ protected: } bool mFocused; Rect mFrame; int32_t mLayoutParamFlags; }; static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, Loading @@ -500,7 +523,7 @@ static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, } static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source, int32_t displayId) { int32_t displayId, int32_t x = 100, int32_t y = 200) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; Loading @@ -510,8 +533,8 @@ static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t s pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. Loading Loading @@ -907,4 +930,98 @@ TEST_F(InputFilterTest, KeyEvent_InputFilter) { testNotifyKey(/*expectToBeFiltered*/ false); } class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { virtual void SetUp() { InputDispatcherTest::SetUp(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); mWindowFocused = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mWindowFocused->setFrame(Rect(50, 50, 100, 100)); mWindowFocused->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); mWindowFocusedTouchPoint = 60; // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mWindowFocused->setFocus(); // Expect one focus window exist in display. std::vector<sp<InputWindowHandle>> inputWindowHandles; inputWindowHandles.push_back(mUnfocusedWindow); inputWindowHandles.push_back(mWindowFocused); mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); } virtual void TearDown() { InputDispatcherTest::TearDown(); mUnfocusedWindow.clear(); mWindowFocused.clear(); } protected: sp<FakeWindowHandle> mUnfocusedWindow; sp<FakeWindowHandle> mWindowFocused; int32_t mWindowFocusedTouchPoint; }; // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received // the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken()); } // Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action // DOWN on the window that doesn't have focus. Ensure no window received the // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } // Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't // have focus. Ensure no window received the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action // DOWN on the window that already has focus. Ensure no window received the // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, mWindowFocusedTouchPoint, mWindowFocusedTouchPoint)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; // Call monitor to wait for the command queue to get flushed. mDispatcher->monitor(); mFakePolicy->assertOnPointerDownEquals(nullptr); } } // namespace android