aidl: light: Refactor

Change-Id: Ib4ae8e9821dd0fb36e922e2c5f993aa6c0e28be1
This commit is contained in:
Sebastiano Barezzi 2024-04-18 17:34:39 +02:00
parent d43b640a7b
commit ee864f39ea
No known key found for this signature in database
GPG Key ID: 763BD3AE91A7A13F
20 changed files with 941 additions and 339 deletions

View File

@ -1,18 +1,22 @@
//
// Copyright (C) 2021-2022 The LineageOS Project
// Copyright (C) 2021-2024 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "android.hardware.light-service.xiaomi",
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
init_rc: ["android.hardware.light-service.xiaomi.rc"],
vintf_fragments: ["android.hardware.light-service.xiaomi.xml"],
srcs: [
"Backlight.cpp",
"BacklightDevice.cpp",
"Devices.cpp",
"LedDevice.cpp",
"Lights.cpp",
"LED.cpp",
"RgbLedDevice.cpp",
"Utils.cpp",
"service.cpp",
],
@ -21,5 +25,4 @@ cc_binary {
"libbinder_ndk",
"android.hardware.light-V2-ndk",
],
vendor: true,
}

View File

@ -1,82 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Backlight.h"
#include "LED.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class BacklightBrightness : public BacklightDevice {
public:
BacklightBrightness(std::string name) : mBasePath(mkBacklightBasePath + name + "/") {
if (!readFromFile(mBasePath + "max_brightness", &mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
}
};
void setBacklight(uint8_t value) {
writeToFile(mBasePath + "brightness", value * mMaxBrightness / 0xFF);
}
bool exists() { return fileWriteable(mBasePath + "brightness"); }
private:
std::string mBasePath;
uint32_t mMaxBrightness;
inline static const std::string mkBacklightBasePath = "/sys/class/backlight/";
inline static const uint32_t kDefaultMaxBrightness = 255;
};
class LEDBacklight : public BacklightDevice {
public:
LEDBacklight(std::string type) : mLED(type){};
void setBacklight(uint8_t value) { mLED.setBrightness(value); }
bool exists() { return mLED.exists(); }
private:
LED mLED;
};
static const std::string kBacklightDevices[] = {
"backlight",
"panel0-backlight",
};
static const std::string kLedDevices[] = {
"lcd-backlight",
};
BacklightDevice* getBacklightDevice() {
for (auto& device : kBacklightDevices) {
auto backlight = new BacklightBrightness(device);
if (backlight->exists()) {
return backlight;
}
delete backlight;
}
for (auto& device : kLedDevices) {
auto backlight = new LEDBacklight(device);
if (backlight->exists()) {
return backlight;
}
delete backlight;
}
return nullptr;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -1,27 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class BacklightDevice {
public:
virtual ~BacklightDevice() = default;
virtual void setBacklight(uint8_t value) = 0;
virtual bool exists() = 0;
};
BacklightDevice* getBacklightDevice();
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2022-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "BacklightDevice.h"
#define LOG_TAG "BacklightDevice"
#include <android-base/logging.h>
#include <fstream>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const std::string kBacklightBasePath = "/sys/class/backlight/";
static const uint32_t kDefaultMaxBrightness = 255;
static const std::string kBrightnessNode = "brightness";
static const std::string kMaxBrightnessNode = "max_brightness";
BacklightDevice::BacklightDevice(std::string name)
: mName(name), mBasePath(kBacklightBasePath + name + "/") {
if (!readFromFile(mBasePath + kMaxBrightnessNode, mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
}
};
std::string BacklightDevice::getName() const {
return mName;
}
bool BacklightDevice::exists() const {
return std::ifstream(mBasePath + kBrightnessNode).good();
}
bool BacklightDevice::setBrightness(uint8_t value) {
return writeToFile(mBasePath + kBrightnessNode, scaleBrightness(value, mMaxBrightness));
}
void BacklightDevice::dump(int fd) const {
dprintf(fd, "Name: %s", mName.c_str());
dprintf(fd, ", exists: %d", exists());
dprintf(fd, ", base path: %s", mBasePath.c_str());
dprintf(fd, ", max brightness: %u", mMaxBrightness);
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2022-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <string>
#include "IDumpable.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* A Linux backlight device.
* @see https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
*/
class BacklightDevice : public IDumpable {
public:
BacklightDevice() = delete;
/**
* Constructor.
*
* @param name The name of the backlight device
*/
BacklightDevice(std::string name);
/**
* Get the name of the backlight device.
*
* @return std::string The name of the backlight device
*/
std::string getName() const;
/**
* Return whether this backlight device exists.
*
* @return bool true if the backlight device exists, false otherwise
*/
bool exists() const;
/**
* Set the brightness of this backlight device.
*
* @param value The brightness value to set
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(uint8_t value);
void dump(int fd) const override;
private:
std::string mName;
std::string mBasePath;
uint32_t mMaxBrightness;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

217
aidl/light/Devices.cpp Normal file
View File

@ -0,0 +1,217 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Devices.h"
#define LOG_TAG "Devices"
#include <android-base/logging.h>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const std::string kBacklightDevices[] = {
"backlight",
"panel0-backlight",
};
static std::vector<BacklightDevice> getBacklightDevices() {
std::vector<BacklightDevice> devices;
for (const auto& device : kBacklightDevices) {
BacklightDevice backlight(device);
if (backlight.exists()) {
LOG(INFO) << "Found backlight device: " << backlight.getName();
devices.push_back(backlight);
}
}
return devices;
}
static const std::string kLedBacklightDevices[] = {
"lcd-backlight",
};
static std::vector<LedDevice> getBacklightLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kLedBacklightDevices) {
LedDevice backlight(device);
if (backlight.exists()) {
LOG(INFO) << "Found backlight LED device: " << backlight.getName();
devices.push_back(backlight);
}
}
return devices;
}
static const std::string kButtonLedDevices[] = {
"button-backlight",
"button-backlight1",
};
static std::vector<LedDevice> getButtonLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kButtonLedDevices) {
LedDevice button(device);
if (button.exists()) {
LOG(INFO) << "Found button LED device: " << button.getName();
devices.emplace_back(button);
}
}
return devices;
}
static const std::string kRgbLedDevices[][3] = {
{"red", "green", "blue"},
};
static std::vector<RgbLedDevice> getNotificationRgbLedDevices() {
std::vector<RgbLedDevice> devices;
for (const auto& device : kRgbLedDevices) {
LedDevice red(device[0]);
LedDevice green(device[1]);
LedDevice blue(device[2]);
RgbLedDevice rgbLedDevice(red, green, blue);
if (rgbLedDevice.exists()) {
LOG(INFO) << "Found notification RGB LED device: " << red.getName() << ", "
<< green.getName() << ", " << blue.getName();
devices.emplace_back(red, green, blue);
}
}
return devices;
}
static const std::string kNotificationLedDevices[] = {
"white",
};
static std::vector<LedDevice> getNotificationLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kNotificationLedDevices) {
LedDevice notification(device);
if (notification.exists()) {
LOG(INFO) << "Found notification LED device: " << notification.getName();
devices.emplace_back(notification);
}
}
return devices;
}
Devices::Devices()
: mBacklightDevices(getBacklightDevices()),
mBacklightLedDevices(getBacklightLedDevices()),
mButtonLedDevices(getButtonLedDevices()),
mNotificationRgbLedDevices(getNotificationRgbLedDevices()),
mNotificationLedDevices(getNotificationLedDevices()) {
if (!hasBacklightDevices()) {
LOG(INFO) << "No backlight devices found";
}
if (!hasButtonDevices()) {
LOG(INFO) << "No button devices found";
}
if (!hasNotificationDevices()) {
LOG(INFO) << "No notification devices found";
}
}
bool Devices::hasBacklightDevices() const {
return !mBacklightDevices.empty() || !mBacklightLedDevices.empty();
}
bool Devices::hasButtonDevices() const {
return !mButtonLedDevices.empty();
}
bool Devices::hasNotificationDevices() const {
return !mNotificationRgbLedDevices.empty() || !mNotificationLedDevices.empty();
}
void Devices::setBacklightColor(rgb color) {
for (auto& device : mBacklightDevices) {
device.setBrightness(color.toBrightness());
}
for (auto& device : mBacklightLedDevices) {
device.setBrightness(color.toBrightness());
}
}
void Devices::setButtonsColor(rgb color) {
for (auto& device : mButtonLedDevices) {
device.setBrightness(color.toBrightness());
}
}
void Devices::setNotificationColor(rgb color, LightMode mode) {
for (auto& device : mNotificationRgbLedDevices) {
device.setBrightness(color, mode);
}
for (auto& device : mNotificationLedDevices) {
device.setBrightness(color.toBrightness(), mode);
}
}
void Devices::dump(int fd) const {
dprintf(fd, "Backlight devices:\n");
for (const auto& device : mBacklightDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Backlight LED devices:\n");
for (const auto& device : mBacklightLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Button LED devices:\n");
for (const auto& device : mButtonLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Notification RGB LED devices:\n");
for (const auto& device : mNotificationRgbLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Notification LED devices:\n");
for (const auto& device : mNotificationLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
return;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

51
aidl/light/Devices.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <vector>
#include "BacklightDevice.h"
#include "IDumpable.h"
#include "LedDevice.h"
#include "RgbLedDevice.h"
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class Devices : public IDumpable {
public:
Devices();
bool hasBacklightDevices() const;
bool hasButtonDevices() const;
bool hasNotificationDevices() const;
void setBacklightColor(rgb color);
void setButtonsColor(rgb color);
void setNotificationColor(rgb color, LightMode mode = LightMode::STATIC);
void dump(int fd) const override;
private:
// Backlight
std::vector<BacklightDevice> mBacklightDevices;
std::vector<LedDevice> mBacklightLedDevices;
// Buttons
std::vector<LedDevice> mButtonLedDevices;
// Notifications
std::vector<RgbLedDevice> mNotificationRgbLedDevices;
std::vector<LedDevice> mNotificationLedDevices;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

32
aidl/light/IDumpable.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* Interface for dumpable objects using AIDL dump()'s file descriptor.
*/
class IDumpable {
public:
virtual ~IDumpable() = default;
/**
* Write information regarding this object to the given file descriptor using dprintf().
* You should avoid ending newline, since the caller will add it.
* @param fd The file descriptor to write to.
*/
virtual void dump(int fd) const = 0;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2021-2022 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(uint8_t value) {
return writeToFile(mBasePath + (mBreath ? "breath" : "blink"), value);
}
bool LED::setBrightness(uint8_t value) {
return writeToFile(mBasePath + "brightness", value * mMaxBrightness / 0xFF);
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2021-2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <string>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class LED {
public:
LED(std::string type);
bool exists();
bool setBreath(uint8_t value);
bool setBrightness(uint8_t value);
private:
std::string mBasePath;
uint32_t mMaxBrightness;
bool mBreath;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

94
aidl/light/LedDevice.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "LedDevice.h"
#define LOG_TAG "LedDevice"
#include <android-base/logging.h>
#include <fstream>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const uint32_t kDefaultMaxBrightness = 255;
static const std::string kBaseLedsPath = "/sys/class/leds/";
static const std::string kBrightnessNode = "brightness";
static const std::string kMaxBrightnessNode = "max_brightness";
static const std::string kBreathNodes[] = {
"breath",
"blink",
};
LedDevice::LedDevice(std::string name) : mName(name), mBasePath(kBaseLedsPath + name + "/") {
if (!readFromFile(mBasePath + kMaxBrightnessNode, mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
}
for (const auto& node : kBreathNodes) {
if (std::ifstream(mBasePath + node).good()) {
mBreathNode = node;
break;
}
}
}
std::string LedDevice::getName() const {
return mName;
}
bool LedDevice::supportsBreath() const {
return !mBreathNode.empty();
}
bool LedDevice::exists() const {
return std::ifstream(mBasePath + kBrightnessNode).good();
}
bool LedDevice::setBrightness(uint8_t value, LightMode mode) {
// Disable current blinking
if (supportsBreath()) {
writeToFile(mBasePath + mBreathNode, 0);
}
switch (mode) {
case LightMode::BREATH:
if (supportsBreath()) {
return writeToFile(mBasePath + mBreathNode, value > 0 ? 1 : 0);
break;
}
// Fallthrough to static mode if breath is not supported
FALLTHROUGH_INTENDED;
case LightMode::STATIC:
return writeToFile(mBasePath + kBrightnessNode, scaleBrightness(value, mMaxBrightness));
break;
default:
LOG(ERROR) << "Unknown mode: " << mode;
return false;
break;
}
}
void LedDevice::dump(int fd) const {
dprintf(fd, "Name: %s", mName.c_str());
dprintf(fd, ", exists: %d", exists());
dprintf(fd, ", base path: %s", mBasePath.c_str());
dprintf(fd, ", max brightness: %u", mMaxBrightness);
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", breath node: %s", mBreathNode.c_str());
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

82
aidl/light/LedDevice.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <string>
#include "IDumpable.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
enum LightMode {
STATIC,
BREATH,
};
/**
* A Linux LED device.
* @see https://docs.kernel.org/leds/leds-class.html
*/
class LedDevice : public IDumpable {
public:
LedDevice() = delete;
/**
* Constructor.
*
* @param name The name of the LED device
*/
LedDevice(std::string name);
/**
* Get the name of the LED device.
*
* @return std::string The name of the LED device
*/
std::string getName() const;
/**
* Return whether this LED device exists.
*
* @return bool true if the LED device exists, false otherwise
*/
bool exists() const;
/**
* Return whether this LED device supports breathing.
* When it doesn't, calling setBrightness with LightMode::BREATH will behave like
* LightMode::STATIC.
*
* @return bool true if the LED device supports breathing, false otherwise
*/
bool supportsBreath() const;
/**
* Set the brightness of the LED device.
*
* @param value The brightness value to set
* @param mode The light mode to use
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(uint8_t value, LightMode mode = LightMode::STATIC);
void dump(int fd) const override;
private:
std::string mName;
std::string mBasePath;
uint32_t mMaxBrightness;
std::string mBreathNode;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -1,13 +1,14 @@
/*
* Copyright (C) 2021-2022 The LineageOS Project
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Lights.h"
#define LOG_TAG "Lights"
#include <android-base/logging.h>
#include "LED.h"
#include "Utils.h"
namespace aidl {
@ -15,48 +16,23 @@ namespace android {
namespace hardware {
namespace light {
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 }
{ .id = static_cast<int32_t>(light), .ordinal = 0, .type = light }
Lights::Lights() {
mBacklightDevice = getBacklightDevice();
if (mBacklightDevice) {
if (mDevices.hasBacklightDevices()) {
mLights.push_back(AutoHwLight(LightType::BACKLIGHT));
}
for (auto& buttons : kAllButtonsPaths) {
if (!fileWriteable(buttons)) continue;
mButtonsPaths.push_back(buttons);
if (mDevices.hasButtonDevices()) {
mLights.push_back(AutoHwLight(LightType::BUTTONS));
}
if (!mButtonsPaths.empty()) mLights.push_back(AutoHwLight(LightType::BUTTONS));
mWhiteLED = kLEDs[WHITE].exists();
mLights.push_back(AutoHwLight(LightType::BATTERY));
mLights.push_back(AutoHwLight(LightType::NOTIFICATIONS));
mLights.push_back(AutoHwLight(LightType::ATTENTION));
if (mDevices.hasNotificationDevices()) {
mLights.push_back(AutoHwLight(LightType::BATTERY));
mLights.push_back(AutoHwLight(LightType::NOTIFICATIONS));
mLights.push_back(AutoHwLight(LightType::ATTENTION));
}
}
ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state) {
@ -65,27 +41,22 @@ ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state)
LightType type = static_cast<LightType>(id);
switch (type) {
case LightType::BACKLIGHT:
if (mBacklightDevice) mBacklightDevice->setBacklight(color.toBrightness());
mDevices.setBacklightColor(color);
break;
case LightType::BUTTONS:
for (auto& buttons : mButtonsPaths) writeToFile(buttons, color.isLit());
mDevices.setButtonsColor(color);
break;
case LightType::BATTERY:
mLastBatteryState = state;
updateNotificationColor();
break;
case LightType::NOTIFICATIONS:
mLastNotificationsState = state;
updateNotificationColor();
break;
case LightType::ATTENTION:
mLEDMutex.lock();
if (type == LightType::BATTERY)
mLastBatteryState = state;
else if (type == LightType::NOTIFICATIONS)
mLastNotificationState = state;
else if (type == LightType::ATTENTION)
mLastAttentionState = state;
setLED();
mLEDMutex.unlock();
mLastAttentionState = state;
updateNotificationColor();
break;
default:
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@ -96,47 +67,59 @@ ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state)
}
ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* _aidl_return) {
for (const auto& light : mLights) _aidl_return->push_back(light);
for (const auto& light : mLights) {
_aidl_return->push_back(light);
}
return ndk::ScopedAStatus::ok();
}
void Lights::setLED() {
bool rc = true;
binder_status_t Lights::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
dprintf(fd, "Lights AIDL:\n");
dprintf(fd, "\n");
dprintf(fd, "Lights:\n");
for (const auto& light : mLights) {
dprintf(fd, "- %d: LightType::%s\n", light.id, toString(light.type).c_str());
}
dprintf(fd, "\n");
dprintf(fd, "Devices:\n");
mDevices.dump(fd);
dprintf(fd, "\n");
return STATUS_OK;
}
void Lights::updateNotificationColor() {
std::lock_guard<std::mutex> lock(mLedMutex);
bool isBatteryLit = rgb(mLastBatteryState.color).isLit();
bool isAttentionLit = rgb(mLastAttentionState.color).isLit();
const HwLightState state = isBatteryLit ? mLastBatteryState
: isAttentionLit ? mLastAttentionState
: mLastNotificationState;
: mLastNotificationsState;
rgb color(state.color);
uint8_t blink = (state.flashOnMs != 0 && state.flashOffMs != 0);
LightMode lightMode;
switch (state.flashMode) {
case FlashMode::HARDWARE:
case FlashMode::NONE:
lightMode = LightMode::STATIC;
break;
case FlashMode::TIMED:
if (mWhiteLED) {
rc = kLEDs[WHITE].setBreath(blink);
} else {
rc = kLEDs[RED].setBreath(blink && color.red);
rc &= kLEDs[GREEN].setBreath(blink && color.green);
rc &= kLEDs[BLUE].setBreath(blink && color.blue);
}
if (rc) break;
FALLTHROUGH_INTENDED;
case FlashMode::HARDWARE:
lightMode = LightMode::BREATH;
break;
default:
if (mWhiteLED) {
rc = kLEDs[WHITE].setBrightness(color.toBrightness());
} else {
rc = kLEDs[RED].setBrightness(color.red);
rc &= kLEDs[GREEN].setBrightness(color.green);
rc &= kLEDs[BLUE].setBrightness(color.blue);
}
LOG(ERROR) << "Unknown flash mode: " << static_cast<int>(state.flashMode);
lightMode = LightMode::STATIC;
break;
}
mDevices.setNotificationColor(color, lightMode);
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2022 The LineageOS Project
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,10 +8,7 @@
#include <aidl/android/hardware/light/BnLights.h>
#include <mutex>
#include "Backlight.h"
using ::aidl::android::hardware::light::HwLight;
using ::aidl::android::hardware::light::HwLightState;
#include "Devices.h"
namespace aidl {
namespace android {
@ -25,20 +22,19 @@ class Lights : public BnLights {
ndk::ScopedAStatus setLightState(int32_t id, const HwLightState& state) override;
ndk::ScopedAStatus getLights(std::vector<HwLight>* _aidl_return) override;
private:
void setLED();
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
std::vector<HwLight> mLights;
BacklightDevice* mBacklightDevice;
std::vector<std::string> mButtonsPaths;
bool mWhiteLED;
std::mutex mLEDMutex;
Devices mDevices;
HwLightState mLastBatteryState;
HwLightState mLastNotificationState;
HwLightState mLastNotificationsState;
HwLightState mLastAttentionState;
std::mutex mLedMutex;
void updateNotificationColor();
};
} // namespace light

109
aidl/light/RgbLedDevice.cpp Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "RgbLedDevice.h"
#define LOG_TAG "RgbLedDevice"
#include <android-base/logging.h>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
RgbLedDevice::RgbLedDevice(LedDevice red, LedDevice green, LedDevice blue)
: mRed(red), mGreen(green), mBlue(blue), mColors(Color::NONE) {
if (mRed.exists()) {
mColors |= Color::RED;
}
if (mGreen.exists()) {
mColors |= Color::GREEN;
}
if (mBlue.exists()) {
mColors |= Color::BLUE;
}
}
bool RgbLedDevice::exists() const {
return mColors != Color::NONE;
}
bool RgbLedDevice::supportsBreath() const {
return (!mRed.exists() || mRed.supportsBreath()) &&
(!mGreen.exists() || mGreen.supportsBreath()) &&
(!mBlue.exists() || mBlue.supportsBreath());
}
bool RgbLedDevice::setBrightness(rgb color, LightMode mode) {
bool rc = true;
if (mColors == Color::NONE) {
LOG(ERROR) << "No LEDs found";
return false;
}
if (mode == LightMode::BREATH && !supportsBreath()) {
// Not all LEDs support breathing, force static mode
mode = LightMode::STATIC;
}
if (mColors == Color::ALL) {
rc &= mRed.setBrightness(color.red, mode);
rc &= mGreen.setBrightness(color.green, mode);
rc &= mBlue.setBrightness(color.blue, mode);
} else {
// Check if we have only one LED
if (mColors == Color::RED) {
rc &= mRed.setBrightness(color.toBrightness(), mode);
} else if (mColors == Color::GREEN) {
rc &= mGreen.setBrightness(color.toBrightness(), mode);
} else if (mColors == Color::BLUE) {
rc &= mBlue.setBrightness(color.toBrightness(), mode);
} else {
// We only have two LEDs, blend the missing color in the other two
if ((mColors & Color::RED) == Color::NONE) {
rc &= mBlue.setBrightness((color.blue + color.red) / 2, mode);
rc &= mGreen.setBrightness((color.green + color.red) / 2, mode);
} else if ((mColors & Color::GREEN) == Color::NONE) {
rc &= mRed.setBrightness((color.red + color.green) / 2, mode);
rc &= mBlue.setBrightness((color.blue + color.green) / 2, mode);
} else if ((mColors & Color::BLUE) == Color::NONE) {
rc &= mRed.setBrightness((color.red + color.blue) / 2, mode);
rc &= mGreen.setBrightness((color.green + color.blue) / 2, mode);
}
}
}
return rc;
}
void RgbLedDevice::dump(int fd) const {
dprintf(fd, "Exists: %d", exists());
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", colors:");
if (mColors != Color::NONE) {
if (mColors & Color::RED) {
dprintf(fd, "\nRed: ");
mRed.dump(fd);
}
if (mColors & Color::GREEN) {
dprintf(fd, "\nGreen: ");
mGreen.dump(fd);
}
if (mColors & Color::BLUE) {
dprintf(fd, "\nBlue: ");
mBlue.dump(fd);
}
} else {
dprintf(fd, " None");
}
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

84
aidl/light/RgbLedDevice.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "IDumpable.h"
#include "LedDevice.h"
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* A pool of LED devices that will be toggled based on the wanted color.
* Support all types of LED combinations, with a maximum of 3 LEDs.
* Also supports 2 color LEDs (*cough* ASUS *cough*).
*/
class RgbLedDevice : public IDumpable {
public:
RgbLedDevice() = delete;
/**
* Constructor.
*
* @param red The red LED device
* @param green The green LED device
* @param blue The blue LED device
*/
RgbLedDevice(LedDevice red, LedDevice green, LedDevice blue);
/**
* Return whether this RGB LED device exists.
* This is true when at least one of the LEDs exists.
*
* @return bool true if the RGB LED device exists, false otherwise
*/
bool exists() const;
/**
* Return whether this RGB LED device supports breathing.
* This is true when all existing LEDs support breathing.
* In case this is false, calling setBrightness with LightMode::BREATH will behave like
* LightMode::STATIC.
*
* @return bool true if the RGB LED device supports breathing, false otherwise
*/
bool supportsBreath() const;
/**
* Set the brightness of this RGB LED device.
*
* @param color The color to set
* @param mode The mode to set
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(rgb color, LightMode mode = LightMode::STATIC);
void dump(int fd) const override;
enum Color {
NONE = 0,
RED = 1 << 0,
GREEN = 1 << 1,
BLUE = 1 << 2,
ALL = RED | GREEN | BLUE,
};
private:
LedDevice mRed;
LedDevice mGreen;
LedDevice mBlue;
int mColors;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@ -1,49 +1,19 @@
/*
* Copyright (C) 2021-2022 The LineageOS Project
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Utils.h"
#define LOG_TAG "android.hardware.light-service.xiaomi"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <unistd.h>
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);
}
rgb::rgb() : red(0), green(0), blue(0) {}
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));
}
rgb::rgb(uint8_t r, uint8_t g, uint8_t b) : red(r), green(g), blue(b){};
rgb::rgb(uint32_t color) {
// Extract brightness from AARRGGBB.
@ -55,7 +25,7 @@ rgb::rgb(uint32_t color) {
blue = color & 0xFF;
// Scale RGB colors if a brightness has been applied by the user
if (alpha > 0 && alpha < 255) {
if (alpha > 0 && alpha < 0xFF) {
red = red * alpha / 0xFF;
green = green * alpha / 0xFF;
blue = blue * alpha / 0xFF;
@ -66,8 +36,16 @@ bool rgb::isLit() {
return !!red || !!green || !!blue;
}
static constexpr uint8_t kRedWeight = 77;
static constexpr uint8_t kGreenWeight = 150;
static constexpr uint8_t kBlueWeight = 29;
uint8_t rgb::toBrightness() {
return (77 * red + 150 * green + 29 * blue) >> 8;
return (kRedWeight * red + kGreenWeight * green + kBlueWeight * blue) >> 8;
}
uint32_t scaleBrightness(uint8_t brightness, uint32_t maxBrightness) {
return brightness * maxBrightness / 0xFF;
}
} // namespace light

View File

@ -1,11 +1,13 @@
/*
* Copyright (C) 2021-2022 The LineageOS Project
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <fstream>
#include <string>
namespace aidl {
@ -14,9 +16,9 @@ namespace hardware {
namespace light {
struct rgb {
rgb(uint8_t r, uint8_t g, uint8_t b) : red(r), green(g), blue(b){};
rgb();
rgb(uint8_t r, uint8_t g, uint8_t b);
rgb(uint32_t color);
rgb() : red(0), green(0), blue(0){};
uint8_t red;
uint8_t green;
@ -26,10 +28,31 @@ struct rgb {
uint8_t toBrightness();
};
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);
uint32_t scaleBrightness(uint8_t brightness, uint32_t maxBrightness);
template <typename T>
bool readFromFile(const std::string& file, T& content) {
std::ifstream fileStream(file);
if (!fileStream) {
return false;
}
fileStream >> content;
return true;
}
template <typename T>
bool writeToFile(const std::string& file, const T content) {
std::ofstream fileStream(file);
if (!fileStream) {
return false;
}
fileStream << content;
return true;
}
} // namespace light
} // namespace hardware

View File

@ -1,38 +1,46 @@
on early-boot
# Notification LEDs
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
# Backlight
# Backlight devices
chown system system /sys/class/backlight/backlight/brightness
chown system system /sys/class/backlight/backlight/max_brightness
chown system system /sys/class/backlight/panel0-backlight/brightness
chown system system /sys/class/backlight/panel0-backlight/max_brightness
# LED devices
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/button-backlight/blink
chown system system /sys/class/leds/button-backlight/breath
chown system system /sys/class/leds/button-backlight/brightness
chown system system /sys/class/leds/button-backlight/max_brightness
chown system system /sys/class/leds/button-backlight1/blink
chown system system /sys/class/leds/button-backlight1/breath
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/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/lcd-backlight/blink
chown system system /sys/class/leds/lcd-backlight/breath
chown system system /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/lcd-backlight/max_brightness
# Buttons
chown system system /sys/class/leds/button-backlight/brightness
chown system system /sys/class/leds/button-backlight1/brightness
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/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
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.xiaomi
class hal

View File

@ -1,11 +1,13 @@
/*
* Copyright (C) 2021 The LineageOS Project
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Lights.h"
#define LOG_TAG "android.hardware.light-service.xiaomi"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>