diff options
author | Steve Kondik <steve@cyngn.com> | 2016-08-07 23:21:29 -0700 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2016-08-14 14:10:53 -0700 |
commit | 75956207503ca4f5023c1d2b587594c517e7e28f (patch) | |
tree | 018914747e0ad88ebe3cba5e80c052f7709d4a53 /charger | |
parent | 48f8df8ddb2eb3b32dbc44dcb50fcfc01bfbc8bd (diff) | |
download | vendor_replicant-75956207503ca4f5023c1d2b587594c517e7e28f.zip vendor_replicant-75956207503ca4f5023c1d2b587594c517e7e28f.tar.gz vendor_replicant-75956207503ca4f5023c1d2b587594c517e7e28f.tar.bz2 |
cm: Add custom off-mode charging screen
* Moving this to open-source from CyanogenOS :)
* Thanks to Chao Chen, Ethan Chen, Pat Erley, Scott Mertz,
and Keith Mok for various contributions to this.
Change-Id: If79f9c279668d14ee0cde62889bb09e7185ef08c
Diffstat (limited to 'charger')
19 files changed, 423 insertions, 0 deletions
diff --git a/charger/Android.mk b/charger/Android.mk new file mode 100644 index 0000000..0f5e55f --- /dev/null +++ b/charger/Android.mk @@ -0,0 +1,47 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := healthd_board_cm.cpp +LOCAL_MODULE := libhealthd.cm +LOCAL_CFLAGS := -Werror +LOCAL_C_INCLUDES := \ + system/core/healthd \ + bootable/recovery +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := font_log.png +LOCAL_SRC_FILES := fonts/$(PRODUCT_AAPT_PREF_CONFIG)/font_log.png +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/res/images +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) + +define _add-charger-image +include $$(CLEAR_VARS) +LOCAL_MODULE := vendor_cm_charger_$(notdir $(1)) +LOCAL_MODULE_STEM := $(notdir $(1)) +_img_modules += $$(LOCAL_MODULE) +LOCAL_SRC_FILES := $1 +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger +include $$(BUILD_PREBUILT) +endef + +_img_modules := +_images := +$(foreach _img, $(call find-subdir-subdir-files, "images/$(PRODUCT_AAPT_PREF_CONFIG)", "*.png"), \ + $(eval $(call _add-charger-image,$(_img)))) + +include $(CLEAR_VARS) +LOCAL_MODULE := cm_charger_res_images +LOCAL_MODULE_TAGS := optional +LOCAL_REQUIRED_MODULES := $(_img_modules) +LOCAL_OVERRIDES_PACKAGES := charger_res_images +include $(BUILD_PHONY_PACKAGE) + +_add-charger-image := +_img_modules := diff --git a/charger/fonts/560dpi b/charger/fonts/560dpi new file mode 120000 index 0000000..17ef829 --- /dev/null +++ b/charger/fonts/560dpi @@ -0,0 +1 @@ +xxhdpi
\ No newline at end of file diff --git a/charger/fonts/hdpi/font_log.png b/charger/fonts/hdpi/font_log.png Binary files differnew file mode 100644 index 0000000..ddf9bc7 --- /dev/null +++ b/charger/fonts/hdpi/font_log.png diff --git a/charger/fonts/mdpi/font_log.png b/charger/fonts/mdpi/font_log.png Binary files differnew file mode 100644 index 0000000..d727fa1 --- /dev/null +++ b/charger/fonts/mdpi/font_log.png diff --git a/charger/fonts/xhdpi/font_log.png b/charger/fonts/xhdpi/font_log.png Binary files differnew file mode 100644 index 0000000..9c16b77 --- /dev/null +++ b/charger/fonts/xhdpi/font_log.png diff --git a/charger/fonts/xxhdpi/font_log.png b/charger/fonts/xxhdpi/font_log.png Binary files differnew file mode 100644 index 0000000..5d122b7 --- /dev/null +++ b/charger/fonts/xxhdpi/font_log.png diff --git a/charger/fonts/xxxhdpi/font_log.png b/charger/fonts/xxxhdpi/font_log.png Binary files differnew file mode 100644 index 0000000..60dacec --- /dev/null +++ b/charger/fonts/xxxhdpi/font_log.png diff --git a/charger/healthd_board_cm.cpp b/charger/healthd_board_cm.cpp new file mode 100644 index 0000000..c5aa3e6 --- /dev/null +++ b/charger/healthd_board_cm.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2016 The CyanogenMod 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 <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include <cutils/android_reboot.h> +#include <cutils/klog.h> +#include <cutils/misc.h> +#include <cutils/uevent.h> +#include <cutils/properties.h> + +#include <pthread.h> +#include <linux/android_alarm.h> +#include <sys/timerfd.h> +#include <linux/rtc.h> + +#include "healthd.h" +#include "minui/minui.h" + +#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) +#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0) +#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0) +#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0) + +struct frame { + int min_capacity; + GRSurface *surface; +}; + +struct animation { + struct frame *frames; + int cur_frame; + int num_frames; +}; + +static struct animation anim = { + .frames = NULL, + .cur_frame = 0, + .num_frames = 0, +}; + +static bool font_inited; + +static int draw_surface_centered(GRSurface* surface) +{ + int w, h, x, y; + + w = gr_get_width(surface); + h = gr_get_height(surface); + x = (gr_fb_width() - w) / 2 ; + y = (gr_fb_height() - h) / 2 ; + + gr_blit(surface, 0, 0, w, h, x, y); + return y + h; +} + +#define STR_LEN 64 +static void draw_capacity(int capacity) +{ + struct frame *f = &anim.frames[0]; + int w = gr_get_width(f->surface); + int h = gr_get_height(f->surface); + int x = (gr_fb_width() - w) / 2 ; + int y = (gr_fb_height() + h) / 2; + + char cap_str[STR_LEN]; + snprintf(cap_str, (STR_LEN - 1), "%d%%", capacity); + gr_color(255, 255, 255, 255); + gr_text(x, y * 1.05, cap_str, 0); +} + +#ifdef QCOM_HARDWARE +enum alarm_time_type { + ALARM_TIME, + RTC_TIME, +}; + +/* + * shouldn't be changed after + * reading from alarm register + */ +static time_t alm_secs; + +static int alarm_get_time(enum alarm_time_type time_type, + time_t *secs) +{ + struct tm tm; + unsigned int cmd; + int rc, fd = -1; + + if (!secs) + return -1; + + fd = open("/dev/rtc0", O_RDONLY); + if (fd < 0) { + LOGE("Can't open rtc devfs node\n"); + return -1; + } + + switch (time_type) { + case ALARM_TIME: + cmd = RTC_ALM_READ; + break; + case RTC_TIME: + cmd = RTC_RD_TIME; + break; + default: + LOGE("Invalid time type\n"); + goto err; + } + + rc = ioctl(fd, cmd, &tm); + if (rc < 0) { + LOGE("Unable to get time\n"); + goto err; + } + + *secs = mktime(&tm) + tm.tm_gmtoff; + if (*secs < 0) { + LOGE("Invalid seconds = %ld\n", *secs); + goto err; + } + + close(fd); + return 0; + +err: + close(fd); + return -1; +} + +#define ERR_SECS 2 +static int alarm_is_alm_expired() +{ + int rc; + time_t rtc_secs; + + rc = alarm_get_time(RTC_TIME, &rtc_secs); + if (rc < 0) + return 0; + + return (alm_secs >= rtc_secs - ERR_SECS && + alm_secs <= rtc_secs + ERR_SECS) ? 1 : 0; +} + +static int timerfd_set_reboot_time_and_wait(time_t secs) +{ + int fd; + int ret = -1; + fd = timerfd_create(CLOCK_REALTIME_ALARM, 0); + if (fd < 0) { + LOGE("Can't open timerfd alarm node\n"); + goto err_return; + } + + struct itimerspec spec; + memset(&spec, 0, sizeof(spec)); + spec.it_value.tv_sec = secs; + + if (timerfd_settime(fd, 0 /* relative */, &spec, NULL)) { + LOGE("Can't set timerfd alarm\n"); + goto err_close; + } + + uint64_t unused; + if (read(fd, &unused, sizeof(unused)) < 0) { + LOGE("Wait alarm error\n"); + goto err_close; + } + + ret = 0; +err_close: + close(fd); +err_return: + return ret; +} + +static int alarm_set_reboot_time_and_wait(time_t secs) +{ + int rc, fd; + struct timespec ts; + + fd = open("/dev/alarm", O_RDWR); + if (fd < 0) { + LOGE("Can't open alarm devfs node, trying timerfd\n"); + return timerfd_set_reboot_time_and_wait(secs); + } + + /* get the elapsed realtime from boot time to now */ + rc = ioctl(fd, ANDROID_ALARM_GET_TIME( + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); + if (rc < 0) { + LOGE("Unable to get elapsed realtime\n"); + goto err; + } + + /* calculate the elapsed time from boot time to reboot time */ + ts.tv_sec += secs; + ts.tv_nsec = 0; + + rc = ioctl(fd, ANDROID_ALARM_SET( + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); + if (rc < 0) { + LOGE("Unable to set reboot time to %ld\n", secs); + goto err; + } + + do { + rc = ioctl(fd, ANDROID_ALARM_WAIT); + } while ((rc < 0 && errno == EINTR) || !alarm_is_alm_expired()); + + if (rc <= 0) { + LOGE("Unable to wait on alarm\n"); + goto err; + } + + close(fd); + return 0; + +err: + if (fd >= 0) + close(fd); + return -1; +} + +static void *alarm_thread(void *) +{ + time_t rtc_secs, rb_secs; + int rc; + + /* + * to support power off alarm, the time + * stored in alarm register at latest + * shutdown time should be some time + * earlier than the actual alarm time + * set by user + */ + rc = alarm_get_time(ALARM_TIME, &alm_secs); + if (rc < 0 || !alm_secs) + goto err; + + rc = alarm_get_time(RTC_TIME, &rtc_secs); + if (rc < 0) + goto err; + + /* + * calculate the reboot time after which + * the phone will reboot + */ + rb_secs = alm_secs - rtc_secs; + if (rb_secs <= 0) + goto err; + + rc = alarm_set_reboot_time_and_wait(rb_secs); + if (rc < 0) + goto err; + + LOGI("Exit from power off charging, reboot the phone!\n"); + android_reboot(ANDROID_RB_RESTART, 0, 0); + +err: + LOGE("Exit from alarm thread\n"); + return NULL; +} +#endif + +void healthd_board_init(struct healthd_config*) +{ + pthread_t tid; + char value[PROP_VALUE_MAX]; + int rc = 0, scale_count = 0, i; + GRSurface **scale_frames; + + rc = res_create_multi_display_surface("charger/cm_battery_scale", + &scale_count, &scale_frames); + if (rc < 0) { + LOGE("%s: Unable to load battery scale image", __func__); + return; + } + + anim.frames = new frame[scale_count]; + anim.num_frames = scale_count; + for (i = 0; i < anim.num_frames; i++) { + anim.frames[i].surface = scale_frames[i]; + anim.frames[i].min_capacity = 100/(scale_count-1) * i; + } + +#ifdef QCOM_HARDWARE + property_get("ro.bootmode", value, ""); + if (!strcmp("charger", value)) { + rc = pthread_create(&tid, NULL, alarm_thread, NULL); + if (rc < 0) + LOGE("Create alarm thread failed\n"); + } +#endif +} + +int healthd_board_battery_update(struct android::BatteryProperties*) +{ + // return 0 to log periodic polled battery status to kernel log + return 1; +} + +void healthd_board_mode_charger_draw_battery( + struct android::BatteryProperties *batt_prop) +{ + int start_frame = 0; + int capacity = -1; + + if (!font_inited) { + gr_set_font("log"); + font_inited = true; + } + + if (batt_prop && batt_prop->batteryLevel >= 0) { + capacity = batt_prop->batteryLevel; + } + + if (anim.num_frames == 0 || capacity < 0) { + LOGE("%s: Unable to draw battery", __func__); + return; + } + + // Find starting frame to display based on current capacity + for (start_frame = 1; start_frame < anim.num_frames; start_frame++) { + if (capacity < anim.frames[start_frame].min_capacity) + break; + } + // Always start from the level just below the current capacity + start_frame--; + + if (anim.cur_frame < start_frame) + anim.cur_frame = start_frame; + + draw_surface_centered(anim.frames[anim.cur_frame].surface); + draw_capacity(capacity); + // Move to next frame, with max possible frame at max_idx + anim.cur_frame = ((anim.cur_frame + 1) % anim.num_frames); +} + +void healthd_board_mode_charger_battery_update( + struct android::BatteryProperties*) +{ +} + +void healthd_board_mode_charger_set_backlight(bool) +{ +} + +void healthd_board_mode_charger_init(void) +{ +} diff --git a/charger/images/560dpi b/charger/images/560dpi new file mode 120000 index 0000000..af2d1fe --- /dev/null +++ b/charger/images/560dpi @@ -0,0 +1 @@ +xxxhdpi
\ No newline at end of file diff --git a/charger/images/hdpi/battery_fail.png b/charger/images/hdpi/battery_fail.png Binary files differnew file mode 100644 index 0000000..aded88a --- /dev/null +++ b/charger/images/hdpi/battery_fail.png diff --git a/charger/images/hdpi/cm_battery_scale.png b/charger/images/hdpi/cm_battery_scale.png Binary files differnew file mode 100644 index 0000000..0052c0a --- /dev/null +++ b/charger/images/hdpi/cm_battery_scale.png diff --git a/charger/images/mdpi/battery_fail.png b/charger/images/mdpi/battery_fail.png Binary files differnew file mode 100644 index 0000000..aded88a --- /dev/null +++ b/charger/images/mdpi/battery_fail.png diff --git a/charger/images/mdpi/cm_battery_scale.png b/charger/images/mdpi/cm_battery_scale.png Binary files differnew file mode 100644 index 0000000..eb16a29 --- /dev/null +++ b/charger/images/mdpi/cm_battery_scale.png diff --git a/charger/images/xhdpi/battery_fail.png b/charger/images/xhdpi/battery_fail.png Binary files differnew file mode 100644 index 0000000..aded88a --- /dev/null +++ b/charger/images/xhdpi/battery_fail.png diff --git a/charger/images/xhdpi/cm_battery_scale.png b/charger/images/xhdpi/cm_battery_scale.png Binary files differnew file mode 100644 index 0000000..078b2a6 --- /dev/null +++ b/charger/images/xhdpi/cm_battery_scale.png diff --git a/charger/images/xxhdpi/battery_fail.png b/charger/images/xxhdpi/battery_fail.png Binary files differnew file mode 100644 index 0000000..aded88a --- /dev/null +++ b/charger/images/xxhdpi/battery_fail.png diff --git a/charger/images/xxhdpi/cm_battery_scale.png b/charger/images/xxhdpi/cm_battery_scale.png Binary files differnew file mode 100644 index 0000000..2e6553e --- /dev/null +++ b/charger/images/xxhdpi/cm_battery_scale.png diff --git a/charger/images/xxxhdpi/battery_fail.png b/charger/images/xxxhdpi/battery_fail.png Binary files differnew file mode 100644 index 0000000..aded88a --- /dev/null +++ b/charger/images/xxxhdpi/battery_fail.png diff --git a/charger/images/xxxhdpi/cm_battery_scale.png b/charger/images/xxxhdpi/cm_battery_scale.png Binary files differnew file mode 100644 index 0000000..90c627d --- /dev/null +++ b/charger/images/xxxhdpi/cm_battery_scale.png |