SyncPointerCapture (1/n): Notify PointerCaptureChanged through InputListener

This CL adds notifyPointerCaptureChanged(NotifyPointerCaptureChangedArgs)
to the InputListener interface so that InputReader can notify the Dispatcher
about changes in its PointerCapture state synchronously with the
processing of input events.

Notifying the Dispatcher about the pointer capture state through the
InputListener interface will synchronize the state change notification
with input events that are reported through the same interface.

Bug: 141749603
Test: atest inputflinger_tests
Change-Id: I7bfd45334fa70eccdd5a0f002cbb00e7a1de8d14
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 77a0716..eafb5ab 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -405,6 +405,11 @@
     mListener->notifyDeviceReset(args);
 }
 
+void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    // pass through
+    mListener->notifyPointerCaptureChanged(args);
+}
+
 void InputClassifier::setMotionClassifier(
         std::unique_ptr<MotionClassifierInterface> motionClassifier) {
     std::scoped_lock lock(mLock);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 03510a6..6965940 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -230,6 +230,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     virtual void dump(std::string& dump) override;
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 84838ec..49a813e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -48,7 +48,6 @@
     listener->notifyConfigurationChanged(this);
 }
 
-
 // --- NotifyKeyArgs ---
 
 NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -90,7 +89,6 @@
     listener->notifyKey(this);
 }
 
-
 // --- NotifyMotionArgs ---
 
 NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -189,7 +187,6 @@
     listener->notifyMotion(this);
 }
 
-
 // --- NotifySwitchArgs ---
 
 NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
@@ -214,7 +211,6 @@
     listener->notifySwitch(this);
 }
 
-
 // --- NotifyDeviceResetArgs ---
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
@@ -231,6 +227,23 @@
     listener->notifyDeviceReset(this);
 }
 
+// --- NotifyPointerCaptureChangedArgs ---
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime,
+                                                                 bool enabled)
+      : NotifyArgs(id, eventTime), enabled(enabled) {}
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
+        const NotifyPointerCaptureChangedArgs& other)
+      : NotifyArgs(other.id, other.eventTime), enabled(other.enabled) {}
+
+bool NotifyPointerCaptureChangedArgs::operator==(const NotifyPointerCaptureChangedArgs& rhs) const {
+    return id == rhs.id && eventTime == rhs.eventTime && enabled == rhs.enabled;
+}
+
+void NotifyPointerCaptureChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
+    listener->notifyPointerCaptureChanged(this);
+}
 
 // --- QueuedInputListener ---
 
@@ -278,6 +291,11 @@
     mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
 }
 
+void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    traceEvent(__func__, args->id);
+    mArgsQueue.push_back(new NotifyPointerCaptureChangedArgs(*args));
+}
+
 void QueuedInputListener::flush() {
     size_t count = mArgsQueue.size();
     for (size_t i = 0; i < count; i++) {
@@ -288,5 +306,4 @@
     mArgsQueue.clear();
 }
 
-
 } // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ff5f6d8..6a90352 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3542,6 +3542,15 @@
     }
 }
 
