diff options
| -rw-r--r-- | services/inputflinger/Android.bp | 1 | ||||
| -rw-r--r-- | services/inputflinger/InputManager.cpp | 22 | ||||
| -rw-r--r-- | services/inputflinger/InputManager.h | 11 | ||||
| -rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 70 | ||||
| -rw-r--r-- | services/inputflinger/PointerChoreographer.h | 61 | ||||
| -rw-r--r-- | services/inputflinger/include/PointerChoreographerPolicyInterface.h | 44 | ||||
| -rw-r--r-- | services/inputflinger/tests/Android.bp | 1 | ||||
| -rw-r--r-- | services/inputflinger/tests/PointerChoreographer_test.cpp | 89 |
8 files changed, 297 insertions, 2 deletions
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index d5512132be..74510374e8 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -77,6 +77,7 @@ filegroup { "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 0733a1c7c6..0567a32550 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -38,6 +38,9 @@ namespace { 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 @@ std::shared_ptr<IInputFlingerRust> createInputFlingerRust() { * 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 @@ InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy, 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 @@ InputReaderInterface& InputManager::getReader() { return *mReader; } +PointerChoreographerInterface& InputManager::getChoreographer() { + return *mChoreographer; +} + InputProcessorInterface& InputManager::getProcessor() { return *mProcessor; } @@ -210,6 +226,10 @@ void InputManager::dump(std::string& dump) { 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 51d582fba1..20b9fd50df 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 @@ public: /* 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 @@ protected: 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 @@ private: 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 0000000000..e411abb251 --- /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 0000000000..5e5f78257b --- /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 0000000000..9e020c7c7f --- /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 f2e88858ee..64100467db 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -58,6 +58,7 @@ cc_test { "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 0000000000..7237424e2a --- /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 |