关机充电是用minui开发的,代码路径如下vendor/sprd/proprietories-source/charge
代码中的图片资源路径vendor/sprd/proprietories-source/charge/images
手机上的图片资源路径vendor/etc/res/images
项目的屏幕分辨率是540X1200,根据 vendor/sprd/proprietories-source/charge/ui.c
代码中的判断,是 SIZE_720X1280
static int res_pixel_identify(void) {
int x = gr_fb_width();
int y = gr_fb_height();
int size = 0;
if((x<= 360) && (y <= 640)){
size = SIZE_360X640;
}else if((x<=480) && (y<=800)){
size = SIZE_480X800;
}else if((x<=480) && (y<=854)) {
size = SIZE_480X800;
LOGD("480 * 854 Use res of 480 * 800\n");
}else if((x<=720) && (y<=1280)){
size = SIZE_720X1280;
}else if((x<=1080) && (y<=1920)){
size = SIZE_1080X1920;
}else if((x<=1440) && (y<=2560)){
size = SIZE_1440X2560;
}else{
LOGE("Picture size is not standard size\n");
}
return size;
}
从如下代码中得知,对应电池电量的图片是根据 PROGRESSBAR_INDETERMINATE_STATES 这个值来进行设置的,默认为0%-100%每16.6%为一档7个状态,但要求是20%为一档,我们只需要修改 0-5 档的6个状态的图片资源,并把 PROGRESSBAR_INDETERMINATE_STATES 改为 6 即可
#define PROGRESSBAR_INDETERMINATE_STATES 7
frame = level * (PROGRESSBAR_INDETERMINATE_STATES - 1) / 100;
然后修改电池电量 level 的字体,默认情况下字体是显示在图片的外面的上面,客户要求显示在图片中间,而且默认是用图片显示的,默认代码如下:
#ifdef PICTURE_SHOW_PERCENT_SUPPORT
draw_text_picture(level);
#else
draw_text_xy((dy + height), (gr_fb_width()/2 - 20), bat);
#endif
首先去掉文件上面定义的宏 PICTURE_SHOW_PERCENT_SUPPORT,让它走 draw_text_xy 去画字体
然后修改 x,y 的坐标居中显示,修改后的代码如下:
#ifdef PICTURE_SHOW_PERCENT_SUPPORT
draw_text_picture(level);
#else
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 20), bat);
#endif
修改之后发现字体不见了,找了一下原因原来是先画字体然后画图片导致字体被覆盖了,只需要修改一下图片和字体的顺序即可,修改之后代码如下:
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy); //画电量的图片
frame = (frame + 1);
if (frame >= PROGRESSBAR_INDETERMINATE_STATES) {
frame = level * (PROGRESSBAR_INDETERMINATE_STATES - 1) / 100;
}
}
#ifdef PICTURE_SHOW_PERCENT_SUPPORT
draw_text_picture(level);
#else
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 20), bat);
#endif
然后修改字体的颜色,修改之后的代码如下
gr_color(0xa4,0xc6,0x39,255); //RGBA,0xa4c639是客户要求的颜色
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 20), bat);
然后测试之后发现这个字体的坐标是固定坐标,从左边开始画字体,对于0-9是居中的,但是10-100就不是居中的了,需要添加判断level,动态修改字体x的坐标,修改后的代码如下:
gr_color(0xa4,0xc6,0x39,255);
if (level < 10) {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 20), bat);
} else if (level < 100) {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 30), bat);
} else {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 40), bat);
}
然后发现客户对字体也有要求,他们也提供了96x2的图片资源,查看代码发现本身已经支持了这个功能,代码如下:vendor/sprd/proprietories-source/charge/minui/graphics.c
static void gr_init_font(void) {
gr_font = calloc(sizeof(*gr_font), 1);
int res = res_create_alpha_surface("font", &(gr_font->texture)); //系统本身会先去找 font.png 这个资源文件,如果没有就用默认的
if (res == 0) {
// The font image should be a 96x2 array of character images. The
// columns are the printable ASCII characters 0x20 - 0x7f. The
// top row is regular text; the bottom row is bold.
gr_font->cwidth = gr_font->texture->width / 96;
gr_font->cheight = gr_font->texture->height / 2;
} else {
printf("failed to read font: res=%d\n", res);
// fall back to the compiled-in font.
gr_font->texture = malloc(sizeof(*gr_font->texture));
gr_font->texture->width = font.width;
gr_font->texture->height = font.height;
gr_font->texture->row_bytes = font.width;
gr_font->texture->pixel_bytes = 1;
unsigned char* bits = malloc(font.width * font.height);
gr_font->texture->data = (void*) bits;
unsigned char data;
unsigned char* in = font.rundata;
while ((data = *in++)) {
memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
bits += (data & 0x7f);
}
gr_font->cwidth = font.cwidth;
gr_font->cheight = font.cheight;
}
}
系统本身会先去找 font.png 这个资源文件,如果没有就用默认的,所以我们只需要把客户提供的图片改为 font.png 让后放入资源文件夹中即可,测试之后有效果
然后客户对充电动画也有要求,默认的充电动画在没充满的情况下是从0-5每一张图片都会播放,客户要求是 0%-19% 在0-1之间变化,修改后的代码如下
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
if (frame > level * (PROGRESSBAR_INDETERMINATE_STATES - 1) / 100) {
frame = level * (PROGRESSBAR_INDETERMINATE_STATES - 1) / 100;
} else {
frame = (frame + 1);
}
if (level >= 100) {
frame = PROGRESSBAR_INDETERMINATE_STATES - 1;
}
}
#ifdef PICTURE_SHOW_PERCENT_SUPPORT
draw_text_picture(level);
#else
gr_color(0xa4, 0xc6, 0x39, 255);
if (level < 10) {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 20), bat);
} else if (level < 100) {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 30), bat);
} else {
draw_text_xy((dy + height / 2), (gr_fb_width()/2 - 40), bat);
}
#endif
gr_flip(); //从下面的方法介绍中得知这个方法的作用是“刷新显示内容”,调用这个方法之后就会重新调用 charge_thread() 这个方法
修改每次刷新的时间为750ms
void *charge_thread(void *cookie) {
int bat_level = 0;
for (; !is_exit; ) {
if(thread_ext_ctrl == CHARGE_THREAD_CTRL){
thread_count++;
if(thread_count > 5){
is_exit = 1;
thread_count = 0;
}
}
usleep(1000000/ PROGRESSBAR_INDETERMINATE_FPS);
bat_level = battery_capacity();
if(bat_level < 0){
thread_st = CHARGE_THREAD_EXIT_ERROR;
}else{
thread_st = CHARGE_THREAD_OK;
}
pthread_mutex_lock(&gchargeMutex);
led_control(bat_level);
status_index = charge_health_check();
if (screen_on_flag == 1) {
draw_progress_locked(bat_level);
}
pthread_mutex_unlock(&gchargeMutex);
//modified begin
usleep(750000); //这里原来是500000微秒,现在改为750000微秒
//modified end
}
usleep(200);
return NULL;
}
调试方法
./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-sp7731e_1h10_native.ninja charge 2>&1 | tee charge.log;adb wait-for-device;adb root;adb remount;adb sync vendor;adb shell reboot -p;
如果只修改了图片,只需要把对应的图片 push 到 vendor/etc/res/images
文件夹下关机查看关机充电动画即可
快速模拟测试查看从 0%-100% 的充电效果变化的方法
void *charge_thread(void *cookie) {
int bat_level = 0;
for (; !is_exit; ) {
if(thread_ext_ctrl == CHARGE_THREAD_CTRL){
thread_count++;
if(thread_count > 5){
is_exit = 1;
thread_count = 0;
}
}
usleep(1000000/ PROGRESSBAR_INDETERMINATE_FPS);
//modified begin
//bat_level = battery_capacity();
bat_level = bat_level > 100 ? 0 : bat_level++;
//modified end
if(bat_level < 0){
thread_st = CHARGE_THREAD_EXIT_ERROR;
}else{
thread_st = CHARGE_THREAD_OK;
}
pthread_mutex_lock(&gchargeMutex);
led_control(bat_level);
status_index = charge_health_check();
if (screen_on_flag == 1) {
draw_progress_locked(bat_level);
}
pthread_mutex_unlock(&gchargeMutex);
//Redmine46812 zhangqi modified for power off charge anim 2020/10/27:begin
usleep(750000);
//Redmine46812 zhangqi modified for power off charge anim 2020/10/27:end
}
usleep(200);
return NULL;
}
minui简介
方法简介
gr_init() /*初始化图形设备,分配Pixelflinger库渲染的内存*/
gr_font_size() /*将字体对应的surface长宽赋值给char_width和char_height*/
int gr_init(void); /* 初始化图形显示,主要是打开设备、分配内存、初始化一些参数 */
void gr_exit(void); /* 注销图形显示,关闭设备并释放内存 */
int gr_fb_width(void); /* 获取屏幕的宽度 */
int gr_fb_height(void); /* 获取屏幕的高度 */
gr_pixel *gr_fb_data(void); /* 获取显示数据缓存的地址 */
void gr_flip(void); /* 刷新显示内容 */
void gr_fb_blank(bool blank); /* 清屏 */
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); /* 设置字体颜色 */
void gr_fill(int x, int y, int w, int h); /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */
int gr_text(int x, int y, const char *s); /* 显示字符串 */
int gr_measure(const char *s); /* 获取字符串在默认字库中占用的像素长度 */
void gr_font_size(int *x, int *y); /* 获取当前字库一个字符所占的长宽 */
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy); /* 填充由source指定的图片 */
unsigned int gr_get_width(gr_surface surface); /* 获取图片宽度 */
unsigned int gr_get_height(gr_surface surface); /* 获取图片高度 */
int res_create_surface(const char* name, gr_surface* pSurface); /* 根据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */
void res_free_surface(gr_surface surface); /* 释放资源数据 */