Introduce PointerChoreographer stage in C++
PointerChoreographer will be the new inputflinger component responsible
for managing the pointer icons drawn on the screen.
In this CL, we set up the PointerChoreographer InputListener stage,
which will be created when the choreographer is enabled.
Bug: 293587049
Bug: 278783893
Test: adb shell setprop persist.input.enable_pointer_choreographer 1;
boot
Change-Id: Ice610055ef7ffc44c7c3e1d3904715eabda31a86
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index d551213..7451037 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -77,6 +77,7 @@
"InputCommonConverter.cpp",
"InputDeviceMetricsCollector.cpp",
"InputProcessor.cpp",
+ "PointerChoreographer.cpp",
"PreferStylusOverTouchBlocker.cpp",
"UnwantedInteractionBlocker.cpp",
],
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 0733a1c..0567a32 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -38,6 +38,9 @@
const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
+const bool ENABLE_POINTER_CHOREOGRAPHER =
+ sysprop::InputProperties::enable_pointer_choreographer().value_or(false);
+
int32_t exceptionCodeFromStatusT(status_t status) {
switch (status) {
case OK:
@@ -113,12 +116,14 @@
* The event flow is via the "InputListener" interface, as follows:
* InputReader
* -> UnwantedInteractionBlocker
+ * -> PointerChoreographer
* -> InputProcessor
* -> InputDeviceMetricsCollector
* -> InputDispatcher
*/
InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,
- InputDispatcherPolicyInterface& dispatcherPolicy) {
+ InputDispatcherPolicyInterface& dispatcherPolicy,
+ PointerChoreographerPolicyInterface& choreographerPolicy) {
mInputFlingerRust = createInputFlingerRust();
mDispatcher = createInputDispatcher(dispatcherPolicy);
@@ -135,6 +140,13 @@
mTracingStages.emplace_back(
std::make_unique<TracedInputListener>("InputProcessor", *mProcessor));
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ mChoreographer =
+ std::make_unique<PointerChoreographer>(*mTracingStages.back(), choreographerPolicy);
+ mTracingStages.emplace_back(
+ std::make_unique<TracedInputListener>("PointerChoreographer", *mChoreographer));
+ }
+
mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mTracingStages.back());
mTracingStages.emplace_back(
std::make_unique<TracedInputListener>("UnwantedInteractionBlocker", *mBlocker));
@@ -186,6 +198,10 @@
return *mReader;
}
+PointerChoreographerInterface& InputManager::getChoreographer() {
+ return *mChoreographer;
+}
+
InputProcessorInterface& InputManager::getProcessor() {
return *mProcessor;
}
@@ -210,6 +226,10 @@
dump += '\n';
mBlocker->dump(dump);
dump += '\n';
+ if (ENABLE_POINTER_CHOREOGRAPHER) {
+ mChoreographer->dump(dump);
+ dump += '\n';
+ }
mProcessor->dump(dump);
dump += '\n';
if (ENABLE_INPUT_DEVICE_USAGE_METRICS) {
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 51d582f..20b9fd5 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -23,10 +23,12 @@
#include "InputDeviceMetricsCollector.h"
#include "InputProcessor.h"
#include "InputReaderBase.h"
+#include "PointerChoreographer.h"
#include "include/UnwantedInteractionBlockerInterface.h"
#include <InputDispatcherInterface.h>
#include <InputDispatcherPolicyInterface.h>
+#include <PointerChoreographerPolicyInterface.h>
#include <input/Input.h>
#include <input/InputTransport.h>
@@ -86,6 +88,9 @@
/* Gets the input reader. */
virtual InputReaderInterface& getReader() = 0;
+ /* Gets the PointerChoreographer. */
+ virtual PointerChoreographerInterface& getChoreographer() = 0;
+
/* Gets the input processor. */
virtual InputProcessorInterface& getProcessor() = 0;
@@ -108,12 +113,14 @@
public:
InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,
- InputDispatcherPolicyInterface& dispatcherPolicy);
+ InputDispatcherPolicyInterface& dispatcherPolicy,
+ PointerChoreographerPolicyInterface& choreographerPolicy);
status_t start() override;
status_t stop() override;
InputReaderInterface& getReader() override;
+ PointerChoreographerInterface& getChoreographer() override;
InputProcessorInterface& getProcessor() override;
InputDeviceMetricsCollectorInterface& getMetricsCollector() override;
InputDispatcherInterface& getDispatcher() override;
@@ -130,6 +137,8 @@
std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
+ std::unique_ptr<PointerChoreographerInterface> mChoreographer;
+
std::unique_ptr<InputProcessorInterface> mProcessor;
std::unique_ptr<InputDeviceMetricsCollectorInterface> mCollector;
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
new file mode 100644
index 0000000..e411abb
--- /dev/null
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PointerChoreographer"
+
+#include "PointerChoreographer.h"
+
+namespace android {
+
+// --- PointerChoreographer ---
+
+PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
+ PointerChoreographerPolicyInterface& policy)
+ : mNextListener(listener) {}
+
+void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::notifyPointerCaptureChanged(
+ const NotifyPointerCaptureChangedArgs& args) {
+ mNextListener.notify(args);
+}
+
+void PointerChoreographer::dump(std::string& dump) {
+ dump += "PointerChoreographer:\n";
+}
+
+} // namespace android
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
new file mode 100644
index 0000000..5e5f782
--- /dev/null
+++ b/services/inputflinger/PointerChoreographer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "InputListener.h"
+#include "NotifyArgs.h"
+#include "PointerChoreographerPolicyInterface.h"
+
+namespace android {
+
+/**
+ * PointerChoreographer manages the icons shown by the system for input interactions.
+ * This includes showing the mouse cursor, stylus hover icons, and touch spots.
+ * It is responsible for accumulating the location of the mouse cursor, and populating
+ * the cursor position for incoming events, if necessary.
+ */
+class PointerChoreographerInterface : public InputListenerInterface {
+public:
+ /**
+ * This method may be called on any thread (usually by the input manager on a binder thread).
+ */
+ virtual void dump(std::string& dump) = 0;
+};
+
+class PointerChoreographer : public PointerChoreographerInterface {
+public:
+ explicit PointerChoreographer(InputListenerInterface& listener,
+ PointerChoreographerPolicyInterface&);
+ ~PointerChoreographer() override = default;
+
+ void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
+ void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override;
+ void notifyKey(const NotifyKeyArgs& args) override;
+ void notifyMotion(const NotifyMotionArgs& args) override;
+ void notifySwitch(const NotifySwitchArgs& args) override;
+ void notifySensor(const NotifySensorArgs& args) override;
+ void notifyVibratorState(const NotifyVibratorStateArgs& args) override;
+ void notifyDeviceReset(const NotifyDeviceResetArgs& args) override;
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
+
+ void dump(std::string& dump) override;
+
+private:
+ InputListenerInterface& mNextListener;
+};
+
+} // namespace android
diff --git a/services/inputflinger/include/PointerChoreographerPolicyInterface.h b/services/inputflinger/include/PointerChoreographerPolicyInterface.h
new file mode 100644
index 0000000..9e020c7
--- /dev/null
+++ b/services/inputflinger/include/PointerChoreographerPolicyInterface.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "PointerControllerInterface.h"
+
+namespace android {
+
+/**
+ * The PointerChoreographer policy interface.
+ *
+ * This is the interface that PointerChoreographer uses to talk to Window Manager and other
+ * system components.
+ */
+class PointerChoreographerPolicyInterface {
+public:
+ virtual ~PointerChoreographerPolicyInterface() = default;
+
+ /**
+ * A factory method for PointerController. The PointerController implementation has
+ * dependencies on a graphical library - libgui, used to draw icons on the screen - which
+ * isn't available for the host. Since we want libinputflinger and its test to be buildable
+ * for and runnable on the host, the PointerController implementation must be in a separate
+ * library, libinputservice, that has the additional dependencies. The PointerController
+ * will be mocked when testing PointerChoreographer.
+ */
+ virtual std::shared_ptr<PointerControllerInterface> createPointerController() = 0;
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index f2e8885..6410046 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -58,6 +58,7 @@
"InstrumentedInputReader.cpp",
"LatencyTracker_test.cpp",
"NotifyArgs_test.cpp",
+ "PointerChoreographer_test.cpp",
"PreferStylusOverTouch_test.cpp",
"PropertyProvider_test.cpp",
"SlopController_test.cpp",
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
new file mode 100644
index 0000000..7237424
--- /dev/null
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../PointerChoreographer.h"
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include "TestInputListener.h"
+
+namespace android {
+
+// Helpers to std::visit with lambdas.
+template <typename... V>
+struct Visitor : V... {};
+template <typename... V>
+Visitor(V...) -> Visitor<V...>;
+
+// --- PointerChoreographerTest ---
+
+class PointerChoreographerTest : public testing::Test, public PointerChoreographerPolicyInterface {
+protected:
+ TestInputListener mTestListener;
+ PointerChoreographer mChoreographer{mTestListener, *this};
+
+ std::shared_ptr<PointerControllerInterface> createPointerController() { return {}; }
+};
+
+TEST_F(PointerChoreographerTest, ForwardsArgsToInnerListener) {
+ const std::vector<NotifyArgs> allArgs{NotifyInputDevicesChangedArgs{},
+ NotifyConfigurationChangedArgs{},
+ NotifyKeyArgs{},
+ NotifyMotionArgs{},
+ NotifySensorArgs{},
+ NotifySwitchArgs{},
+ NotifyDeviceResetArgs{},
+ NotifyPointerCaptureChangedArgs{},
+ NotifyVibratorStateArgs{}};
+
+ for (auto notifyArgs : allArgs) {
+ mChoreographer.notify(notifyArgs);
+ EXPECT_NO_FATAL_FAILURE(
+ std::visit(Visitor{
+ [&](const NotifyInputDevicesChangedArgs& args) {
+ mTestListener.assertNotifyInputDevicesChangedWasCalled();
+ },
+ [&](const NotifyConfigurationChangedArgs& args) {
+ mTestListener.assertNotifyConfigurationChangedWasCalled();
+ },
+ [&](const NotifyKeyArgs& args) {
+ mTestListener.assertNotifyKeyWasCalled();
+ },
+ [&](const NotifyMotionArgs& args) {
+ mTestListener.assertNotifyMotionWasCalled();
+ },
+ [&](const NotifySensorArgs& args) {
+ mTestListener.assertNotifySensorWasCalled();
+ },
+ [&](const NotifySwitchArgs& args) {
+ mTestListener.assertNotifySwitchWasCalled();
+ },
+ [&](const NotifyDeviceResetArgs& args) {
+ mTestListener.assertNotifyDeviceResetWasCalled();
+ },
+ [&](const NotifyPointerCaptureChangedArgs& args) {
+ mTestListener.assertNotifyCaptureWasCalled();
+ },
+ [&](const NotifyVibratorStateArgs& args) {
+ mTestListener.assertNotifyVibratorStateWasCalled();
+ },
+ },
+ notifyArgs));
+ }
+}
+
+} // namespace android