mirror of
https://github.com/Evolution-X-Devices/device_oplus_mt6893-common
synced 2026-01-30 13:44:50 +00:00
ossi: sensors: implement als compensation algorithm
* Adapt for QPR2 * Imported stock values from cupida F.12 dump
This commit is contained in:
1
ossi.mk
1
ossi.mk
@@ -452,6 +452,7 @@ PRODUCT_COPY_FILES += \
|
||||
# Sensors
|
||||
PRODUCT_PACKAGES += \
|
||||
android.hardware.sensors@2.0-service-multihal.mt6893 \
|
||||
als_correction_service.mt6893 \
|
||||
android.hardware.sensors@1.0.vendor \
|
||||
android.hardware.sensors@2.0.vendor \
|
||||
android.hardware.sensors@2.1.vendor \
|
||||
|
||||
447
sensors/AlsCorrection.cpp
Normal file
447
sensors/AlsCorrection.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "AlsCorrection"
|
||||
|
||||
#include "AlsCorrection.h"
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cutils/properties.h>
|
||||
#include <fstream>
|
||||
#include <log/log.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#define PROC_OPLUSALS "/proc/oplusAls/"
|
||||
#define OPLUS_DISPLAY "/sys/kernel/oplus_display/"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace V2_1 {
|
||||
namespace implementation {
|
||||
|
||||
static const std::string rgbw_max_lux_paths[4] = {
|
||||
PROC_OPLUSALS "red_max_lux",
|
||||
PROC_OPLUSALS "green_max_lux",
|
||||
PROC_OPLUSALS "blue_max_lux",
|
||||
PROC_OPLUSALS "white_max_lux",
|
||||
};
|
||||
|
||||
bool DEBUG = false;
|
||||
|
||||
struct als_config {
|
||||
bool hbr;
|
||||
float rgbw_max_lux[4];
|
||||
float rgbw_max_lux_div[4];
|
||||
float rgbw_lux_postmul[4];
|
||||
float rgbw_poly[4][4];
|
||||
float grayscale_weights[3];
|
||||
float sensor_inverse_gain[4];
|
||||
float agc_threshold;
|
||||
float calib_gain;
|
||||
float bias;
|
||||
float max_brightness;
|
||||
};
|
||||
|
||||
#define DEVICE_nashc
|
||||
|
||||
#if defined(DEVICE_guacamole) || defined(DEVICE_guacamoleg)
|
||||
static als_config conf = {
|
||||
.hbr = false,
|
||||
.rgbw_max_lux = { 199.0, 216.0, 79.0, 428.0 },
|
||||
.rgbw_max_lux_div = { 198.0, 216.0, 78.0, 409.0 },
|
||||
.rgbw_poly = {
|
||||
{ 1.7404983E-6, 0.0018088078, 0.003599656, -0.5450117 },
|
||||
{ 4.12301E-6, 0.0017906721, -0.034968063, -0.08428217 },
|
||||
{ 1.361745E-6, 8.127534E-4, -0.046870504, 0.52842677 },
|
||||
{ 2.7275946E-6, 0.0016300974, -0.021769103, -0.16610238 },
|
||||
},
|
||||
.grayscale_weights = { 0.4, 0.43, 0.17 },
|
||||
.sensor_inverse_gain = { 1.003141, 0.497163, 0.28517, 0.178429 },
|
||||
};
|
||||
#elif defined(DEVICE_guacamoleb)
|
||||
static als_config conf = {
|
||||
.hbr = false,
|
||||
.rgbw_max_lux = { 670.0, 680.0, 347.0, 1294.0 },
|
||||
.rgbw_max_lux_div = { 485.0, 647.0, 275.0, 1225.0 },
|
||||
.rgbw_poly = {
|
||||
{ 4.6876557E-6, 0.0039652763, 0.58725166, 0.0 },
|
||||
{ 3.999002E-6, 0.0076181223, 0.35004568, 0.0 },
|
||||
{ 1.8699997E-6, 0.0030195534, 0.19580707, 0.0 },
|
||||
{ 3.83552E-6, 0.0054658977, 0.40376243, 0.0 },
|
||||
},
|
||||
.grayscale_weights = { 0.35, 0.46, 0.19 },
|
||||
.sensor_inverse_gain = { 0.472747, 0.206944, 0.117592, 0.067704 },
|
||||
};
|
||||
#elif defined(DEVICE_hotdog) || defined(DEVICE_hotdogg)
|
||||
static als_config conf = {
|
||||
.hbr = true,
|
||||
.rgbw_max_lux = { 419.0, 822.0, 251.0, 1255.0 },
|
||||
.rgbw_max_lux_div = { 414.0, 817.0, 251.0, 1245.0 },
|
||||
.rgbw_poly = {
|
||||
{ 1.1255767E-5, 0.0023767108, 0.2771623, 0.0 },
|
||||
{ 2.8453156E-5, 0.004190259, 0.25827286, 0.0 },
|
||||
{ 6.5442537E-6, 0.0020840308, 0.020182181, 0.0 },
|
||||
{ 1.9053505E-5, 0.003323373, 0.22403096, 0.0 },
|
||||
},
|
||||
.grayscale_weights = { 0.33, 0.5, 0.17 },
|
||||
.sensor_inverse_gain = { 0.232, 0.175, 0.133, 0.097 },
|
||||
};
|
||||
#elif defined(DEVICE_hotdogb)
|
||||
static als_config conf = {
|
||||
.hbr = true,
|
||||
.rgbw_max_lux = { 1500.0, 2600.0, 1400.0, 4600.0 },
|
||||
.rgbw_max_lux_div = { 1437.0, 2427.0, 1369.0, 4606.0 },
|
||||
.rgbw_poly = {
|
||||
{ 4.787111E-5, 0.0073087, 0.6651031, 0.0 },
|
||||
{ 1.1037093E-4, 0.0059161806, 0.82983816, 0.0 },
|
||||
{ 4.6553232E-5, 0.008220689, 0.24763061, 0.0 },
|
||||
{ 7.379156E-5, 0.006951839, 0.6299237, 0.0 },
|
||||
},
|
||||
.grayscale_weights = { 0.33, 0.42, 0.25 },
|
||||
.sensor_inverse_gain = { 0.0615, 0.0466, 0.0361, 0.0288 },
|
||||
};
|
||||
#elif defined(DEVICE_nashc)
|
||||
static als_config conf = {
|
||||
.hbr = true,
|
||||
.rgbw_max_lux = { 840.0, 1558.0, 1337.0, 682.0 },
|
||||
.rgbw_max_lux_div = { 829.0, 1537.0, 1319.0, 673.0 },
|
||||
.rgbw_poly = {
|
||||
{ 2.4E-05, 0.00599, 0.21617, 0.0 },
|
||||
{ 4.8E-05, 0.0108, 0.24531, 0.0 },
|
||||
{ 3.7E-05, 0.01138, -0.05037, 0.0 },
|
||||
{ 7.4E-05, -0.01022, 0.53187, 0.0 },
|
||||
},
|
||||
.grayscale_weights = { 0.232, 0.415, 0.353 },
|
||||
.sensor_inverse_gain = { 0.0615, 0.0466, 0.0361, 0.0288 },
|
||||
};
|
||||
#else
|
||||
#error No ALS configuration for this device
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
float middle;
|
||||
float min, max;
|
||||
} hysteresis_ranges[] = {
|
||||
{ 0, 0, 4 },
|
||||
{ 7, 1, 12 },
|
||||
{ 15, 5, 30 },
|
||||
{ 30, 10, 50 },
|
||||
{ 360, 25, 700 },
|
||||
{ 1200, 300, 1600 },
|
||||
{ 2250, 1000, 2940 },
|
||||
{ 4600, 2000, 5900 },
|
||||
{ 10000, 4000, 80000 },
|
||||
{ HUGE_VALF, 8000, HUGE_VALF },
|
||||
};
|
||||
|
||||
static struct {
|
||||
nsecs_t last_update, last_forced_update;
|
||||
bool force_update;
|
||||
float hyst_min, hyst_max;
|
||||
float last_corrected_value;
|
||||
float last_agc_gain;
|
||||
} state = {
|
||||
.last_update = 0,
|
||||
.force_update = true,
|
||||
.hyst_min = -1.0, .hyst_max = -1.0,
|
||||
.last_agc_gain = 0.0,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T get(const std::string& path, const T& def) {
|
||||
std::ifstream file(path);
|
||||
T result;
|
||||
|
||||
file >> result;
|
||||
return file.fail() ? def : result;
|
||||
}
|
||||
|
||||
void AlsCorrection::init() {
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
// TODO: Constantly update and persist this
|
||||
float screen_on_time = get(PROC_OPLUSALS "screenontimebyhours", 0.0);
|
||||
float screen_aging_factor = 1.0 - screen_on_time / 87600.0;
|
||||
ALOGI("Screen on time: %.2fh (aging factor: %.2f%%)",
|
||||
screen_on_time, screen_aging_factor * 100.0);
|
||||
|
||||
float rgbw_acc = 0.0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float max_lux = get(rgbw_max_lux_paths[i], 0.0);
|
||||
if (max_lux != 0.0) {
|
||||
conf.rgbw_max_lux[i] = max_lux;
|
||||
}
|
||||
conf.rgbw_max_lux[i] *= screen_aging_factor;
|
||||
if (i < 3) {
|
||||
rgbw_acc += conf.rgbw_max_lux[i];
|
||||
conf.rgbw_lux_postmul[i] = conf.rgbw_max_lux[i] / conf.rgbw_max_lux_div[i];
|
||||
} else {
|
||||
rgbw_acc -= conf.rgbw_max_lux[i];
|
||||
conf.rgbw_lux_postmul[i] = rgbw_acc / conf.rgbw_max_lux_div[i];
|
||||
}
|
||||
}
|
||||
if(DEBUG)
|
||||
ALOGI("Display maximums: R=%.0f G=%.0f B=%.0f W=%.0f",
|
||||
conf.rgbw_max_lux[0], conf.rgbw_max_lux[1],
|
||||
conf.rgbw_max_lux[2], conf.rgbw_max_lux[3]);
|
||||
|
||||
float row_coe = get(PROC_OPLUSALS "row_coe", 0.0);
|
||||
if (row_coe != 0.0) {
|
||||
conf.sensor_inverse_gain[0] = row_coe / 1000.0;
|
||||
}
|
||||
conf.agc_threshold = 800.0 / conf.sensor_inverse_gain[0];
|
||||
|
||||
float cali_coe = get(PROC_OPLUSALS "cali_coe", 0.0);
|
||||
conf.calib_gain = cali_coe > 0.0 ? cali_coe / 1000.0 : 1.0;
|
||||
if(DEBUG) ALOGI("Calibrated sensor gain: %.2fx", 1.0 / (conf.calib_gain * conf.sensor_inverse_gain[0]));
|
||||
|
||||
float als_bias = get(PROC_OPLUSALS "als_bias", 0.0);
|
||||
conf.bias = als_bias <= 4.0 ? als_bias : 0.0;
|
||||
if(DEBUG) ALOGI("Sensor bias: %.2f", conf.bias);
|
||||
|
||||
float max_brightness = get(OPLUS_DISPLAY "oplus_max_brightness", 0.0);
|
||||
conf.max_brightness = max_brightness > 0.0 ? max_brightness : 1023.0;
|
||||
|
||||
for (auto& range : hysteresis_ranges) {
|
||||
range.min /= conf.calib_gain * conf.sensor_inverse_gain[0];
|
||||
range.max /= conf.calib_gain * conf.sensor_inverse_gain[0];
|
||||
}
|
||||
hysteresis_ranges[0].min = -1.0;
|
||||
}
|
||||
|
||||
void AlsCorrection::process(Event& event) {
|
||||
/*
|
||||
ALOGV("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
|
||||
event.u.data[0],
|
||||
event.u.data[1],
|
||||
event.u.data[2],
|
||||
event.u.data[3],
|
||||
event.u.data[4],
|
||||
event.u.data[5],
|
||||
event.u.data[6],
|
||||
event.u.data[7],
|
||||
event.u.data[8],
|
||||
event.u.data[9],
|
||||
event.u.data[10],
|
||||
event.u.data[11],
|
||||
event.u.data[12],
|
||||
event.u.data[13],
|
||||
event.u.data[14],
|
||||
event.u.data[15]
|
||||
);
|
||||
*/
|
||||
if(DEBUG) ALOGV("Raw sensor reading: %.0f", event.u.scalar);
|
||||
|
||||
if (conf.rgbw_max_lux[0] == 0.0 && conf.rgbw_max_lux[1] == 0.0 &&
|
||||
conf.rgbw_max_lux[2] == 0.0 && conf.rgbw_max_lux[3] == 0.0) {
|
||||
ALOGE("Trying to init AlsCorrection again");
|
||||
AlsCorrection::init();
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.u.scalar > conf.bias) {
|
||||
event.u.scalar -= conf.bias;
|
||||
}
|
||||
|
||||
if (conf.hbr && event.u.data[8] != 2.0) {
|
||||
state.force_update = true;
|
||||
event.u.scalar *= conf.calib_gain * conf.sensor_inverse_gain[0];
|
||||
if(DEBUG) ALOGV("Skipping correction, calibrated ambient light: %.0f lux", event.u.scalar);
|
||||
return;
|
||||
}
|
||||
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
float brightness = get(OPLUS_DISPLAY "oplus_brightness", 0.0);
|
||||
|
||||
if (state.last_update == 0) {
|
||||
state.last_update = now;
|
||||
state.last_forced_update = now;
|
||||
} else {
|
||||
if (brightness > 0.0 && (now - state.last_forced_update) > s2ns(3)) {
|
||||
if(DEBUG) ALOGV("Forcing screenshot");
|
||||
state.last_forced_update = now;
|
||||
state.force_update = true;
|
||||
}
|
||||
if ((now - state.last_update) < ms2ns(100)) {
|
||||
if(DEBUG) ALOGV("Events coming too fast, dropping");
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
state.last_update = now;
|
||||
}
|
||||
|
||||
float sensor_raw_calibrated = event.u.scalar * conf.calib_gain * state.last_agc_gain;
|
||||
if (state.force_update
|
||||
|| ((event.u.scalar < state.hyst_min || event.u.scalar > state.hyst_max)
|
||||
&& (event.u.data[6] > 2.0
|
||||
|| sensor_raw_calibrated < 10.0 || sensor_raw_calibrated > (5.0 / .07)))) {
|
||||
android::base::unique_fd fd(socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
|
||||
if (fd.get() < 0) {
|
||||
if(DEBUG) ALOGV("Failed to open als correction socket: %s", strerror(errno));
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sockaddr_un addr{ AF_UNIX, "/dev/socket/als_correction" };
|
||||
if (connect(fd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
|
||||
if(DEBUG) ALOGV("Failed to connect to als correction socket: %s", strerror(errno));
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const char *cmd = "take_screenshot";
|
||||
if (send(fd.get(), cmd, strlen(cmd) + 1, 0) == -1) {
|
||||
if(DEBUG) ALOGV("Failed to send command to als correction socket: %s", strerror(errno));
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pollfd fds{ fd.get(), POLLIN, 0 };
|
||||
if (poll(&fds, 1, -1) != 1) {
|
||||
if(DEBUG) ALOGV("Invalid poll als correction socket fd");
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
struct screenshot_t {
|
||||
uint32_t r, g, b;
|
||||
nsecs_t timestamp;
|
||||
} screenshot;
|
||||
|
||||
if (read(fd.get(), &screenshot, sizeof(screenshot_t)) != sizeof(screenshot_t)) {
|
||||
if(DEBUG) ALOGV("Invalid reply from als correction socket");
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((now - screenshot.timestamp) > ms2ns(1000)) {
|
||||
if(DEBUG) ALOGV("Screenshot too old, dropping event");
|
||||
// TODO figure out a better way to drop events
|
||||
event.sensorHandle = 0;
|
||||
return;
|
||||
}
|
||||
if(DEBUG) ALOGV("Screen color above sensor: %d %d %d", screenshot.r, screenshot.g, screenshot.b);
|
||||
|
||||
float rgbw[4] = {
|
||||
static_cast<float>(screenshot.r), static_cast<float>(screenshot.g), static_cast<float>(screenshot.b),
|
||||
screenshot.r * conf.grayscale_weights[0]
|
||||
+ screenshot.g * conf.grayscale_weights[1]
|
||||
+ screenshot.b * conf.grayscale_weights[2]
|
||||
};
|
||||
float cumulative_correction = 0.0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float corr = 0.0;
|
||||
for (float coef : conf.rgbw_poly[i]) {
|
||||
corr *= rgbw[i];
|
||||
corr += coef;
|
||||
}
|
||||
corr *= conf.rgbw_lux_postmul[i];
|
||||
if (i < 3) {
|
||||
cumulative_correction += std::max(corr, 0.0f);
|
||||
} else {
|
||||
cumulative_correction -= corr;
|
||||
}
|
||||
}
|
||||
cumulative_correction *= brightness / conf.max_brightness;
|
||||
float brightness_fullwhite = conf.rgbw_max_lux[3] * brightness / conf.max_brightness;
|
||||
float brightness_grayscale_gamma = std::pow(rgbw[3] / 255.0, 2.2) * brightness_fullwhite;
|
||||
cumulative_correction = std::min(cumulative_correction, brightness_fullwhite);
|
||||
cumulative_correction = std::max(cumulative_correction, brightness_grayscale_gamma);
|
||||
if(DEBUG) ALOGV("Estimated screen brightness: %.0f", cumulative_correction);
|
||||
|
||||
float sensor_raw_corrected = std::max(event.u.scalar - cumulative_correction, 0.0f);
|
||||
|
||||
float agc_gain = conf.sensor_inverse_gain[0];
|
||||
if (sensor_raw_corrected > conf.agc_threshold) {
|
||||
if (!conf.hbr) {
|
||||
float gain_estimate = sensor_raw_corrected / event.u.data[8];
|
||||
if (gain_estimate > 85.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[0];
|
||||
} else if (gain_estimate >= 39.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[1];
|
||||
} else if (gain_estimate >= 29.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[2];
|
||||
} else {
|
||||
agc_gain = conf.sensor_inverse_gain[3];
|
||||
}
|
||||
} else {
|
||||
float gain_estimate = event.u.data[8] * 1000.0 / event.u.scalar;
|
||||
if (gain_estimate > 1050.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[3];
|
||||
} else if (gain_estimate > 800.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[2];
|
||||
} else if (gain_estimate > 450.0) {
|
||||
agc_gain = conf.sensor_inverse_gain[1];
|
||||
} else {
|
||||
agc_gain = conf.sensor_inverse_gain[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(DEBUG) ALOGV("AGC gain: %f", agc_gain);
|
||||
|
||||
if (cumulative_correction <= event.u.scalar * 1.35
|
||||
|| event.u.scalar * conf.calib_gain * agc_gain < 10000.0
|
||||
|| state.force_update) {
|
||||
float sensor_corrected = sensor_raw_corrected * conf.calib_gain * agc_gain;
|
||||
state.last_agc_gain = agc_gain;
|
||||
for (auto& range : hysteresis_ranges) {
|
||||
if (sensor_corrected <= range.middle) {
|
||||
state.hyst_min = range.min;
|
||||
state.hyst_max = range.max + brightness_fullwhite;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sensor_corrected = std::max(sensor_corrected - 14.0, 0.0);
|
||||
event.u.scalar = sensor_corrected;
|
||||
state.last_corrected_value = sensor_corrected;
|
||||
if(DEBUG) ALOGV("Fully corrected sensor value: %.0f lux", sensor_corrected);
|
||||
} else {
|
||||
event.u.scalar = state.last_corrected_value;
|
||||
if(DEBUG) ALOGV("Reusing cached value: %.0f lux", event.u.scalar);
|
||||
}
|
||||
|
||||
state.force_update = false;
|
||||
} else {
|
||||
event.u.scalar = state.last_corrected_value;
|
||||
if(DEBUG) ALOGV("Reusing cached value: %.0f lux", event.u.scalar);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V2_1
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
@@ -21,6 +21,7 @@ cc_binary {
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
srcs: [
|
||||
"AlsCorrection.cpp",
|
||||
"HalProxy.cpp",
|
||||
"HalProxyCallback.cpp",
|
||||
"service.cpp",
|
||||
@@ -46,4 +47,23 @@ cc_binary {
|
||||
static_libs: [
|
||||
"android.hardware.sensors@1.0-convert",
|
||||
],
|
||||
local_include_dirs: [ "include",],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "als_correction_service.mt6893",
|
||||
stem: "als_correction_service",
|
||||
init_rc: ["als_correction_service.rc"],
|
||||
system_ext_specific: true,
|
||||
srcs: ["als_correction_service.cpp", ],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder",
|
||||
"libgui",
|
||||
"libui",
|
||||
"libsysutils",
|
||||
"libutils",
|
||||
"liblog",
|
||||
], cflags: [ "-DNO_INPUT", ],
|
||||
local_include_dirs: [ "include",],
|
||||
}
|
||||
|
||||
148
sensors/als_correction_service.cpp
Normal file
148
sensors/als_correction_service.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
* 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 <android-base/properties.h>
|
||||
#include <binder/ProcessState.h>
|
||||
#include <gui/LayerState.h>
|
||||
#include <gui/SurfaceComposerClient.h>
|
||||
#include <gui/SyncScreenCaptureListener.h>
|
||||
#include <ui/DisplayState.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sysutils/FrameworkCommand.h>
|
||||
#include <sysutils/FrameworkListener.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
using android::base::SetProperty;
|
||||
using android::ui::Rotation;
|
||||
using android::ui::DisplayState;
|
||||
using android::GraphicBuffer;
|
||||
using android::Rect;
|
||||
using android::ScreenshotClient;
|
||||
using android::sp;
|
||||
using android::SurfaceComposerClient;
|
||||
using namespace android;
|
||||
|
||||
constexpr int ALS_POS_X = 610;
|
||||
constexpr int ALS_POS_Y = 40;
|
||||
constexpr int ALS_RADIUS = 64;
|
||||
|
||||
static sp<IBinder> getInternalDisplayToken() {
|
||||
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
|
||||
sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(displayIds[0]);
|
||||
return token;
|
||||
}
|
||||
|
||||
static Rect screenshot_rect_0(ALS_POS_X - ALS_RADIUS, ALS_POS_Y - ALS_RADIUS, ALS_POS_X + ALS_RADIUS, ALS_POS_Y + ALS_RADIUS);
|
||||
static Rect screenshot_rect_land_90(ALS_POS_Y - ALS_RADIUS, 1080 - ALS_POS_X - ALS_RADIUS, ALS_POS_Y + ALS_RADIUS, 1080 - ALS_POS_X + ALS_RADIUS);
|
||||
static Rect screenshot_rect_180(1080-ALS_POS_X - ALS_RADIUS, 2400-ALS_POS_Y - ALS_RADIUS, 1080-ALS_POS_X + ALS_RADIUS, 2400-ALS_POS_Y + ALS_RADIUS);
|
||||
static Rect screenshot_rect_land_270(2400 - (ALS_POS_Y + ALS_RADIUS),ALS_POS_X - ALS_RADIUS, 2400 - (ALS_POS_Y - ALS_RADIUS), ALS_POS_X + ALS_RADIUS);
|
||||
|
||||
class TakeScreenshotCommand : public FrameworkCommand {
|
||||
public:
|
||||
TakeScreenshotCommand() : FrameworkCommand("take_screenshot") {}
|
||||
~TakeScreenshotCommand() override = default;
|
||||
|
||||
int runCommand(SocketClient* cli, int /*argc*/, char **/*argv*/) {
|
||||
auto screenshot = takeScreenshot();
|
||||
cli->sendData(&screenshot, sizeof(screenshot_t));
|
||||
return 0;
|
||||
}
|
||||
private:
|
||||
struct screenshot_t {
|
||||
uint32_t r, g, b;
|
||||
nsecs_t timestamp;
|
||||
};
|
||||
|
||||
screenshot_t takeScreenshot() {
|
||||
sp<IBinder> display = getInternalDisplayToken();
|
||||
|
||||
android::ui::DisplayState state;
|
||||
SurfaceComposerClient::getDisplayState(display, &state);
|
||||
Rect screenshot_rect;
|
||||
switch (state.orientation) {
|
||||
case Rotation::Rotation90: screenshot_rect = screenshot_rect_land_90;
|
||||
break;
|
||||
case Rotation::Rotation180: screenshot_rect = screenshot_rect_180;
|
||||
break;
|
||||
case Rotation::Rotation270: screenshot_rect = screenshot_rect_land_270;
|
||||
break;
|
||||
default: screenshot_rect = screenshot_rect_0;
|
||||
break;
|
||||
}
|
||||
|
||||
sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
|
||||
gui::ScreenCaptureResults captureResults;
|
||||
|
||||
static sp<GraphicBuffer> outBuffer = new GraphicBuffer(
|
||||
screenshot_rect.getWidth(), screenshot_rect.getHeight(),
|
||||
android::PIXEL_FORMAT_RGB_888,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN);
|
||||
|
||||
DisplayCaptureArgs captureArgs;
|
||||
captureArgs.displayToken = display;
|
||||
captureArgs.pixelFormat = android::ui::PixelFormat::RGBA_8888;
|
||||
|
||||
captureArgs.sourceCrop = screenshot_rect;
|
||||
captureArgs.width = screenshot_rect.getWidth();
|
||||
captureArgs.height = screenshot_rect.getHeight();
|
||||
//captureArgs.useIdentityTransform = false;
|
||||
status_t ret = ScreenshotClient::captureDisplay(captureArgs, captureListener);
|
||||
|
||||
uint8_t *out;
|
||||
auto resultWidth = outBuffer->getWidth();
|
||||
auto resultHeight = outBuffer->getHeight();
|
||||
auto stride = outBuffer->getStride();
|
||||
|
||||
outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void **>(&out));
|
||||
// we can sum this directly on linear light
|
||||
uint32_t rsum = 0, gsum = 0, bsum = 0;
|
||||
for (int y = 0; y < resultHeight; y++) {
|
||||
for (int x = 0; x < resultWidth; x++) {
|
||||
rsum += out[y * (stride * 4) + x * 4];
|
||||
gsum += out[y * (stride * 4) + x * 4 + 1];
|
||||
bsum += out[y * (stride * 4) + x * 4 + 2];
|
||||
}
|
||||
}
|
||||
uint32_t max = resultWidth * resultHeight;
|
||||
outBuffer->unlock();
|
||||
|
||||
return { rsum / max, gsum / max, bsum / max, systemTime(SYSTEM_TIME_BOOTTIME) };
|
||||
}
|
||||
};
|
||||
|
||||
class AlsCorrectionListener : public FrameworkListener {
|
||||
public:
|
||||
AlsCorrectionListener() : FrameworkListener("als_correction") {
|
||||
registerCmd(new TakeScreenshotCommand);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
ProcessState::self()->setThreadPoolMaxThreadCount(0);
|
||||
ProcessState::self()->startThreadPool();
|
||||
|
||||
auto listener = new AlsCorrectionListener();
|
||||
listener->startListener();
|
||||
|
||||
while (true) {
|
||||
pause();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
sensors/als_correction_service.rc
Normal file
6
sensors/als_correction_service.rc
Normal file
@@ -0,0 +1,6 @@
|
||||
service als_correction_service /system_ext/bin/als_correction_service
|
||||
class hal
|
||||
user system
|
||||
group system
|
||||
socket als_correction stream 600 system system
|
||||
writepid /dev/cpuset/system-background/tasks
|
||||
39
sensors/include/AlsCorrection.h
Normal file
39
sensors/include/AlsCorrection.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/hardware/sensors/2.1/types.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace V2_1 {
|
||||
namespace implementation {
|
||||
|
||||
static constexpr int SENSOR_TYPE_ANDROID_WISE_LIGHT = 65627;
|
||||
|
||||
class AlsCorrection {
|
||||
public:
|
||||
static void init();
|
||||
static void process(Event& event);
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V2_1
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
46
sensors/include/AsyncScreenCaptureListener.h
Normal file
46
sensors/include/AsyncScreenCaptureListener.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Project Kaleidoscope
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/gui/BnScreenCaptureListener.h>
|
||||
#include <gui/SurfaceComposerClient.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
using gui::ScreenCaptureResults;
|
||||
|
||||
typedef std::function<void(const ScreenCaptureResults& captureResults)> CaptureCallback;
|
||||
|
||||
struct AsyncScreenCaptureListener : gui::BnScreenCaptureListener {
|
||||
public:
|
||||
AsyncScreenCaptureListener(CaptureCallback callback, int timeout)
|
||||
: callback(callback), timeout(timeout) {}
|
||||
|
||||
binder::Status onScreenCaptureCompleted(const ScreenCaptureResults& captureResults) override {
|
||||
if (captureResults.fenceResult.ok()) {
|
||||
if(captureResults.fenceResult.value()->wait(timeout) == OK) {
|
||||
callback(captureResults);
|
||||
}
|
||||
return binder::Status::ok();
|
||||
}
|
||||
|
||||
private:
|
||||
CaptureCallback callback;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user