diff options
5 files changed, 158 insertions, 6 deletions
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index ffb2cb1fc1..b7751f704a 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -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> @@ -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 @@ -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 { diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index a380b5eadf..eabf591dbf 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -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" @@ -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 @@ -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()) { @@ -550,5 +588,4 @@ std::optional<int32_t> PeripheralController::getLightPlayerId(int32_t lightId) { int32_t PeripheralController::getEventHubId() const { return getDeviceContext().getEventHubId(); } - } // namespace android diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h index 8ac42c3792..07ade7c931 100644 --- a/services/inputflinger/reader/controller/PeripheralController.h +++ b/services/inputflinger/reader/controller/PeripheralController.h @@ -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); }; @@ -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 diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 0b8a608891..2f8e5bd6cf 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -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); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index bfb371f02a..327513d8f5 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -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", |