From f835d254f3e72530633c0fd047ff122507f4912e Mon Sep 17 00:00:00 2001 From: Art_Chen Date: Fri, 5 Apr 2024 21:53:00 +0530 Subject: [PATCH] ossi: sensors: implement als compensation algorithm * Adapt for QPR2 * Imported stock values from cupida F.12 dump --- ossi.mk | 1 + sensors/AlsCorrection.cpp | 447 +++++++++++++++++++ sensors/Android.bp | 20 + sensors/als_correction_service.cpp | 148 ++++++ sensors/als_correction_service.rc | 6 + sensors/include/AlsCorrection.h | 39 ++ sensors/include/AsyncScreenCaptureListener.h | 46 ++ 7 files changed, 707 insertions(+) create mode 100644 sensors/AlsCorrection.cpp create mode 100644 sensors/als_correction_service.cpp create mode 100644 sensors/als_correction_service.rc create mode 100644 sensors/include/AlsCorrection.h create mode 100644 sensors/include/AsyncScreenCaptureListener.h diff --git a/ossi.mk b/ossi.mk index f58c467..60fe38f 100644 --- a/ossi.mk +++ b/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 \ diff --git a/sensors/AlsCorrection.cpp b/sensors/AlsCorrection.cpp new file mode 100644 index 0000000..2e40d75 --- /dev/null +++ b/sensors/AlsCorrection.cpp @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +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(&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(screenshot.r), static_cast(screenshot.g), static_cast(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 diff --git a/sensors/Android.bp b/sensors/Android.bp index cd33a8d..87a53f6 100644 --- a/sensors/Android.bp +++ b/sensors/Android.bp @@ -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",], } diff --git a/sensors/als_correction_service.cpp b/sensors/als_correction_service.cpp new file mode 100644 index 0000000..bcea51f --- /dev/null +++ b/sensors/als_correction_service.cpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 getInternalDisplayToken() { + const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); + sp 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 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 captureListener = new SyncScreenCaptureListener(); + gui::ScreenCaptureResults captureResults; + + static sp 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(&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; +} diff --git a/sensors/als_correction_service.rc b/sensors/als_correction_service.rc new file mode 100644 index 0000000..52d296c --- /dev/null +++ b/sensors/als_correction_service.rc @@ -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 diff --git a/sensors/include/AlsCorrection.h b/sensors/include/AlsCorrection.h new file mode 100644 index 0000000..ca67c37 --- /dev/null +++ b/sensors/include/AlsCorrection.h @@ -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 + +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 diff --git a/sensors/include/AsyncScreenCaptureListener.h b/sensors/include/AsyncScreenCaptureListener.h new file mode 100644 index 0000000..e8a848c --- /dev/null +++ b/sensors/include/AsyncScreenCaptureListener.h @@ -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 +#include + +namespace android { + +using gui::ScreenCaptureResults; + +typedef std::function 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