/* * Copyright (C) 2021 The LineageOS Project * * SPDX-License-Identifier: Apache-2.0 */ #define LOG_TAG "android.hardware.lights-service.samsung" #include #include #include "Lights.h" #define COLOR_MASK 0x00ffffff #define MAX_INPUT_BRIGHTNESS 255 namespace aidl { namespace android { namespace hardware { namespace light { /* * Write value to path and close file. */ template static void set(const std::string& path, const T& value) { std::ofstream file(path); file << value << std::endl; } template static T get(const std::string& path, const T& def) { std::ifstream file(path); T result; file >> result; return file.fail() ? def : result; } Lights::Lights() { mLights.emplace(LightType::BACKLIGHT, std::bind(&Lights::handleBacklight, this, std::placeholders::_1)); #ifdef BUTTON_BRIGHTNESS_NODE mLights.emplace(LightType::BUTTONS, std::bind(&Lights::handleButtons, this, std::placeholders::_1)); #endif /* BUTTON_BRIGHTNESS_NODE */ #ifdef LED_BLINK_NODE mLights.emplace(LightType::BATTERY, std::bind(&Lights::handleBattery, this, std::placeholders::_1)); mLights.emplace(LightType::NOTIFICATIONS, std::bind(&Lights::handleNotifications, this, std::placeholders::_1)); mLights.emplace(LightType::ATTENTION, std::bind(&Lights::handleAttention, this, std::placeholders::_1)); #endif /* LED_BLINK_NODE */ } ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state) { LightType type = static_cast(id); auto it = mLights.find(type); if (it == mLights.end()) { return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } /* * Lock global mutex until light state is updated. */ std::lock_guard lock(mLock); it->second(state); return ndk::ScopedAStatus::ok(); } void Lights::handleBacklight(const HwLightState& state) { uint32_t max_brightness = get(PANEL_MAX_BRIGHTNESS_NODE, MAX_INPUT_BRIGHTNESS); uint32_t brightness = rgbToBrightness(state); if (max_brightness != MAX_INPUT_BRIGHTNESS) { brightness = brightness * max_brightness / MAX_INPUT_BRIGHTNESS; } set(PANEL_BRIGHTNESS_NODE, brightness); } #ifdef BUTTON_BRIGHTNESS_NODE void Lights::handleButtons(const HwLightState& state) { #ifdef VAR_BUTTON_BRIGHTNESS uint32_t brightness = rgbToBrightness(state); #else uint32_t brightness = (state.color & COLOR_MASK) ? 1 : 0; #endif set(BUTTON_BRIGHTNESS_NODE, brightness); } #endif #ifdef LED_BLINK_NODE void Lights::handleBattery(const HwLightState& state) { mBatteryState = state; setNotificationLED(); } void Lights::handleNotifications(const HwLightState& state) { mNotificationState = state; setNotificationLED(); } void Lights::handleAttention(const HwLightState& state) { mAttentionState = state; setNotificationLED(); } void Lights::setNotificationLED() { int32_t adjusted_brightness = MAX_INPUT_BRIGHTNESS; HwLightState state; #ifdef LED_BLN_NODE bool bln = false; #endif /* LED_BLN_NODE */ if (mNotificationState.color & COLOR_MASK) { adjusted_brightness = LED_BRIGHTNESS_NOTIFICATION; state = mNotificationState; #ifdef LED_BLN_NODE bln = true; #endif /* LED_BLN_NODE */ } else if (mAttentionState.color & COLOR_MASK) { adjusted_brightness = LED_BRIGHTNESS_ATTENTION; state = mAttentionState; if (state.flashMode == FlashMode::HARDWARE) { if (state.flashOnMs > 0 && state.flashOffMs == 0) state.flashMode = FlashMode::NONE; state.color = 0x000000ff; } if (state.flashMode == FlashMode::NONE) { state.color = 0; } } else if (mBatteryState.color & COLOR_MASK) { adjusted_brightness = LED_BRIGHTNESS_BATTERY; state = mBatteryState; } else { set(LED_BLINK_NODE, "0x00000000 0 0"); return; } if (state.flashMode == FlashMode::NONE) { state.flashOnMs = 0; state.flashOffMs = 0; } state.color = calibrateColor(state.color & COLOR_MASK, adjusted_brightness); set(LED_BLINK_NODE, ::android::base::StringPrintf("0x%08x %d %d", state.color, state.flashOnMs, state.flashOffMs)); #ifdef LED_BLN_NODE if (bln) { set(LED_BLN_NODE, (state.color & COLOR_MASK) ? 1 : 0); } #endif /* LED_BLN_NODE */ } uint32_t Lights::calibrateColor(uint32_t color, int32_t brightness) { uint32_t red = ((color >> 16) & 0xFF) * LED_ADJUSTMENT_R; uint32_t green = ((color >> 8) & 0xFF) * LED_ADJUSTMENT_G; uint32_t blue = (color & 0xFF) * LED_ADJUSTMENT_B; return (((red * brightness) / 255) << 16) + (((green * brightness) / 255) << 8) + ((blue * brightness) / 255); } #endif /* LED_BLINK_NODE */ #define AutoHwLight(light) {.id = (int32_t)light, .type = light, .ordinal = 0} ndk::ScopedAStatus Lights::getLights(std::vector *_aidl_return) { for (auto const& light : mLights) { _aidl_return->push_back(AutoHwLight(light.first)); } return ndk::ScopedAStatus::ok(); } uint32_t Lights::rgbToBrightness(const HwLightState& state) { uint32_t color = state.color & COLOR_MASK; return ((77 * ((color >> 16) & 0xff)) + (150 * ((color >> 8) & 0xff)) + (29 * (color & 0xff))) >> 8; } } // namespace light } // namespace hardware } // namespace android } // namespace aidl