237 lines
7.2 KiB
C++
237 lines
7.2 KiB
C++
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "Lights.h"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <log/log.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include <aidl/android/hardware/light/LightType.h>
|
|
#include <aidl/android/hardware/light/FlashMode.h>
|
|
|
|
using namespace std;
|
|
|
|
namespace aidl {
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace light {
|
|
|
|
static int write_int(const char* path, int value) {
|
|
int fd;
|
|
|
|
fd = open(path, O_RDWR);
|
|
if (fd >= 0) {
|
|
char buf[20];
|
|
int bytes = snprintf(buf, sizeof(buf), "%d\n", value);
|
|
ssize_t amt = write(fd, buf, (size_t)bytes);
|
|
close(fd);
|
|
return amt == -1? -errno : 0;
|
|
} else {
|
|
ALOGE("write_int() failed to open %s:%s\n", path, strerror(errno));
|
|
return -errno;
|
|
}
|
|
}
|
|
|
|
static int state2brightbess(const HwLightState& state) {
|
|
int color = state.color;
|
|
return ((77*((color>>16)&0x00ff))
|
|
+ (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
|
|
}
|
|
|
|
const char* getDriverPath(LightType type) {
|
|
switch (type) {
|
|
case LightType::BACKLIGHT:
|
|
return "/sys/class/backlight/backlight/brightness";
|
|
case LightType::BUTTONS:
|
|
return "/sys/class/leds/button-backlight/brightness";
|
|
case LightType::BATTERY:
|
|
case LightType::NOTIFICATIONS:
|
|
case LightType::ATTENTION:
|
|
return "/sys/class/leds";
|
|
case LightType::BLUETOOTH:
|
|
case LightType::WIFI:
|
|
case LightType::MICROPHONE:
|
|
case LightType::KEYBOARD:
|
|
default:
|
|
return "/not_supported";
|
|
}
|
|
}
|
|
|
|
static int setLightFromType(LightType type, const HwLightState& state) {
|
|
int err = 0;
|
|
switch (type) {
|
|
case LightType::BACKLIGHT:
|
|
case LightType::BUTTONS: {
|
|
int brightness = state2brightbess(state);
|
|
err = write_int(getDriverPath(type), brightness);
|
|
break;
|
|
}
|
|
case LightType::BATTERY:
|
|
case LightType::NOTIFICATIONS:
|
|
case LightType::ATTENTION: {
|
|
int red, green, blue;
|
|
int blink;
|
|
int onMS, offMS;
|
|
unsigned int colorRGB;
|
|
std::string led_path(getDriverPath(type));
|
|
|
|
switch (state.flashMode) {
|
|
case FlashMode::TIMED: {
|
|
onMS = state.flashOnMs;
|
|
offMS = state.flashOffMs;
|
|
break;
|
|
}
|
|
case FlashMode::NONE:
|
|
case FlashMode::HARDWARE:
|
|
default: {
|
|
onMS = 0;
|
|
offMS = 0;
|
|
break;
|
|
}
|
|
}
|
|
colorRGB = state.color;
|
|
red = (colorRGB >> 16) & 0xFF;
|
|
green = (colorRGB >> 8) & 0xFF;
|
|
blue = colorRGB & 0xFF;
|
|
if (onMS > 0 && offMS > 0) {
|
|
if (onMS == offMS) blink = 2;
|
|
else blink = 1;
|
|
} else {
|
|
blink = 0;
|
|
}
|
|
if (blink) {
|
|
if (red) {
|
|
if (write_int((led_path + "/led_r/blink").c_str(), blink)) {
|
|
err = write_int((led_path + "/led_r/brightness").c_str(), 0);
|
|
}
|
|
}
|
|
if (green) {
|
|
if (write_int((led_path + "/led_g/blink").c_str(), blink)) {
|
|
err = write_int((led_path + "/led_g/brightness").c_str(), 0);
|
|
}
|
|
}
|
|
if (blue) {
|
|
if (write_int((led_path + "/led_b/blink").c_str(), blink)) {
|
|
err = write_int((led_path + "/led_b/brightness").c_str(), 0);
|
|
}
|
|
}
|
|
} else {
|
|
err = write_int((led_path + "/led_r/brightness").c_str(), red);
|
|
err = write_int((led_path + "/led_g/brightness").c_str(), green);
|
|
err = write_int((led_path + "/led_b/brightness").c_str(), blue);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (err != 0) {
|
|
ALOGE("Failed to setLightState: %d", err);
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
|
|
ALOGV("Lights setting state for id=%d to color:%x", id, state.color);
|
|
LightType type;
|
|
int err = -1;
|
|
std::vector<HwLight>::iterator it = _lights.begin();
|
|
for (; it != _lights.end(); ++it) {
|
|
if (it->id == id) {
|
|
type = it->type;
|
|
err = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (err != 0) {
|
|
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
|
}
|
|
// Set lights.
|
|
err = setLightFromType(type, state);
|
|
if (err == 0) {
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
return ndk::ScopedAStatus::fromServiceSpecificError(err);
|
|
}
|
|
|
|
static int access_rgb() {
|
|
std::string led_path(getDriverPath(LightType::NOTIFICATIONS));
|
|
if (access((led_path + "/led_r/brightness").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
if (access((led_path + "/led_g/brightness").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
if (access((led_path + "/led_b/brightness").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
return 0;
|
|
}
|
|
|
|
static int access_rgb_blink() {
|
|
std::string led_path(getDriverPath(LightType::NOTIFICATIONS));
|
|
if (access((led_path + "/led_r/blink").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
if (access((led_path + "/led_g/blink").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
if (access((led_path + "/led_b/blink").c_str(), F_OK) < 0)
|
|
return -errno;
|
|
return 0;
|
|
}
|
|
|
|
static int access_backlight() {
|
|
std::string backlight_path(getDriverPath(LightType::BACKLIGHT));
|
|
ALOGV("backlight_path: %s", backlight_path.c_str());
|
|
if (access(backlight_path.c_str(), F_OK) < 0) {
|
|
ALOGE("error: %s", strerror(errno));
|
|
return -errno;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* lights) {
|
|
ALOGI("Lights reporting supported lights");
|
|
_lights.clear();
|
|
if (access_backlight() == 0) {
|
|
addLight(0, LightType::BACKLIGHT);
|
|
}
|
|
if (access_rgb() == 0) {
|
|
addLight(0, LightType::BATTERY);
|
|
}
|
|
if (access_rgb_blink() == 0) {
|
|
addLight(0, LightType::NOTIFICATIONS);
|
|
}
|
|
for (auto i = _lights.begin(); i != _lights.end(); i++) {
|
|
lights->push_back(*i);
|
|
}
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
|
|
void Lights::addLight(int const ordinal, LightType const type) {
|
|
ALOGI("addLight: %s", getDriverPath(type));
|
|
HwLight light{};
|
|
light.id = _lights.size();
|
|
light.ordinal = ordinal;
|
|
light.type = type;
|
|
_lights.emplace_back(light);
|
|
}
|
|
|
|
} // namespace light
|
|
} // namespace hardware
|
|
} // namespace android
|
|
} // namespace aidl
|