From f162d20b5bee6523e0563323673a298579d2b252 Mon Sep 17 00:00:00 2001 From: Sebastiano Barezzi Date: Sun, 26 Sep 2021 21:08:29 +0200 Subject: [PATCH] aidl: light: Wire up * Merged Xiaomi SM8250, SM8150, SM6250, SDM710 and MSM8953 implementations Change-Id: I16764ec8676de6c2a9f745876dddab75db6adf35 --- aidl/light/Android.bp | 2 + aidl/light/LED.cpp | 39 +++++ aidl/light/LED.h | 32 +++++ aidl/light/Lights.cpp | 133 +++++++++++++++++- aidl/light/Lights.h | 15 ++ aidl/light/Utils.cpp | 86 +++++++++++ aidl/light/Utils.h | 35 +++++ .../android.hardware.light-service.xiaomi.rc | 31 +++- 8 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 aidl/light/LED.cpp create mode 100644 aidl/light/LED.h create mode 100644 aidl/light/Utils.cpp create mode 100644 aidl/light/Utils.h diff --git a/aidl/light/Android.bp b/aidl/light/Android.bp index 31974c9..2fbf1c5 100644 --- a/aidl/light/Android.bp +++ b/aidl/light/Android.bp @@ -11,6 +11,8 @@ cc_binary { vintf_fragments: ["android.hardware.light-service.xiaomi.xml"], srcs: [ "Lights.cpp", + "LED.cpp", + "Utils.cpp", "service.cpp", ], shared_libs: [ diff --git a/aidl/light/LED.cpp b/aidl/light/LED.cpp new file mode 100644 index 0000000..ef9f4bd --- /dev/null +++ b/aidl/light/LED.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "LED.h" + +#include "Utils.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +static const uint32_t kDefaultMaxLedBrightness = 255; + +LED::LED(std::string type) : mBasePath("/sys/class/leds/" + type + "/") { + if (!readFromFile(mBasePath + "max_brightness", &mMaxBrightness)) + mMaxBrightness = kDefaultMaxLedBrightness; + mBreath = fileWriteable(mBasePath + "breath"); +} + +bool LED::exists() { + return fileWriteable(mBasePath + "brightness"); +} + +bool LED::setBreath(uint32_t value) { + return writeToFile(mBasePath + (mBreath ? "breath" : "blink"), value); +} + +bool LED::setBrightness(uint32_t value) { + return writeToFile(mBasePath + "brightness", value * mMaxBrightness / 0xFF); +} + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/light/LED.h b/aidl/light/LED.h new file mode 100644 index 0000000..c21a825 --- /dev/null +++ b/aidl/light/LED.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +class LED { +public: + LED(std::string type); + + bool exists(); + bool setBreath(uint32_t value); + bool setBrightness(uint32_t value); +private: + std::string mBasePath; + uint32_t mMaxBrightness; + bool mBreath; +}; + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/light/Lights.cpp b/aidl/light/Lights.cpp index 7191881..97d8c1d 100644 --- a/aidl/light/Lights.cpp +++ b/aidl/light/Lights.cpp @@ -6,17 +6,142 @@ #include "Lights.h" +#include +#include "LED.h" +#include "Utils.h" + namespace aidl { namespace android { namespace hardware { namespace light { -ndk::ScopedAStatus Lights::setLightState(int32_t /*id*/, const HwLightState& /*state*/) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +static const std::string kAllBacklightPaths[] = { + "/sys/class/backlight/panel0-backlight/brightness", + "/sys/class/leds/lcd-backlight/brightness", +}; + +static const std::string kAllButtonsPaths[] = { + "/sys/class/leds/button-backlight/brightness", + "/sys/class/leds/button-backlight1/brightness", +}; + +enum led_type { + RED, + GREEN, + BLUE, + WHITE, + MAX_LEDS, +}; + +static LED kLEDs[MAX_LEDS] = { + [RED] = LED("red"), + [GREEN] = LED("green"), + [BLUE] = LED("blue"), + [WHITE] = LED("white"), +}; + +#define AutoHwLight(light) {.id = (int32_t)light, .type = light, .ordinal = 0} + +static const HwLight kBacklightHwLight = AutoHwLight(LightType::BACKLIGHT); +static const HwLight kBatteryHwLight = AutoHwLight(LightType::BATTERY); +static const HwLight kButtonsHwLight = AutoHwLight(LightType::BUTTONS); +static const HwLight kNotificationHwLight = AutoHwLight(LightType::NOTIFICATIONS); + +Lights::Lights() { + for (auto& backlight : kAllBacklightPaths) { + if (!fileWriteable(backlight)) + continue; + + mBacklightPath = backlight; + mLights.push_back(kBacklightHwLight); + break; + } + + for (auto& buttons : kAllButtonsPaths) { + if (!fileWriteable(buttons)) + continue; + + mButtonsPaths.push_back(buttons); + } + + if (!mButtonsPaths.empty()) + mLights.push_back(kButtonsHwLight); + + mWhiteLED = kLEDs[WHITE].exists(); + + mLights.push_back(kBatteryHwLight); + mLights.push_back(kNotificationHwLight); } -ndk::ScopedAStatus Lights::getLights(std::vector */*_aidl_return*/) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state) { + LightType type = static_cast(id); + switch (type) { + case LightType::BACKLIGHT: + if (!mBacklightPath.empty()) + writeToFile(mBacklightPath, colorToBrightness(state.color)); + break; + case LightType::BUTTONS: + for (auto& buttons : mButtonsPaths) + writeToFile(buttons, isLit(state.color)); + break; + case LightType::BATTERY: + case LightType::NOTIFICATIONS: + mLEDMutex.lock(); + if (type == LightType::BATTERY) + mLastBatteryState = state; + else + mLastNotificationState = state; + setLED(isLit(mLastBatteryState.color) ? mLastBatteryState : mLastNotificationState); + mLEDMutex.unlock(); + break; + default: + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + break; + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Lights::getLights(std::vector *_aidl_return) { + for (auto& light : mLights) + _aidl_return->push_back(light); + + return ndk::ScopedAStatus::ok(); +} + +void Lights::setLED(const HwLightState& state) { + bool rc = true; + argb_t color = colorToArgb(state.color); + uint32_t blink = (state.flashOnMs != 0 && state.flashOffMs != 0); + + switch (state.flashMode) { + case FlashMode::HARDWARE: + case FlashMode::TIMED: + if (mWhiteLED) { + rc = kLEDs[WHITE].setBreath(blink); + } else { + if (!!color.red) + rc &= kLEDs[RED].setBreath(blink); + if (!!color.green) + rc &= kLEDs[GREEN].setBreath(blink); + if (!!color.blue) + rc &= kLEDs[BLUE].setBreath(blink); + } + if (rc) + break; + FALLTHROUGH_INTENDED; + default: + if (mWhiteLED) { + rc = kLEDs[WHITE].setBrightness(colorToBrightness(state.color)); + } else { + rc = kLEDs[RED].setBrightness(color.red); + rc &= kLEDs[GREEN].setBrightness(color.green); + rc &= kLEDs[BLUE].setBrightness(color.blue); + } + break; + } + + return; } } // namespace light diff --git a/aidl/light/Lights.h b/aidl/light/Lights.h index a6087ad..084c92c 100644 --- a/aidl/light/Lights.h +++ b/aidl/light/Lights.h @@ -7,6 +7,7 @@ #pragma once #include +#include using ::aidl::android::hardware::light::HwLightState; using ::aidl::android::hardware::light::HwLight; @@ -18,8 +19,22 @@ namespace light { class Lights : public BnLights { public: + Lights(); + ndk::ScopedAStatus setLightState(int32_t id, const HwLightState& state) override; ndk::ScopedAStatus getLights(std::vector *_aidl_return) override; +private: + void setLED(const HwLightState& state); + + std::vector mLights; + + std::string mBacklightPath; + std::vector mButtonsPaths; + bool mWhiteLED; + + std::mutex mLEDMutex; + HwLightState mLastBatteryState; + HwLightState mLastNotificationState; }; } // namespace light diff --git a/aidl/light/Utils.cpp b/aidl/light/Utils.cpp new file mode 100644 index 0000000..8878f10 --- /dev/null +++ b/aidl/light/Utils.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "Utils.h" + +#define LOG_TAG "android.hardware.light-service.xiaomi" + +#include +#include +#include + +using ::android::base::ReadFileToString; +using ::android::base::WriteStringToFile; + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +bool fileWriteable(const std::string& file) { + return !access(file.c_str(), W_OK); +} + +bool readFromFile(const std::string& file, std::string *content) { + return ReadFileToString(file, content, true); +} + +bool readFromFile(const std::string& file, uint32_t *content) { + std::string content_str; + if (readFromFile(file, &content_str)) + *content = std::stoi(content_str); + else + return false; + return true; +} + +bool writeToFile(const std::string& file, std::string content) { + return WriteStringToFile(content, file); +} + +bool writeToFile(const std::string& file, uint32_t content) { + return writeToFile(file, std::to_string(content)); +} + +bool isLit(uint32_t color) { + return color & 0x00ffffff; +} + +argb_t colorToArgb(uint32_t color) { + argb_t r; + + // Extract brightness from AARRGGBB. + r.alpha = (color >> 24) & 0xFF; + + // Retrieve each of the RGB colors + r.red = (color >> 16) & 0xFF; + r.green = (color >> 8) & 0xFF; + r.blue = color & 0xFF; + + // Scale RGB colors if a brightness has been applied by the user + if (r.alpha != 0xFF) { + r.red = r.red * r.alpha / 0xFF; + r.green = r.green * r.alpha / 0xFF; + r.blue = r.blue * r.alpha / 0xFF; + } + + return r; +} + +uint32_t argbToBrightness(argb_t c_argb) { + return (77 * c_argb.red + 150 * c_argb.green + 29 * c_argb.blue) >> 8; +} + +uint32_t colorToBrightness(uint32_t color) { + argb_t c_argb = colorToArgb(color); + + return argbToBrightness(c_argb); +} + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/light/Utils.h b/aidl/light/Utils.h new file mode 100644 index 0000000..3dbd11d --- /dev/null +++ b/aidl/light/Utils.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace light { + +typedef struct argb { + uint32_t alpha; + uint32_t red; + uint32_t green; + uint32_t blue; +} argb_t; + +bool fileWriteable(const std::string& file); +bool readFromFile(const std::string& file, std::string *content); +bool readFromFile(const std::string& file, uint32_t *content); +bool writeToFile(const std::string& file, uint32_t content); +bool isLit(uint32_t color); +argb_t colorToArgb(uint32_t color); +uint32_t argbToBrightness(argb_t c_argb); +uint32_t colorToBrightness(uint32_t color); + +} // namespace light +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/light/android.hardware.light-service.xiaomi.rc b/aidl/light/android.hardware.light-service.xiaomi.rc index 37cecd1..efc8fef 100644 --- a/aidl/light/android.hardware.light-service.xiaomi.rc +++ b/aidl/light/android.hardware.light-service.xiaomi.rc @@ -1,5 +1,32 @@ +on early-boot + chown system system /sys/class/leds/red/blink + chown system system /sys/class/leds/red/breath + chown system system /sys/class/leds/red/brightness + chown system system /sys/class/leds/red/max_brightness + + chown system system /sys/class/leds/green/blink + chown system system /sys/class/leds/green/breath + chown system system /sys/class/leds/green/brightness + chown system system /sys/class/leds/green/max_brightness + + chown system system /sys/class/leds/blue/blink + chown system system /sys/class/leds/blue/breath + chown system system /sys/class/leds/blue/brightness + chown system system /sys/class/leds/blue/max_brightness + + chown system system /sys/class/leds/white/blink + chown system system /sys/class/leds/white/breath + chown system system /sys/class/leds/white/brightness + chown system system /sys/class/leds/white/max_brightness + + chown system system /sys/class/leds/lcd-backlight/brightness + chown system system /sys/class/backlight/panel0-backlight/brightness + + chown system system /sys/class/leds/button-backlight/brightness + chown system system /sys/class/leds/button-backlight1/brightness + service vendor.light-default /vendor/bin/hw/android.hardware.light-service.xiaomi class hal - user nobody - group nobody + user system + group system shutdown critical