Loading include/input/InputDevice.h +19 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ #include <android/sensor.h> #include <ftl/flags.h> #include <ftl/mixins.h> #include <input/Input.h> #include <input/KeyCharacterMap.h> #include <set> #include <unordered_map> #include <vector> Loading Loading @@ -182,11 +184,24 @@ struct InputDeviceSensorInfo { int32_t id; }; struct BrightnessLevel : ftl::DefaultConstructible<BrightnessLevel, std::uint8_t>, ftl::Equatable<BrightnessLevel>, ftl::Orderable<BrightnessLevel>, ftl::Addable<BrightnessLevel> { using DefaultConstructible::DefaultConstructible; }; struct InputDeviceLightInfo { explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type, ftl::Flags<InputDeviceLightCapability> capabilityFlags, int32_t ordinal) : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal) {} int32_t ordinal, std::set<BrightnessLevel> preferredBrightnessLevels) : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal), preferredBrightnessLevels(std::move(preferredBrightnessLevels)) {} // Name string of the light. std::string name; // Light id Loading @@ -197,6 +212,8 @@ struct InputDeviceLightInfo { ftl::Flags<InputDeviceLightCapability> capabilityFlags; // Ordinal of the light int32_t ordinal; // Custom brightness levels for the light std::set<BrightnessLevel> preferredBrightnessLevels; }; struct InputDeviceBatteryInfo { Loading services/inputflinger/reader/controller/PeripheralController.cpp +40 −3 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ #include <locale> #include <regex> #include <set> #include <sstream> #include <string> #include <android/sysprop/InputProperties.sysprop.h> #include <ftl/enum.h> #include "../Macros.h" Loading Loading @@ -45,6 +47,10 @@ static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff); } static inline bool isKeyboardBacklightCustomLevelsEnabled() { return sysprop::InputProperties::enable_keyboard_backlight_custom_levels().value_or(true); } /** * Input controller owned by InputReader device, implements the native API for querying input * lights, getting and setting the lights brightness and color, by interacting with EventHub Loading Loading @@ -272,11 +278,43 @@ void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) { for (const auto& [lightId, light] : mLights) { // Input device light doesn't support ordinal, always pass 1. InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags, /*ordinal=*/1); /*ordinal=*/1, getPreferredBrightnessLevels(light.get())); deviceInfo->addLightInfo(lightInfo); } } // TODO(b/281822656): Move to constructor and add as a parameter to avoid parsing repeatedly. // Need to change lifecycle of Peripheral controller so that Input device configuration map is // available at construction time before moving this logic to constructor. std::set<BrightnessLevel> PeripheralController::getPreferredBrightnessLevels( const Light* light) const { std::set<BrightnessLevel> levels; if (!isKeyboardBacklightCustomLevelsEnabled() || light->type != InputDeviceLightType::KEYBOARD_BACKLIGHT) { return levels; } std::optional<std::string> keyboardBacklightLevels = mDeviceContext.getConfiguration().getString("keyboard.backlight.brightnessLevels"); if (!keyboardBacklightLevels) { return levels; } std::stringstream ss(*keyboardBacklightLevels); while (ss.good()) { std::string substr; std::getline(ss, substr, ','); char* end; int32_t value = static_cast<int32_t>(strtol(substr.c_str(), &end, 10)); if (*end != '\0' || value < 0 || value > 255) { ALOGE("Error parsing keyboard backlight brightness levels, provided levels = %s", keyboardBacklightLevels->c_str()); levels.clear(); break; } levels.insert(BrightnessLevel(value)); } return levels; } void PeripheralController::dump(std::string& dump) { dump += INDENT2 "Input Controller:\n"; if (!mLights.empty()) { Loading Loading @@ -550,5 +588,4 @@ std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) { int32_t PeripheralController::getEventHubId() const { return getDeviceContext().getEventHubId(); } } // namespace android services/inputflinger/reader/controller/PeripheralController.h +3 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ private: virtual void dump(std::string& dump) {} void configureSuggestedBrightnessLevels(); std::optional<std::int32_t> getRawLightBrightness(int32_t rawLightId); void setRawLightBrightness(int32_t rawLightId, int32_t brightness); }; Loading Loading @@ -152,6 +153,8 @@ private: // Battery map from battery ID to battery std::unordered_map<int32_t, std::unique_ptr<Battery>> mBatteries; std::set<BrightnessLevel> getPreferredBrightnessLevels(const Light* light) const; }; } // namespace android services/inputflinger/reader/include/InputDevice.h +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ public: } inline bool hasMic() const { return mHasMic; } inline bool isIgnored() { return !getMapperCount(); } inline bool isIgnored() { return !getMapperCount() && !mController; } bool isEnabled(); [[nodiscard]] std::list<NotifyArgs> setEnabled(bool enabled, nsecs_t when); Loading services/inputflinger/tests/InputReader_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -11070,6 +11070,101 @@ TEST_F(LightControllerTest, MonoKeyboardBacklight) { ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS); } TEST_F(LightControllerTest, Ignore_MonoLight_WithPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_light", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, KeyboardBacklight_WithNoPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, KeyboardBacklight_WithPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(3U, lights[0].preferredBrightnessLevels.size()); std::set<BrightnessLevel>::iterator it = lights[0].preferredBrightnessLevels.begin(); ASSERT_EQ(BrightnessLevel(0), *it); std::advance(it, 1); ASSERT_EQ(BrightnessLevel(100), *it); std::advance(it, 1); ASSERT_EQ(BrightnessLevel(200), *it); } TEST_F(LightControllerTest, KeyboardBacklight_WithWrongPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200,300,400,500"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, RGBLight) { RawLightInfo infoRed = {.id = 1, .name = "red", Loading
include/input/InputDevice.h +19 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ #include <android/sensor.h> #include <ftl/flags.h> #include <ftl/mixins.h> #include <input/Input.h> #include <input/KeyCharacterMap.h> #include <set> #include <unordered_map> #include <vector> Loading Loading @@ -182,11 +184,24 @@ struct InputDeviceSensorInfo { int32_t id; }; struct BrightnessLevel : ftl::DefaultConstructible<BrightnessLevel, std::uint8_t>, ftl::Equatable<BrightnessLevel>, ftl::Orderable<BrightnessLevel>, ftl::Addable<BrightnessLevel> { using DefaultConstructible::DefaultConstructible; }; struct InputDeviceLightInfo { explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type, ftl::Flags<InputDeviceLightCapability> capabilityFlags, int32_t ordinal) : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal) {} int32_t ordinal, std::set<BrightnessLevel> preferredBrightnessLevels) : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal), preferredBrightnessLevels(std::move(preferredBrightnessLevels)) {} // Name string of the light. std::string name; // Light id Loading @@ -197,6 +212,8 @@ struct InputDeviceLightInfo { ftl::Flags<InputDeviceLightCapability> capabilityFlags; // Ordinal of the light int32_t ordinal; // Custom brightness levels for the light std::set<BrightnessLevel> preferredBrightnessLevels; }; struct InputDeviceBatteryInfo { Loading
services/inputflinger/reader/controller/PeripheralController.cpp +40 −3 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ #include <locale> #include <regex> #include <set> #include <sstream> #include <string> #include <android/sysprop/InputProperties.sysprop.h> #include <ftl/enum.h> #include "../Macros.h" Loading Loading @@ -45,6 +47,10 @@ static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int return (brightness & 0xff) << 24 | (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff); } static inline bool isKeyboardBacklightCustomLevelsEnabled() { return sysprop::InputProperties::enable_keyboard_backlight_custom_levels().value_or(true); } /** * Input controller owned by InputReader device, implements the native API for querying input * lights, getting and setting the lights brightness and color, by interacting with EventHub Loading Loading @@ -272,11 +278,43 @@ void PeripheralController::populateDeviceInfo(InputDeviceInfo* deviceInfo) { for (const auto& [lightId, light] : mLights) { // Input device light doesn't support ordinal, always pass 1. InputDeviceLightInfo lightInfo(light->name, light->id, light->type, light->capabilityFlags, /*ordinal=*/1); /*ordinal=*/1, getPreferredBrightnessLevels(light.get())); deviceInfo->addLightInfo(lightInfo); } } // TODO(b/281822656): Move to constructor and add as a parameter to avoid parsing repeatedly. // Need to change lifecycle of Peripheral controller so that Input device configuration map is // available at construction time before moving this logic to constructor. std::set<BrightnessLevel> PeripheralController::getPreferredBrightnessLevels( const Light* light) const { std::set<BrightnessLevel> levels; if (!isKeyboardBacklightCustomLevelsEnabled() || light->type != InputDeviceLightType::KEYBOARD_BACKLIGHT) { return levels; } std::optional<std::string> keyboardBacklightLevels = mDeviceContext.getConfiguration().getString("keyboard.backlight.brightnessLevels"); if (!keyboardBacklightLevels) { return levels; } std::stringstream ss(*keyboardBacklightLevels); while (ss.good()) { std::string substr; std::getline(ss, substr, ','); char* end; int32_t value = static_cast<int32_t>(strtol(substr.c_str(), &end, 10)); if (*end != '\0' || value < 0 || value > 255) { ALOGE("Error parsing keyboard backlight brightness levels, provided levels = %s", keyboardBacklightLevels->c_str()); levels.clear(); break; } levels.insert(BrightnessLevel(value)); } return levels; } void PeripheralController::dump(std::string& dump) { dump += INDENT2 "Input Controller:\n"; if (!mLights.empty()) { Loading Loading @@ -550,5 +588,4 @@ std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) { int32_t PeripheralController::getEventHubId() const { return getDeviceContext().getEventHubId(); } } // namespace android
services/inputflinger/reader/controller/PeripheralController.h +3 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ private: virtual void dump(std::string& dump) {} void configureSuggestedBrightnessLevels(); std::optional<std::int32_t> getRawLightBrightness(int32_t rawLightId); void setRawLightBrightness(int32_t rawLightId, int32_t brightness); }; Loading Loading @@ -152,6 +153,8 @@ private: // Battery map from battery ID to battery std::unordered_map<int32_t, std::unique_ptr<Battery>> mBatteries; std::set<BrightnessLevel> getPreferredBrightnessLevels(const Light* light) const; }; } // namespace android
services/inputflinger/reader/include/InputDevice.h +1 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ public: } inline bool hasMic() const { return mHasMic; } inline bool isIgnored() { return !getMapperCount(); } inline bool isIgnored() { return !getMapperCount() && !mController; } bool isEnabled(); [[nodiscard]] std::list<NotifyArgs> setEnabled(bool enabled, nsecs_t when); Loading
services/inputflinger/tests/InputReader_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -11070,6 +11070,101 @@ TEST_F(LightControllerTest, MonoKeyboardBacklight) { ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS); } TEST_F(LightControllerTest, Ignore_MonoLight_WithPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_light", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, KeyboardBacklight_WithNoPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, KeyboardBacklight_WithPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(3U, lights[0].preferredBrightnessLevels.size()); std::set<BrightnessLevel>::iterator it = lights[0].preferredBrightnessLevels.begin(); ASSERT_EQ(BrightnessLevel(0), *it); std::advance(it, 1); ASSERT_EQ(BrightnessLevel(100), *it); std::advance(it, 1); ASSERT_EQ(BrightnessLevel(200), *it); } TEST_F(LightControllerTest, KeyboardBacklight_WithWrongPreferredBacklightLevels) { RawLightInfo infoMono = {.id = 1, .name = "mono_keyboard_backlight", .maxBrightness = 255, .flags = InputLightClass::BRIGHTNESS | InputLightClass::KEYBOARD_BACKLIGHT, .path = ""}; mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "keyboard.backlight.brightnessLevels", "0,100,200,300,400,500"); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); InputDeviceInfo info; controller.populateDeviceInfo(&info); std::vector<InputDeviceLightInfo> lights = info.getLights(); ASSERT_EQ(1U, lights.size()); ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size()); } TEST_F(LightControllerTest, RGBLight) { RawLightInfo infoRed = {.id = 1, .name = "red",