From d9f012a6f409b2c92c5d71c00ef4cfe3e1cb4085 Mon Sep 17 00:00:00 2001 From: erfanoabdi Date: Tue, 27 Apr 2021 16:26:32 +0600 Subject: [PATCH] sdm660-common: light: Adapt light HAL for k4.19 --- light/Android.bp | 5 +- light/Light.cpp | 302 ++++++------------ light/Light.h | 62 ++-- ...ardware.light@2.0-service.xiaomi_sdm660.rc | 30 -- light/service.cpp | 7 +- 5 files changed, 137 insertions(+), 269 deletions(-) diff --git a/light/Android.bp b/light/Android.bp index e3a91f6a..91918ec7 100644 --- a/light/Android.bp +++ b/light/Android.bp @@ -1,4 +1,5 @@ -// Copyright (C) 2018,2020 The LineageOS Project +// +// Copyright (C) 2018,2020 The LineageOS Projec // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,9 +21,7 @@ cc_binary { srcs: ["service.cpp", "Light.cpp"], shared_libs: [ "libbase", - "libhardware", "libhidlbase", - "liblog", "libutils", "android.hardware.light@2.0", ], diff --git a/light/Light.cpp b/light/Light.cpp index 7effab80..e850d1b9 100644 --- a/light/Light.cpp +++ b/light/Light.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2018 The LineageOS Project + * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,98 +15,50 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.light@2.0-service.xiaomi_sdm660" +// Author := dev_harsh1998, Isaac Chen -#include +#define LOG_TAG "android.hardware.light@2.0-impl.xiaomi_sdm660" +/* #define LOG_NDEBUG 0 */ #include "Light.h" -#include - -#define LEDS "/sys/class/leds/" - -#define BUTTON1_LED LEDS "button-backlight1/" -#define BUTTON_LED LEDS "button-backlight/" -#define LCD_LED LEDS "lcd-backlight/" -#define WHITE_LED LEDS "white/" -#define RED_LED LEDS "red/" - -#define BLINK "blink" -#define BRIGHTNESS "brightness" -#define MAX_BRIGHTNESS "max_brightness" -#define DUTY_PCTS "duty_pcts" -#define PAUSE_HI "pause_hi" -#define PAUSE_LO "pause_lo" -#define RAMP_STEP_MS "ramp_step_ms" -#define START_IDX "start_idx" - -#define MAX_LED_BRIGHTNESS 255 -#define MAX_WHITE_LED_BRIGHTNESS 255 -#define MAX_RED_LED_BRIGHTNESS 255 -#define MAX_LCD_BRIGHTNESS 4095 - -/* - * 8 duty percent steps. - */ -#define RAMP_STEPS 8 -/* - * Each step will stay on for 50ms by default. - */ -#define RAMP_STEP_DURATION 150 -/* - * Each value represents a duty percent (0 - 100) for the led pwm. - */ -static int32_t BRIGHTNESS_RAMP[RAMP_STEPS] = {0, 12, 25, 37, 50, 72, 85, 100}; +#include +#include +#include namespace { -/* - * Write value to path and close file. - */ -static void set(std::string path, std::string value) { - std::ofstream file(path); - if (!file.is_open()) { - LOG(DEBUG) << "failed to write %s to %s" << value.c_str() << path.c_str(); - return; - } +#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) - file << value; +#define LEDS(x) PPCAT(/sys/class/leds, x) +#define LCD_ATTR(x) STRINGIFY(PPCAT(LEDS(lcd-backlight), x)) +#define WHITE_ATTR(x) STRINGIFY(PPCAT(LEDS(red), x)) + +using ::android::base::ReadFileToString; +using ::android::base::WriteStringToFile; + +// Default max brightness +constexpr auto kDefaultMaxLedBrightness = 255; +constexpr auto kDefaultMaxScreenBrightness = 4095; + +// Write value to path and close file. +bool WriteToFile(const std::string& path, uint32_t content) { + return WriteStringToFile(std::to_string(content), path); } -/* - * Read value to path and close file. - */ -static int get(std::string path) { - std::ifstream file(path); - int value; +uint32_t RgbaToBrightness(uint32_t color) { + // Extract brightness from AARRGGBB. + uint32_t alpha = (color >> 24) & 0xFF; - if (!file.is_open()) { - LOG(DEBUG) << "failed to read from %s" << path.c_str(); - return 0; - } + // Retrieve each of the RGB colors + uint32_t red = (color >> 16) & 0xFF; + uint32_t green = (color >> 8) & 0xFF; + uint32_t blue = color & 0xFF; - file >> value; - return value; -} - -static void set(std::string path, int value) { - set(path, std::to_string(value)); -} - -static uint32_t getBrightness(const LightState& state) { - uint32_t alpha, red, green, blue; - - /* - * Extract brightness from AARRGGBB. - */ - alpha = (state.color >> 24) & 0xFF; - red = (state.color >> 16) & 0xFF; - green = (state.color >> 8) & 0xFF; - blue = state.color & 0xFF; - - /* - * Scale RGB brightness if Alpha brightness is not 0xFF. - */ + // Scale RGB colors if a brightness has been applied by the user if (alpha != 0xFF) { red = red * alpha / 0xFF; green = green * alpha / 0xFF; @@ -115,105 +68,14 @@ static uint32_t getBrightness(const LightState& state) { return (77 * red + 150 * green + 29 * blue) >> 8; } -static inline uint32_t scaleBrightness(uint32_t brightness, uint32_t maxBrightness) { - return brightness * maxBrightness / 0xFF; +inline uint32_t RgbaToBrightness(uint32_t color, uint32_t max_brightness) { + return RgbaToBrightness(color) * max_brightness / 0xFF; } -static inline uint32_t getScaledBrightness(const LightState& state, uint32_t maxBrightness) { - return scaleBrightness(getBrightness(state), maxBrightness); +inline bool IsLit(uint32_t color) { + return color & 0x00ffffff; } -static int getMaxBrightness(std::string path) { - int value = get(path); - LOG(DEBUG) << "Got max brightness %d" << value; - return value; -} - -static void handleBacklight(const LightState& state) { - uint32_t brightness = getScaledBrightness(state, getMaxBrightness(LCD_LED MAX_BRIGHTNESS)); - set(LCD_LED BRIGHTNESS, brightness); -} - -static void handleButtons(const LightState& state) { - uint32_t brightness = getScaledBrightness(state, getMaxBrightness(BUTTON_LED MAX_BRIGHTNESS)); - set(BUTTON_LED BRIGHTNESS, brightness); - set(BUTTON1_LED BRIGHTNESS, brightness); -} - -/* - * Scale each value of the brightness ramp according to the - * brightness of the color. - */ -static std::string getScaledRamp(uint32_t brightness) { - std::string ramp, pad; - - for (auto const& step : BRIGHTNESS_RAMP) { - ramp += pad + std::to_string(step * brightness / 0xFF); - pad = ","; - } - - return ramp; -} - -static void handleNotification(const LightState& state) { - uint32_t whiteBrightness = getScaledBrightness(state, getMaxBrightness(WHITE_LED MAX_BRIGHTNESS)); - uint32_t redBrightness = getScaledBrightness(state, getMaxBrightness(RED_LED MAX_BRIGHTNESS)); - - /* Disable blinking */ - set(WHITE_LED BLINK, 0); - set(RED_LED BLINK, 0); - - if (state.flashMode == Flash::TIMED) { - /* - * If the flashOnMs duration is not long enough to fit ramping up - * and down at the default step duration, step duration is modified - * to fit. - */ - int32_t stepDuration = RAMP_STEP_DURATION; - int32_t pauseHi = state.flashOnMs - (stepDuration * RAMP_STEPS * 2); - int32_t pauseLo = state.flashOffMs; - - if (pauseHi < 0) { - stepDuration = state.flashOnMs / (RAMP_STEPS * 2); - pauseHi = 0; - } - - /* White */ - set(WHITE_LED START_IDX, 0 * RAMP_STEPS); - set(WHITE_LED DUTY_PCTS, getScaledRamp(whiteBrightness)); - set(WHITE_LED PAUSE_LO, pauseLo); - set(WHITE_LED PAUSE_HI, pauseHi); - set(WHITE_LED RAMP_STEP_MS, stepDuration); - - /* red */ - set(RED_LED START_IDX, 0 * RAMP_STEPS); - set(RED_LED DUTY_PCTS, getScaledRamp(redBrightness)); - set(RED_LED PAUSE_LO, pauseLo); - set(RED_LED PAUSE_HI, pauseHi); - set(RED_LED RAMP_STEP_MS, stepDuration); - - /* Enable blinking */ - set(WHITE_LED BLINK, 1); - set(RED_LED BLINK, 1); - } else { - set(WHITE_LED BRIGHTNESS, whiteBrightness); - set(RED_LED BRIGHTNESS, redBrightness); - } -} - -static inline bool isLit(const LightState& state) { - return state.color & 0x00ffffff; -} - -/* Keep sorted in the order of importance. */ -static std::vector backends = { - { Type::ATTENTION, handleNotification }, - { Type::NOTIFICATIONS, handleNotification }, - { Type::BATTERY, handleNotification }, - { Type::BACKLIGHT, handleBacklight }, - { Type::BUTTONS, handleButtons }, -}; - } // anonymous namespace namespace android { @@ -222,35 +84,33 @@ namespace light { namespace V2_0 { namespace implementation { -Return Light::setLight(Type type, const LightState& state) { - LightStateHandler handler = nullptr; +Light::Light() { + std::string buf; - /* Lock global mutex until light state is updated. */ - std::lock_guard lock(globalLock); - - /* Update the cached state value for the current type. */ - for (LightBackend& backend : backends) { - if (backend.type == type) { - backend.state = state; - handler = backend.handler; - } + if (ReadFileToString(LCD_ATTR(max_brightness), &buf)) { + max_screen_brightness_ = std::stoi(buf); + } else { + max_screen_brightness_ = kDefaultMaxScreenBrightness; + LOG(ERROR) << "Failed to read max screen brightness, fallback to " + << kDefaultMaxScreenBrightness; } - /* If no handler has been found, then the type is not supported. */ - if (!handler) { + if (ReadFileToString(WHITE_ATTR(max_brightness), &buf)) { + max_led_brightness_ = std::stoi(buf); + } else { + max_led_brightness_ = kDefaultMaxLedBrightness; + LOG(ERROR) << "Failed to read max LED brightness, fallback to " << kDefaultMaxLedBrightness; + } +} + +Return Light::setLight(Type type, const LightState& state) { + auto it = lights_.find(type); + + if (it == lights_.end()) { return Status::LIGHT_NOT_SUPPORTED; } - /* Light up the type with the highest priority that matches the current handler. */ - for (LightBackend& backend : backends) { - if (handler == backend.handler && isLit(backend.state)) { - handler(backend.state); - return Status::SUCCESS; - } - } - - /* If no type has been lit up, then turn off the hardware. */ - handler(state); + it->second(type, state); return Status::SUCCESS; } @@ -258,15 +118,53 @@ Return Light::setLight(Type type, const LightState& state) { Return Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { std::vector types; - for (const LightBackend& backend : backends) { - types.push_back(backend.type); - } + for (auto&& light : lights_) types.emplace_back(light.first); _hidl_cb(types); return Void(); } +void Light::setLightBacklight(Type /*type*/, const LightState& state) { + uint32_t brightness = RgbaToBrightness(state.color, max_screen_brightness_); + WriteToFile(LCD_ATTR(brightness), brightness); +} + +void Light::setLightNotification(Type type, const LightState& state) { + bool found = false; + for (auto&& [cur_type, cur_state] : notif_states_) { + if (cur_type == type) { + cur_state = state; + } + + // Fallback to battery light + if (!found && (cur_type == Type::BATTERY || IsLit(cur_state.color))) { + found = true; + LOG(DEBUG) << __func__ << ": type=" << toString(cur_type); + applyNotificationState(cur_state); + } + } +} + +void Light::applyNotificationState(const LightState& state) { + uint32_t white_brightness = RgbaToBrightness(state.color, max_led_brightness_); + + // Turn off the leds (initially) + WriteToFile(WHITE_ATTR(breath), 0); + + if (state.flashMode == Flash::TIMED && state.flashOnMs > 0 && state.flashOffMs > 0) { + LOG(DEBUG) << __func__ << ": color=" << std::hex << state.color << std::dec + << " onMs=" << state.flashOnMs << " offMs=" << state.flashOffMs; + + // White + WriteToFile(WHITE_ATTR(delay_off), static_cast(state.flashOffMs)); + WriteToFile(WHITE_ATTR(delay_on), static_cast(state.flashOnMs)); + WriteToFile(WHITE_ATTR(breath), 1); + } else { + WriteToFile(WHITE_ATTR(brightness), white_brightness); + } +} + } // namespace implementation } // namespace V2_0 } // namespace light diff --git a/light/Light.h b/light/Light.h index 4f102d8d..1a28589b 100644 --- a/light/Light.h +++ b/light/Light.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The LineageOS Project + * Copyright (C) 2017-2020 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. @@ -14,35 +14,11 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H -#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H +#pragma once #include -#include -#include -#include -#include -#include -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::light::V2_0::Flash; -using ::android::hardware::light::V2_0::ILight; -using ::android::hardware::light::V2_0::LightState; -using ::android::hardware::light::V2_0::Status; -using ::android::hardware::light::V2_0::Type; - -typedef void (*LightStateHandler)(const LightState&); - -struct LightBackend { - Type type; - LightState state; - LightStateHandler handler; - - LightBackend(Type type, LightStateHandler handler) : type(type), handler(handler) { - this->state.color = 0xff000000; - } -}; +#include namespace android { namespace hardware { @@ -50,13 +26,41 @@ namespace light { namespace V2_0 { namespace implementation { +using ::android::hardware::Return; +using ::android::hardware::light::V2_0::ILight; +using ::android::hardware::light::V2_0::LightState; +using ::android::hardware::light::V2_0::Status; +using ::android::hardware::light::V2_0::Type; + class Light : public ILight { public: + Light(); + Return setLight(Type type, const LightState& state) override; Return getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; private: - std::mutex globalLock; + void setLightBacklight(Type type, const LightState& state); + void setLightButtons(Type type, const LightState& state); + void setLightNotification(Type type, const LightState& state); + void applyNotificationState(const LightState& state); + + uint32_t max_button_brightness_; + uint32_t max_led_brightness_; + uint32_t max_screen_brightness_; + + std::unordered_map> lights_{ + {Type::BACKLIGHT, [this](auto&&... args) { setLightBacklight(args...); }}, + {Type::BATTERY, [this](auto&&... args) { setLightNotification(args...); }}, + {Type::NOTIFICATIONS, [this](auto&&... args) { setLightNotification(args...); }}}; + + // Keep sorted in the order of importance. + std::array, 2> notif_states_ = {{ + {Type::NOTIFICATIONS, {}}, + {Type::BATTERY, {}}, + }}; + + std::vector buttons_; }; } // namespace implementation @@ -64,5 +68,3 @@ class Light : public ILight { } // namespace light } // namespace hardware } // namespace android - -#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H diff --git a/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc b/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc index eeb6014f..313ee8ff 100644 --- a/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc +++ b/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc @@ -1,22 +1,5 @@ on early-boot # Notification LED - chown system system /sys/class/leds/white/blink - chown system system /sys/class/leds/white/brightness - chown system system /sys/class/leds/white/duty_pcts - chown system system /sys/class/leds/white/max_brightness - chown system system /sys/class/leds/white/pause_hi - chown system system /sys/class/leds/white/pause_lo - chown system system /sys/class/leds/white/ramp_step_ms - chown system system /sys/class/leds/white/start_idx - - chmod 660 /sys/class/leds/white/blink - chmod 660 /sys/class/leds/white/brightness - chmod 660 /sys/class/leds/white/duty_pcts - chmod 660 /sys/class/leds/white/pause_hi - chmod 660 /sys/class/leds/white/pause_lo - chmod 660 /sys/class/leds/white/ramp_step_ms - chmod 660 /sys/class/leds/white/start_idx - chown system system /sys/class/leds/red/blink chown system system /sys/class/leds/red/brightness chown system system /sys/class/leds/red/duty_pcts @@ -26,18 +9,6 @@ on early-boot chown system system /sys/class/leds/red/ramp_step_ms chown system system /sys/class/leds/red/start_idx - chmod 660 /sys/class/leds/red/blink - chmod 660 /sys/class/leds/red/brightness - chmod 660 /sys/class/leds/red/duty_pcts - chmod 660 /sys/class/leds/red/pause_hi - chmod 660 /sys/class/leds/red/pause_lo - chmod 660 /sys/class/leds/red/ramp_step_ms - chmod 660 /sys/class/leds/red/start_idx - - chown system system /sys/class/leds/button-backlight/max_brightness - chown system system /sys/class/leds/button-backlight1/brightness - chown system system /sys/class/leds/button-backlight1/max_brightness - chown system system /sys/class/leds/lcd-backlight/max_brightness service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.xiaomi_sdm660 @@ -45,5 +16,4 @@ service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.x class hal user system group system - # shutting off lights while powering-off shutdown critical diff --git a/light/service.cpp b/light/service.cpp index 19c02e35..27a4ebf3 100644 --- a/light/service.cpp +++ b/light/service.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2018 The LineageOS Project + * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -24,15 +25,13 @@ using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; -using android::hardware::light::V2_0::ILight; using android::hardware::light::V2_0::implementation::Light; using android::OK; -using android::sp; using android::status_t; int main() { - sp service = new Light(); + android::sp service = new Light(); configureRpcThreadpool(1, true);