diff --git a/lights/Lights.cpp b/lights/Lights.cpp index 04ea9e3..ea887df 100644 --- a/lights/Lights.cpp +++ b/lights/Lights.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2019 The Android Open Source Project - * Copyright (C) 2020-2021 The LineageOS Project + * Copyright (C) 2020-2022 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,27 +21,26 @@ #include #include -namespace { - /* clang-format off */ #define PPCAT_NX(A, B) A/B #define PPCAT(A, B) PPCAT_NX(A, B) #define STRINGIFY_INNER(x) #x #define STRINGIFY(x) STRINGIFY_INNER(x) -#define LEDS(x) PPCAT(/sys/class/leds, x) -#define WHITE_ATTR(x) STRINGIFY(PPCAT(LEDS(charging), x)) +#define CHARGING_ATTR(x) STRINGIFY(PPCAT(/sys/class/leds/charging, x)) /* clang-format on */ -using ::android::base::ReadFileToString; -using ::android::base::WriteStringToFile; +namespace aidl { +namespace android { +namespace hardware { +namespace light { -// Default max brightness -constexpr auto kDefaultMaxLedBrightness = 255; +namespace { // Write value to path and close file. -bool WriteToFile(const std::string& path, uint32_t content) { - return WriteStringToFile(std::to_string(content), path); +template +inline bool WriteToFile(const std::string& path, T content) { + return ::android::base::WriteStringToFile(std::to_string(content), path); } uint32_t RgbaToBrightness(uint32_t color) { @@ -63,97 +62,72 @@ uint32_t RgbaToBrightness(uint32_t color) { return (77 * red + 150 * green + 29 * blue) >> 8; } -inline uint32_t RgbaToBrightness(uint32_t color, uint32_t max_brightness) { - return RgbaToBrightness(color) * max_brightness / 0xFF; -} - inline bool IsLit(uint32_t color) { return color & 0x00ffffff; } -} // anonymous namespace +void ApplyNotificationState(const HwLightState& state) { + auto brightness = RgbaToBrightness(state.color); -namespace aidl { -namespace android { -namespace hardware { -namespace light { - -Lights::Lights() { - std::map> lights_{ - {(int)LightType::NOTIFICATIONS, - [this](auto&&... args) { setLightNotification(args...); }}, - {(int)LightType::BATTERY, [this](auto&&... args) { setLightNotification(args...); }}, - {(int)LightType::BACKLIGHT, {}}}; - - std::vector availableLights; - for (auto const& pair : lights_) { - int id = pair.first; - HwLight hwLight{}; - hwLight.id = id; - availableLights.emplace_back(hwLight); - } - mAvailableLights = availableLights; - mLights = lights_; - - std::string buf; - - if (ReadFileToString(WHITE_ATTR(max_brightness), &buf)) { - max_led_brightness_ = std::stoi(buf); + // Turn off the leds (initially) + WriteToFile(CHARGING_ATTR(breath), 0); + if (state.flashMode == FlashMode::TIMED && state.flashOnMs > 0 && state.flashOffMs > 0) { + WriteToFile(CHARGING_ATTR(delay_on), state.flashOnMs); + WriteToFile(CHARGING_ATTR(delay_off), state.flashOffMs); + WriteToFile(CHARGING_ATTR(breath), 1); } else { - max_led_brightness_ = kDefaultMaxLedBrightness; - LOG(ERROR) << "Failed to read max LED brightness, fallback to " << kDefaultMaxLedBrightness; + WriteToFile(CHARGING_ATTR(brightness), brightness); } } +} // anonymous namespace + ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) { - auto it = mLights.find(id); - if (it == mLights.end()) { + static_assert(kAvailableLights.size() == std::tuple_size_v); + + if (id == static_cast(LightType::BACKLIGHT)) { + // Stub backlight handling + return ndk::ScopedAStatus::ok(); + } + + // Update saved state first + bool found = false; + for (size_t i = 0; i < notif_states_.size(); ++i) { + if (kAvailableLights[i].id == id) { + notif_states_[i] = state; + LOG(DEBUG) << __func__ << ": updating id=" << id + << ", type=" << toString(kAvailableLights[i].type); + found = true; + break; + } + } + if (!found) { LOG(ERROR) << "Light not supported"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } - it->second(id, state); + // Lit up in order or fallback to battery light if others are dim + for (size_t i = 0; i < notif_states_.size(); ++i) { + auto&& cur_state = notif_states_[i]; + auto&& cur_light = kAvailableLights[i]; + if (IsLit(cur_state.color) || cur_light.type == LightType::BATTERY) { + LOG(DEBUG) << __func__ << ": applying id=" << cur_light.id + << ", type=" << toString(cur_light.type); + ApplyNotificationState(cur_state); + break; + } + } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Lights::getLights(std::vector* lights) { - for (auto i = mAvailableLights.begin(); i != mAvailableLights.end(); i++) { - lights->push_back(*i); - } + lights->insert(lights->end(), kAvailableLights.begin(), kAvailableLights.end()); + // We don't handle backlight but still need to report as supported. + lights->push_back({static_cast(LightType::BACKLIGHT), 0, LightType::BACKLIGHT}); return ndk::ScopedAStatus::ok(); } -void Lights::setLightNotification(int id, const HwLightState& state) { - bool found = false; - for (auto&& [cur_id, cur_state] : notif_states_) { - if (cur_id == id) { - cur_state = state; - } - - // Fallback to battery light - if (!found && (cur_id == (int)LightType::BATTERY || IsLit(cur_state.color))) { - found = true; - LOG(DEBUG) << __func__ << ": id=" << id; - applyNotificationState(cur_state); - } - } -} - -void Lights::applyNotificationState(const HwLightState& state) { - int brightness = RgbaToBrightness(state.color, max_led_brightness_); - - // Turn off the leds (initially) - WriteToFile(WHITE_ATTR(breath), 0); - if (state.flashMode == FlashMode::TIMED && state.flashOnMs > 0 && state.flashOffMs > 0) { - WriteToFile(WHITE_ATTR(delay_on), static_cast(state.flashOnMs)); - WriteToFile(WHITE_ATTR(delay_off), static_cast(state.flashOffMs)); - WriteToFile(WHITE_ATTR(breath), 1); - } else { - WriteToFile(WHITE_ATTR(brightness), brightness); - } -} - } // namespace light } // namespace hardware } // namespace android diff --git a/lights/Lights.h b/lights/Lights.h index d634988..323b878 100644 --- a/lights/Lights.h +++ b/lights/Lights.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2020 The Android Open Source Project - * Copyright (C) 2020-2021 The LineageOS Project + * Copyright (C) 2020-2022 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,36 +18,27 @@ #pragma once #include -#include -#include -#include -#include +#include namespace aidl { namespace android { namespace hardware { namespace light { +// Keep sorted in the order of priority. +constexpr std::array kAvailableLights = { + // id, ordinal, type + HwLight{static_cast(LightType::NOTIFICATIONS), 0, LightType::NOTIFICATIONS}, + HwLight{static_cast(LightType::BATTERY), 0, LightType::BATTERY}, +}; + class Lights : public BnLights { public: - Lights(); ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override; ndk::ScopedAStatus getLights(std::vector* types) override; private: - void setLightNotification(int id, const HwLightState& state); - void applyNotificationState(const HwLightState& state); - - uint32_t max_led_brightness_; - - std::map> mLights; - std::vector mAvailableLights; - - // Keep sorted in the order of importance. - std::array, 2> notif_states_ = {{ - {(int)LightType::NOTIFICATIONS, {}}, - {(int)LightType::BATTERY, {}}, - }}; + std::array notif_states_; }; } // namespace light diff --git a/lights/android.hardware.lights.berlna.rc b/lights/android.hardware.lights.berlna.rc index 4b77288..fe48cb6 100644 --- a/lights/android.hardware.lights.berlna.rc +++ b/lights/android.hardware.lights.berlna.rc @@ -6,12 +6,15 @@ service vendor.light /vendor/bin/hw/android.hardware.lights-service.berlna on boot # Change ownership and permission for leds backlight - chmod 0664 /sys/class/leds/lcd-backlight/brightness + chown system system /sys/class/leds/charging/breath + chmod 0664 /sys/class/leds/charging/breath chown system system /sys/class/leds/charging/brightness chmod 0664 /sys/class/leds/charging/brightness - chown system system /sys/class/leds/charging/breath - chmod 660 /sys/class/leds/charging/breath chown system system /sys/class/leds/charging/delay_off - chmod 660 /sys/class/leds/charging/delay_off + chmod 0664 /sys/class/leds/charging/delay_off chown system system /sys/class/leds/charging/delay_on - chmod 660 /sys/class/leds/charging/delay_on + chmod 0664 /sys/class/leds/charging/delay_on + + # change permission of red leds + chown system system /sys/class/leds/red/brightness + chmod 0664 /sys/class/leds/red/brightness