summaryrefslogtreecommitdiff
path: root/light
diff options
context:
space:
mode:
Diffstat (limited to 'light')
-rw-r--r--light/Android.bp14
-rw-r--r--light/Light.cpp275
-rw-r--r--light/Light.h46
-rw-r--r--light/android.hardware.light@2.0-service.xiaomi_sdm660.rc12
-rw-r--r--light/service.cpp14
5 files changed, 176 insertions, 185 deletions
diff --git a/light/Android.bp b/light/Android.bp
index e05d16d..7a2474b 100644
--- a/light/Android.bp
+++ b/light/Android.bp
@@ -19,14 +19,12 @@ cc_binary {
init_rc: ["android.hardware.light@2.0-service.xiaomi_sdm660.rc"],
srcs: ["service.cpp", "Light.cpp"],
shared_libs: [
- "libhardware",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libhwbinder",
- "libutils",
- "android.hardware.light@2.0",
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.hardware.light@2.0",
],
relative_install_path : "hw",
- proprietary: true,
+ vendor: true,
}
diff --git a/light/Light.cpp b/light/Light.cpp
index e6d9349..0286b6a 100644
--- a/light/Light.cpp
+++ b/light/Light.cpp
@@ -1,5 +1,6 @@
/*
* 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,80 +15,59 @@
* limitations under the License.
*/
-//Author := dev_harsh1998, Isaac Chen
+// Author := dev_harsh1998, Isaac Chen
-#define LOG_TAG "android.hardware.light@2.0-service.xiaomi_sdm660"
+#define LOG_TAG "android.hardware.light@2.0-impl.xiaomi_sdm660"
+/* #define LOG_NDEBUG 0 */
-#include <log/log.h>
-#include <fstream>
#include "Light.h"
-namespace android {
-namespace hardware {
-namespace light {
-namespace V2_0 {
-namespace implementation {
+#include <android-base/file.h>
+#include <android-base/logging.h>
-#define LEDS "/sys/class/leds/"
-#define LCD_LED LEDS "lcd-backlight/"
-#define BRIGHTNESS "brightness"
-#define WHITE LEDS "white/"
-#define BLINK "blink"
-#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"
+namespace {
-#define MAX_LED_BRIGHTNESS 255
-#define MAX_LCD_BRIGHTNESS 4095
+#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)
-/*
- * 8 duty percent steps.
- */
-#define RAMP_STEPS 8
-/*
- * Each step will stay on for 50ms by default.
- */
-#define RAMP_STEP_DURATION 50
-/*
- * 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};
+#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(white), x))
-/*
- * Write value to path and close file.
- */
-static void set(std::string path, std::string value) {
- std::ofstream file(path);
- /* Only write brightness value if stream is open, alive & well */
- if (file.is_open()) {
- file << value;
- } else {
- /* Fire a warning a bail out */
- ALOGE("failed to write %s to %s", value.c_str(), path.c_str());
- return;
- }
+using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
+
+// Default max brightness
+constexpr auto kDefaultMaxLedBrightness = 255;
+constexpr auto kDefaultMaxScreenBrightness = 4095;
+
+// Each step will stay on for 50ms by default.
+constexpr auto kRampStepDuration = 50;
+
+// Each value represents a duty percent (0 - 100) for the led pwm.
+constexpr std::array kBrightnessRamp = {0, 12, 25, 37, 50, 72, 85, 100};
+
+// Write value to path and close file.
+bool WriteToFile(const std::string& path, uint32_t content) {
+ return WriteStringToFile(std::to_string(content), path);
}
-static void set(std::string path, int value) {
- set(path, std::to_string(value));
+bool WriteToFile(const std::string& path, const std::string& content) {
+ return WriteStringToFile(content, path);
}
-static uint32_t getBrightness(const LightState& state) {
- uint32_t alpha, red, green, blue;
+uint32_t RgbaToBrightness(uint32_t color) {
+ // Extract brightness from AARRGGBB.
+ uint32_t alpha = (color >> 24) & 0xFF;
- /*
- * Extract brightness from AARRGGBB.
- */
- alpha = (state.color >> 24) & 0xFF;
- red = (state.color >> 16) & 0xFF;
- green = (state.color >> 8) & 0xFF;
- blue = state.color & 0xFF;
+ // Retrieve each of the RGB colors
+ uint32_t red = (color >> 16) & 0xFF;
+ uint32_t green = (color >> 8) & 0xFF;
+ uint32_t blue = 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;
@@ -97,130 +77,133 @@ static uint32_t getBrightness(const LightState& state) {
return (77 * red + 150 * green + 29 * blue) >> 8;
}
+inline uint32_t RgbaToBrightness(uint32_t color, uint32_t max_brightness) {
+ return RgbaToBrightness(color) * max_brightness / 0xFF;
+}
+
/*
* 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;
+std::string GetScaledDutyPcts(uint32_t brightness) {
+ std::stringstream ramp;
- for (auto const& step : BRIGHTNESS_RAMP) {
- ramp += pad + std::to_string(step * brightness / 0xFF);
- pad = ",";
+ for (size_t i = 0; i < kBrightnessRamp.size(); i++) {
+ if (i > 0) ramp << ",";
+ ramp << kBrightnessRamp[i] * brightness / 0xFF;
}
- return ramp;
+ return ramp.str();
}
-static inline uint32_t scaleBrightness(uint32_t brightness, uint32_t maxBrightness) {
- return brightness * maxBrightness / 0xFF;
+inline bool IsLit(uint32_t color) {
+ return color & 0x00ffffff;
}
-static inline uint32_t getScaledBrightness(const LightState& state, uint32_t maxBrightness) {
- return scaleBrightness(getBrightness(state), maxBrightness);
-}
+} // anonymous namespace
-static void handleXiaomiBacklight(Type /*type*/, const LightState& state) {
- uint32_t brightness = getScaledBrightness(state, MAX_LCD_BRIGHTNESS);
- set(LCD_LED BRIGHTNESS, brightness);
-}
-
-static void setNotification(const LightState& state) {
- uint32_t whiteBrightness = getScaledBrightness(state, MAX_LED_BRIGHTNESS);
-
- /* Turn off the leds (initially) */
- set(WHITE 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;
+namespace android {
+namespace hardware {
+namespace light {
+namespace V2_0 {
+namespace implementation {
- if (pauseHi < 0) {
- pauseHi = 0;
- }
+Light::Light() {
+ std::string buf;
- /* White */
- set(WHITE START_IDX, 0 * RAMP_STEPS);
- set(WHITE DUTY_PCTS, getScaledRamp(whiteBrightness));
- set(WHITE PAUSE_LO, pauseLo);
- set(WHITE PAUSE_HI, pauseHi);
- set(WHITE RAMP_STEP_MS, stepDuration);
- set(WHITE BLINK, 1);
+ if (ReadFileToString(LCD_ATTR(max_brightness), &buf)) {
+ max_screen_brightness_ = std::stoi(buf);
} else {
- set(WHITE BRIGHTNESS, whiteBrightness);
+ max_screen_brightness_ = kDefaultMaxScreenBrightness;
+ LOG(ERROR) << "Failed to read max screen brightness, fallback to "
+ << kDefaultMaxLedBrightness;
}
-}
-
-static inline bool isLit(const LightState& state) {
- return state.color & 0x00ffffff;
-}
-/*
- * Keep sorted in the order of importance.
- */
-static const LightState offState = {};
-static std::vector<std::pair<Type, LightState>> notificationStates = {
- { Type::ATTENTION, offState },
- { Type::NOTIFICATIONS, offState },
- { Type::BATTERY, offState },
-};
-
-static void handleXiaomiNotification(Type type, const LightState& state) {
- for(auto it : notificationStates) {
- if (it.first == type) {
- it.second = state;
- }
-
- if (isLit(it.second)) {
- setNotification(it.second);
- return;
- }
+ 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;
}
-
- setNotification(offState);
}
-static std::map<Type, std::function<void(Type type, const LightState&)>> lights = {
- {Type::BACKLIGHT, handleXiaomiBacklight},
- {Type::NOTIFICATIONS, handleXiaomiNotification},
- {Type::BATTERY, handleXiaomiNotification},
- {Type::ATTENTION, handleXiaomiNotification},
-};
-
-Light::Light() {}
-
Return<Status> Light::setLight(Type type, const LightState& state) {
- auto it = lights.find(type);
+ auto it = lights_.find(type);
- if (it == lights.end()) {
+ if (it == lights_.end()) {
return Status::LIGHT_NOT_SUPPORTED;
}
- /*
- * Lock global mutex until light state is updated.
- */
-
- std::lock_guard<std::mutex> lock(globalLock);
it->second(type, state);
+
return Status::SUCCESS;
}
Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
std::vector<Type> types;
- for (auto const& light : lights) types.push_back(light.first);
+ 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(state.color))) {
+ found = true;
+ LOG(DEBUG) << __func__ << ": type=" << toString(cur_type);
+ applyNotificationState(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(blink), 0);
+
+ if (state.flashMode == Flash::TIMED && state.flashOnMs > 0 && state.flashOffMs > 0) {
+ /*
+ * 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 step_duration = kRampStepDuration;
+ int32_t pause_hi = state.flashOnMs - (step_duration * kBrightnessRamp.size() * 2);
+ if (pause_hi < 0) {
+ step_duration = state.flashOnMs / (kBrightnessRamp.size() * 2);
+ pause_hi = 0;
+ }
+
+ LOG(DEBUG) << __func__ << ": color=" << std::hex << state.color << std::dec
+ << " onMs=" << state.flashOnMs << " offMs=" << state.flashOffMs;
+
+ // White
+ WriteToFile(WHITE_ATTR(start_idx), 0);
+ WriteToFile(WHITE_ATTR(duty_pcts), GetScaledDutyPcts(white_brightness));
+ WriteToFile(WHITE_ATTR(pause_lo), static_cast<uint32_t>(state.flashOffMs));
+ WriteToFile(WHITE_ATTR(pause_hi), static_cast<uint32_t>(pause_hi));
+ WriteToFile(WHITE_ATTR(ramp_step_ms), static_cast<uint32_t>(step_duration));
+ WriteToFile(WHITE_ATTR(blink), 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 311b7de..8427148 100644
--- a/light/Light.h
+++ b/light/Light.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 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.
@@ -13,14 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
-#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
+
+#pragma once
#include <android/hardware/light/2.0/ILight.h>
-#include <hardware/lights.h>
-#include <hidl/Status.h>
-#include <map>
-#include <mutex>
+
+#include <unordered_map>
namespace android {
namespace hardware {
@@ -29,22 +27,38 @@ namespace V2_0 {
namespace implementation {
using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
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();
+ public:
+ Light();
+
+ Return<Status> setLight(Type type, const LightState& state) override;
+ Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
- Return<Status> setLight(Type type, const LightState& state) override;
- Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
+ private:
+ void setLightBacklight(Type type, const LightState& state);
+ void setLightNotification(Type type, const LightState& state);
+ void applyNotificationState(const LightState& state);
- private:
- std::mutex globalLock;
+ uint32_t max_led_brightness_;
+ uint32_t max_screen_brightness_;
+
+ std::unordered_map<Type, std::function<void(Type type, const LightState&)>> lights_{
+ {Type::ATTENTION, [this](auto&&... args) { setLightNotification(args...); }},
+ {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<std::pair<Type, LightState>, 3> notif_states_ = {{
+ {Type::ATTENTION, {}},
+ {Type::NOTIFICATIONS, {}},
+ {Type::BATTERY, {}},
+ }};
};
} // namespace implementation
@@ -52,5 +66,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 7dac2e6..969bdac 100644
--- a/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc
+++ b/light/android.hardware.light@2.0-service.xiaomi_sdm660.rc
@@ -3,21 +3,19 @@ on boot
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/lcd-backlight/max_brightness
+
+ start vendor.light-hal-2-0
service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service.xiaomi_sdm660
class hal
user system
group system
shutdown critical
+ disabled
diff --git a/light/service.cpp b/light/service.cpp
index 8f6fa88..27a4ebf 100644
--- a/light/service.cpp
+++ b/light/service.cpp
@@ -1,5 +1,6 @@
/*
- * Copyright 2018 The Android Open Source 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.
@@ -16,6 +17,7 @@
#define LOG_TAG "android.hardware.light@2.0-service.xiaomi_sdm660"
+#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include "Light.h"
@@ -23,28 +25,26 @@
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() {
- android::sp<ILight> service = new Light();
+ android::sp<Light> service = new Light();
configureRpcThreadpool(1, true);
status_t status = service->registerAsService();
if (status != OK) {
- ALOGE("Cannot register Light HAL service.");
+ LOG(ERROR) << "Cannot register Light HAL service.";
return 1;
}
- ALOGI("Light HAL service ready.");
+ LOG(DEBUG) << "Light HAL service ready.";
joinRpcThreadpool();
- ALOGI("Light HAL service failed to join thread pool.");
+ LOG(ERROR) << "Light HAL service failed to join thread pool.";
return 1;
}