aidl: light: Add support for timed mode

Co-authored-by: Sebastiano Barezzi <seba@sebaubuntu.dev>
Change-Id: I23623c7527cf98230f890935a4742f86adc3b3ea
This commit is contained in:
Bruno Martins 2024-06-18 01:45:59 +02:00 committed by Sebastiano Barezzi
parent ee864f39ea
commit 7329fd774f
No known key found for this signature in database
GPG Key ID: 763BD3AE91A7A13F
8 changed files with 159 additions and 21 deletions

View File

@ -158,13 +158,14 @@ void Devices::setButtonsColor(rgb color) {
}
}
void Devices::setNotificationColor(rgb color, LightMode mode) {
void Devices::setNotificationColor(rgb color, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
for (auto& device : mNotificationRgbLedDevices) {
device.setBrightness(color, mode);
device.setBrightness(color, mode, flashOnMs, flashOffMs);
}
for (auto& device : mNotificationLedDevices) {
device.setBrightness(color.toBrightness(), mode);
device.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
}
}

View File

@ -28,7 +28,8 @@ class Devices : public IDumpable {
void setBacklightColor(rgb color);
void setButtonsColor(rgb color);
void setNotificationColor(rgb color, LightMode mode = LightMode::STATIC);
void setNotificationColor(rgb color, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
void dump(int fd) const override;

View File

@ -29,6 +29,16 @@ static const std::string kBreathNodes[] = {
"blink",
};
static const std::string kBlinkNode = "blink";
static const std::string kStartIdxNode = "start_idx";
static const std::string kDutyPctsNode = "duty_pcts";
static const std::string kPauseLoNode = "pause_lo";
static const std::string kPauseHiNode = "pause_hi";
static const std::string kRampStepMsNode = "ramp_step_ms";
static constexpr int kRampSteps = 8;
static constexpr int kRampMaxStepDurationMs = 50;
LedDevice::LedDevice(std::string name) : mName(name), mBasePath(kBaseLedsPath + name + "/") {
if (!readFromFile(mBasePath + kMaxBrightnessNode, mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
@ -40,6 +50,13 @@ LedDevice::LedDevice(std::string name) : mName(name), mBasePath(kBaseLedsPath +
break;
}
}
mSupportsTimed = std::ifstream(mBasePath + kBlinkNode).good() &&
std::ifstream(mBasePath + kStartIdxNode).good() &&
std::ifstream(mBasePath + kDutyPctsNode).good() &&
std::ifstream(mBasePath + kPauseLoNode).good() &&
std::ifstream(mBasePath + kPauseHiNode).good() &&
std::ifstream(mBasePath + kRampStepMsNode).good();
}
std::string LedDevice::getName() const {
@ -50,17 +67,57 @@ bool LedDevice::supportsBreath() const {
return !mBreathNode.empty();
}
bool LedDevice::supportsTimed() const {
return mSupportsTimed;
}
bool LedDevice::exists() const {
return std::ifstream(mBasePath + kBrightnessNode).good();
}
bool LedDevice::setBrightness(uint8_t value, LightMode mode) {
static std::string getScaledDutyPercent(uint8_t brightness) {
std::string output;
for (int i = 0; i <= kRampSteps; i++) {
if (i != 0) {
output += ",";
}
output += std::to_string(i * 100 * brightness / (0xFF * kRampSteps));
}
return output;
}
bool LedDevice::setBrightness(uint8_t value, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
// Disable current blinking
if (mSupportsTimed) {
writeToFile(mBasePath + kBlinkNode, 0);
}
if (supportsBreath()) {
writeToFile(mBasePath + mBreathNode, 0);
}
switch (mode) {
case LightMode::TIMED:
if (mSupportsTimed) {
int32_t stepDuration = kRampMaxStepDurationMs;
int32_t pauseLo = flashOffMs;
int32_t pauseHi = flashOnMs - (stepDuration * kRampSteps * 2);
if (pauseHi < 0) {
stepDuration = flashOnMs / (kRampSteps * 2);
pauseHi = 0;
}
return writeToFile(mBasePath + kStartIdxNode, 0) &&
writeToFile(mBasePath + kDutyPctsNode, getScaledDutyPercent(value)) &&
writeToFile(mBasePath + kPauseLoNode, pauseLo) &&
writeToFile(mBasePath + kPauseHiNode, pauseHi) &&
writeToFile(mBasePath + kRampStepMsNode, stepDuration) &&
writeToFile(mBasePath + kBlinkNode, 1);
}
// Fallthrough to breath mode if timed is not supported
FALLTHROUGH_INTENDED;
case LightMode::BREATH:
if (supportsBreath()) {
return writeToFile(mBasePath + mBreathNode, value > 0 ? 1 : 0);
@ -85,6 +142,7 @@ void LedDevice::dump(int fd) const {
dprintf(fd, ", base path: %s", mBasePath.c_str());
dprintf(fd, ", max brightness: %u", mMaxBrightness);
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", supports timed: %d", supportsTimed());
dprintf(fd, ", breath node: %s", mBreathNode.c_str());
}

View File

@ -18,6 +18,7 @@ namespace light {
enum LightMode {
STATIC,
BREATH,
TIMED,
};
/**
@ -58,6 +59,15 @@ class LedDevice : public IDumpable {
*/
bool supportsBreath() const;
/**
* Return whether this LED device supports timed mode.
* When it doesn't, calling setBrightness with LightMode::TIMED will behave like
* LightMode::BREATH.
*
* @return bool true if the LED device supports timed mode, false otherwise
*/
bool supportsTimed() const;
/**
* Set the brightness of the LED device.
*
@ -65,7 +75,8 @@ class LedDevice : public IDumpable {
* @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);
bool setBrightness(uint8_t value, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
void dump(int fd) const override;
@ -74,6 +85,7 @@ class LedDevice : public IDumpable {
std::string mBasePath;
uint32_t mMaxBrightness;
std::string mBreathNode;
bool mSupportsTimed;
};
} // namespace light

View File

@ -109,6 +109,8 @@ void Lights::updateNotificationColor() {
lightMode = LightMode::STATIC;
break;
case FlashMode::TIMED:
lightMode = LightMode::TIMED;
break;
case FlashMode::HARDWARE:
lightMode = LightMode::BREATH;
break;
@ -118,7 +120,7 @@ void Lights::updateNotificationColor() {
break;
}
mDevices.setNotificationColor(color, lightMode);
mDevices.setNotificationColor(color, lightMode, state.flashOnMs, state.flashOffMs);
return;
}

View File

@ -38,7 +38,14 @@ bool RgbLedDevice::supportsBreath() const {
(!mBlue.exists() || mBlue.supportsBreath());
}
bool RgbLedDevice::setBrightness(rgb color, LightMode mode) {
bool RgbLedDevice::supportsTimed() const {
return (!mRed.exists() || mRed.supportsTimed()) &&
(!mGreen.exists() || mGreen.supportsTimed()) &&
(!mBlue.exists() || mBlue.supportsTimed());
}
bool RgbLedDevice::setBrightness(rgb color, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
bool rc = true;
if (mColors == Color::NONE) {
@ -46,34 +53,44 @@ bool RgbLedDevice::setBrightness(rgb color, LightMode mode) {
return false;
}
if (mode == LightMode::TIMED && !supportsTimed()) {
// Not all LEDs support timed mode, force breathing mode
mode = LightMode::BREATH;
}
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);
rc &= mRed.setBrightness(color.red, mode, flashOnMs, flashOffMs);
rc &= mGreen.setBrightness(color.green, mode, flashOnMs, flashOffMs);
rc &= mBlue.setBrightness(color.blue, mode, flashOnMs, flashOffMs);
} else {
// Check if we have only one LED
if (mColors == Color::RED) {
rc &= mRed.setBrightness(color.toBrightness(), mode);
rc &= mRed.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} else if (mColors == Color::GREEN) {
rc &= mGreen.setBrightness(color.toBrightness(), mode);
rc &= mGreen.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} else if (mColors == Color::BLUE) {
rc &= mBlue.setBrightness(color.toBrightness(), mode);
rc &= mBlue.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} 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);
rc &= mBlue.setBrightness((color.blue + color.red) / 2, mode, flashOnMs,
flashOffMs);
rc &= mGreen.setBrightness((color.green + color.red) / 2, mode, flashOnMs,
flashOffMs);
} 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);
rc &= mRed.setBrightness((color.red + color.green) / 2, mode, flashOnMs,
flashOffMs);
rc &= mBlue.setBrightness((color.blue + color.green) / 2, mode, flashOnMs,
flashOffMs);
} 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);
rc &= mRed.setBrightness((color.red + color.blue) / 2, mode, flashOnMs, flashOffMs);
rc &= mGreen.setBrightness((color.green + color.blue) / 2, mode, flashOnMs,
flashOffMs);
}
}
}
@ -84,6 +101,7 @@ bool RgbLedDevice::setBrightness(rgb color, LightMode mode) {
void RgbLedDevice::dump(int fd) const {
dprintf(fd, "Exists: %d", exists());
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", supports timed: %d", supportsTimed());
dprintf(fd, ", colors:");
if (mColors != Color::NONE) {
if (mColors & Color::RED) {

View File

@ -51,6 +51,16 @@ class RgbLedDevice : public IDumpable {
*/
bool supportsBreath() const;
/**
* Return whether this RGB LED device supports timed mode.
* This is true when all existing LEDs support timed mode.
* In case this is false, calling setBrightness with LightMode::TIMED will behave like
* LightMode::BREATH.
*
* @return bool true if the RGB LED device supports timed mode, false otherwise
*/
bool supportsTimed() const;
/**
* Set the brightness of this RGB LED device.
*
@ -58,7 +68,8 @@ class RgbLedDevice : public IDumpable {
* @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);
bool setBrightness(rgb color, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
void dump(int fd) const override;

View File

@ -10,37 +10,72 @@ on early-boot
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/duty_pcts
chown system system /sys/class/leds/blue/max_brightness
chown system system /sys/class/leds/blue/pause_hi
chown system system /sys/class/leds/blue/pause_lo
chown system system /sys/class/leds/blue/ramp_step_ms
chown system system /sys/class/leds/blue/start_idx
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/duty_pcts
chown system system /sys/class/leds/button-backlight/max_brightness
chown system system /sys/class/leds/button-backlight/pause_hi
chown system system /sys/class/leds/button-backlight/pause_lo
chown system system /sys/class/leds/button-backlight/ramp_step_ms
chown system system /sys/class/leds/button-backlight/start_idx
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/duty_pcts
chown system system /sys/class/leds/button-backlight1/max_brightness
chown system system /sys/class/leds/button-backlight1/pause_hi
chown system system /sys/class/leds/button-backlight1/pause_lo
chown system system /sys/class/leds/button-backlight1/ramp_step_ms
chown system system /sys/class/leds/button-backlight1/start_idx
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/duty_pcts
chown system system /sys/class/leds/green/max_brightness
chown system system /sys/class/leds/green/pause_hi
chown system system /sys/class/leds/green/pause_lo
chown system system /sys/class/leds/green/ramp_step_ms
chown system system /sys/class/leds/green/start_idx
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/duty_pcts
chown system system /sys/class/leds/lcd-backlight/max_brightness
chown system system /sys/class/leds/lcd-backlight/pause_hi
chown system system /sys/class/leds/lcd-backlight/pause_lo
chown system system /sys/class/leds/lcd-backlight/ramp_step_ms
chown system system /sys/class/leds/lcd-backlight/start_idx
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/duty_pcts
chown system system /sys/class/leds/red/max_brightness
chown system system /sys/class/leds/red/pause_hi
chown system system /sys/class/leds/red/pause_lo
chown system system /sys/class/leds/red/ramp_step_ms
chown system system /sys/class/leds/red/start_idx
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/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
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.xiaomi
class hal