+void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
+          args->enabled ? "true" : "false");
+#endif
+
+    // TODO(prabirmsp): Implement.
+}
+
 InputEventInjectionResult InputDispatcher::injectInputEvent(
         const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
         InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5704a5a..9aaae74 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -94,6 +94,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     virtual android::os::InputEventInjectionResult injectInputEvent(
             const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 8317b05..58eb915 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -181,6 +181,22 @@
     virtual void notify(const sp<InputListenerInterface>& listener) const;
 };
 
+/* Describes a change in the state of Pointer Capture. */
+struct NotifyPointerCaptureChangedArgs : public NotifyArgs {
+    bool enabled;
+
+    inline NotifyPointerCaptureChangedArgs() {}
+
+    NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, bool enabled);
+
+    NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other);
+
+    bool operator==(const NotifyPointerCaptureChangedArgs& rhs) const;
+
+    virtual ~NotifyPointerCaptureChangedArgs() {}
+
+    virtual void notify(const sp<InputListenerInterface>& listener) const;
+};
 
 /*
  * The interface used by the InputReader to notify the InputListener about input events.
@@ -196,6 +212,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0;
 };
 
 
@@ -210,11 +227,12 @@
 public:
     explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
 
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
-    virtual void notifyKey(const NotifyKeyArgs* args);
-    virtual void notifyMotion(const NotifyMotionArgs* args);
-    virtual void notifySwitch(const NotifySwitchArgs* args);
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+    virtual void notifyKey(const NotifyKeyArgs* args) override;
+    virtual void notifyMotion(const NotifyMotionArgs* args) override;
+    virtual void notifySwitch(const NotifySwitchArgs* args) override;
+    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     void flush();
 
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 2028b91..e263f01 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -338,24 +338,30 @@
     mPolicy->getReaderConfiguration(&mConfig);
     mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
 
-    if (changes) {
-        ALOGI("Reconfiguring input devices, changes=%s",
-              InputReaderConfiguration::changesToString(changes).c_str());
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    if (!changes) return;
 
-        if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
-            updatePointerDisplayLocked();
-        }
+    ALOGI("Reconfiguring input devices, changes=%s",
+          InputReaderConfiguration::changesToString(changes).c_str());
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
-        if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
-            mEventHub->requestReopenDevices();
-        } else {
-            for (auto& devicePair : mDevices) {
-                std::shared_ptr<InputDevice>& device = devicePair.second;
-                device->configure(now, &mConfig, changes);
-            }
+    if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
+        updatePointerDisplayLocked();
+    }
+
+    if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
+        mEventHub->requestReopenDevices();
+    } else {
+        for (auto& devicePair : mDevices) {
+            std::shared_ptr<InputDevice>& device = devicePair.second;
+            device->configure(now, &mConfig, changes);
         }
     }
+
+    if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
+        const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+                                                   mConfig.pointerCapture);
+        mQueuedListener->notifyPointerCaptureChanged(&args);
+    }
 }
 
 void InputReader::updateGlobalMetaStateLocked() {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a72d5c3..99eaac6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1792,6 +1792,29 @@
               mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_C));
 }
 
+TEST_F(InputReaderTest, ChangingPointerCaptureNotifiesInputListener) {
+    NotifyPointerCaptureChangedArgs args;
+
+    mFakePolicy->setPointerCapture(true);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_TRUE(args.enabled) << "Pointer Capture should be enabled.";
+
+    mFakePolicy->setPointerCapture(false);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+
+    // Verify that the Pointer Capture state is re-configured correctly when the configuration value
+    // does not change.
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+}
+
 // --- InputReaderIntegrationTest ---
 
 // These tests create and interact with the InputReader only through its interface.
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 9bff166..352995c 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -82,6 +82,14 @@
                                            "Expected notifySwitch() to have been called."));
 }
 
+void TestInputListener::assertNotifyCaptureWasCalled(
+        NotifyPointerCaptureChangedArgs* outEventArgs) {
+    ASSERT_NO_FATAL_FAILURE(
+            assertCalled<NotifyPointerCaptureChangedArgs>(outEventArgs,
+                                                          "Expected notifyPointerCaptureChanged() "
+                                                          "to have been called."));
+}
+
 template <class NotifyArgsType>
 void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
     std::unique_lock<std::mutex> lock(mLock);
@@ -145,4 +153,8 @@
     notify<NotifySwitchArgs>(args);
 }
 
+void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    notify<NotifyPointerCaptureChangedArgs>(args);
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index d50c6bc..887d4ea 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -54,6 +54,8 @@
 
     void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
 
+    void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
+
 private:
     template <class NotifyArgsType>
     void assertCalled(NotifyArgsType* outEventArgs, std::string message);
@@ -74,16 +76,19 @@
 
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
 
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
+
     std::mutex mLock;
     std::condition_variable mCondition;
     const std::chrono::milliseconds mEventHappenedTimeout;
     const std::chrono::milliseconds mEventDidNotHappenTimeout;
 
-    std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
-               std::vector<NotifyDeviceResetArgs>,          //
-               std::vector<NotifyKeyArgs>,                  //
-               std::vector<NotifyMotionArgs>,               //
-               std::vector<NotifySwitchArgs>>               //
+    std::tuple<std::vector<NotifyConfigurationChangedArgs>,  //
+               std::vector<NotifyDeviceResetArgs>,           //
+               std::vector<NotifyKeyArgs>,                   //
+               std::vector<NotifyMotionArgs>,                //
+               std::vector<NotifySwitchArgs>,                //
+               std::vector<NotifyPointerCaptureChangedArgs>> //
             mQueues GUARDED_BY(mLock);
 };