system:Android 8.1

platform:RK3326/PX30

uboot

kernel

system/core/healthd


Android 8.1 关机充电动画(一)模式选择

Android 8.1 关机充电动画(二)Uboot模式

Android 8.1 关机充电动画(三)Android模式


前言

Android模式下的关机充电动画修改相对来说需要修改Linux应用层的东西了,可以定位到源码路径/system/core/healthd下,和uboot模式类似,这里只需要修改轮播的充电图片,然后将每张图片和电量百分比对应到代码中即可,思路还是比较简单的,下面我会慢慢分析具体实现的细节。

文件列表

system/core/healthd下可以看到以下文件,只有一部分文件需要修改,我们需要重点关注一下healthd_mode_charger.cpp,因为基本上修改这个文件就够了。

Android.mk						11-Jun-2018	5.2 KiB
animation.h 11-Jun-2018 1.7 KiB
AnimationParser.cpp 11-Jun-2018 4.8 KiB
AnimationParser.h 11-Jun-2018 1 KiB
BatteryMonitor.cpp 11-Jun-2018 24 KiB
BatteryPropertiesRegistrar.cpp 11-Jun-2018 4 KiB
BatteryPropertiesRegistrar.h 11-Jun-2018 1.8 KiB
charger.cpp 11-Jun-2018 2.8 KiB
healthd.cpp 11-Jun-2018 3.8 KiB
healthd_common.cpp 11-Jun-2018 8.6 KiB
healthd_draw.cpp 11-Jun-2018 5.7 KiB
healthd_draw.h 11-Jun-2018 2.3 KiB
healthd_mode_android.cpp 11-Jun-2018 2 KiB
healthd_mode_charger.cpp 11-Jun-2018 20.6 KiB
images/ 11-Jun-2018 4 KiB
include/ 11-Jun-2018 4 KiB
tests/ 11-Jun-2018 4 KiB

修改 healthd_mode_charger.cpp

  1. 在头文件animation.h的结构体animation添加成员变量user_animation_file,如下所示;
struct animation {
...
#define USER_IMAGE_NUM 5
std::string user_animation_file[USER_IMAGE_NUM];
...
}
  1. healthd_mode_charger.cpp添加frame数组user_animation_frames,目前添加了5帧画面,而且代码里直接固定为5帧的画面为一个充电循环来做,这里后面可能需要改动一下;
static animation::frame user_animation_frames[] = {
{
.disp_time = 750,
.min_level = 0,
.max_level = 19,
.surface = NULL,
},
{
.disp_time = 750,
.min_level = 0,
.max_level = 39,
.surface = NULL,
},
{
.disp_time = 750,
.min_level = 0,
.max_level = 59,
.surface = NULL,
},
{
.disp_time = 750,
.min_level = 0,
.max_level = 79,
.surface = NULL,
},
{
.disp_time = 750,
.min_level = 0,
.max_level = 100,
.surface = NULL,
},
};

init_animation

需要对init_animation函数进行部分的修改,这里简单说明一下;

  1. animation_desc_path = "/res/values/charger/animation.txt" ,这里程序中路径具体我也没有找到源码中对应的路径,最终debug的结果是parse_success = false 是一直成立的;所以程序中会直接制定路径下的图片,源码路径system/core/healthd/images/下的图片会在编译的过程中被拷贝到制定的路径下;
  2. 原程序的做法只去解析一张png图片,而且这张图片中包含了所有电池电量百分比的对应信息。
  3. 修改部分加入到条件编译的宏定义CHARGER_USER_ANIMATION中;
animation* init_animation() {
bool parse_success; std::string content;
if (base::ReadFileToString(animation_desc_path, &content)) {
parse_success = parse_animation_desc(content, &battery_animation);
} else {
LOGW("Could not open animation description at %s\n", animation_desc_path);
parse_success = false;
}
if (!parse_success) {
LOGW("Could not parse animation description. Using default animation.\n");
battery_animation = BASE_ANIMATION;
#ifdef CHARGER_USER_ANIMATION
battery_animation.user_animation_file[0].assign("charger/battery_user_0");
battery_animation.user_animation_file[1].assign("charger/battery_user_1");
battery_animation.user_animation_file[2].assign("charger/battery_user_2");
battery_animation.user_animation_file[3].assign("charger/battery_user_3");
battery_animation.user_animation_file[4].assign("charger/battery_user_4");
battery_animation.frames = user_animation_frames;
battery_animation.num_frames = ARRAY_SIZE(user_animation_frames);
#else
battery_animation.animation_file.assign("charger/battery_scale");
battery_animation.frames = default_animation_frames;
battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
#endif }
if (battery_animation.fail_file.empty()) {
#ifdef CHARGER_USER_ANIMATION
battery_animation.fail_file.assign("charger/battery_user_fail");
#else
battery_animation.fail_file.assign("charger/battery_fail");
#endif
}
if(battery_animation.text_percent.font_file.empty())
battery_animation.text_percent.font_file.assign("charger/font");
//battery_animation.text_clock.font_file.assign("charger/font");
LOGW("Animation Description:\n");
LOGW(" animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
battery_animation.num_frames);
LOGW(" fail_file: '%s'\n", battery_animation.fail_file.c_str());
LOGW(" clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
LOGW(" percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
for (int i = 0; i < battery_animation.num_frames; i++) {
LOGW(" frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
}
return &battery_animation;
}

healthd_mode_charger_init

Android底层的2D引擎库使用了skia,对应的每一帧需要分配GRSurface,通过函数res_create_display_surface分配内存,所以,对于需要定制加入的图片,都需要重新分配内存,然后保存到anim->frames[i].surface中,具体的修改如下所示;

void healthd_mode_charger_init(struct healthd_config* config) {
int ret;
charger* charger = &charger_state;
int i;
int epollfd;
dump_last_kmsg();
LOGW("--------------- STARTING CHARGER MODE ---------------\n");
ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
} animation* anim = init_animation();
charger->batt_anim = anim; ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load custom battery_fail image. Reverting to built in.\n");
ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load built in battery_fail image\n");
charger->surf_unknown = NULL;
}
}
#ifdef CHARGER_USER_ANIMATION
GRSurface* scale_frames[USER_IMAGE_NUM]; for(int i = 0; i<USER_IMAGE_NUM; i++){
ret = res_create_display_surface(anim->user_animation_file[i].c_str(), &scale_frames[i]);
if (ret < 0) {
LOGE("Cannot load custom %s image. Reverting to built in.\n",anim->user_animation_file[i].c_str());
}else{
anim->frames[i].surface = scale_frames[i];
LOGW("file is:[%s],anim->frames[%d].surface = charger->surf_unknown;\n",
anim->user_animation_file[i].c_str(),i);
}
}
#else
GRSurface** scale_frames
int scale_count;
int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text
// chunk). We are using hard-coded frame.disp_time instead. ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
&scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
anim->num_frames = 0;
anim->num_cycles = 1;
} else if (scale_count != anim->num_frames) {
LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
anim->num_frames);
anim->num_frames = 0;
anim->num_cycles = 1;
} else {
for (i = 0; i < anim->num_frames; i++) {
anim->frames[i].surface = scale_frames[i];
}
}
#endif
ev_sync_key_state(
std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
charger->next_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
healthd_config = config;
charger->boot_min_cap = config->boot_min_cap;
}

替换图片

把图片复制到/system/core/healthd/images/路径下,注意图片格式需要是png,而且图片保存的位深度为8位,文件名需要和程序中定义的路径变量保持一致即可;如下所示;我简单地切了五张图片,感觉切图的时间比debug的时间还要久。苦。



然后,在Android.mk中可找到,在编译的时候对图片进行了打包,相应的命令如下所示;

...
_img_modules :=
_images :=
$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
$(eval $(call _add-charger-image,$(_img))))
...

完成以上这些步骤之后,重新编译Android系统,当然还需要进入关机充电的Android模式,可以发现充电动画已经修改完了。

总结

这里介绍的是比较简单对充电动画的单帧图片进行替换,如果有更加复杂的需求,还需要在healthd_draw.cpp进行修改,或者更高级可以自己画充电动画出来也未尝不可。

Android 8.1 关机充电动画(三)Android模式的更多相关文章

  1. Android 8.1 关机充电动画(二)Uboot模式

    system:Android 8.1 platform:RK3326/PX30 uboot kernel Android 8.1 关机充电动画(一)模式选择 Android 8.1 关机充电动画(二) ...

  2. Android 8.1 关机充电动画(一)模式选择

    system:Android 8.1 platform:RK3326/PX30 uboot kernel Android 8.1 关机充电动画(一)模式选择 Android 8.1 关机充电动画(二) ...

  3. Android MTK6580 客制化关机充电动画

    1.客制化关机充电图片 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/xxx 找到对应分辨率替换 2.调整显示图片位置.大小 ...

  4. Android9.0 MTK 平板横屏方案修改(强制app横屏 + 开机logo/动画+关机充电横屏 + RecoveryUI 横屏)

    文章较长建议先收藏再看 拆解步骤 1.app 强制横屏显示,无视 android:screenOrientation="portrait" 属性 2.屏幕触摸坐标修改为横屏 3.开 ...

  5. Android ListView item项 显示动画

    (1)使用LayoutAnimation 所谓的布局动画,其实就是为ViewGroup添加显示动画效果,主要用过LayoutAnimationController来控制实现.LayoutAnimati ...

  6. 【转】android 电池(二):android关机充电流程、充电画面显示

    关键词:android 电池关机充电 androidboot.mode charger关机充电 充电画面显示 平台信息:内核:linux2.6/linux3.0系统:android/android4. ...

  7. Android 电池关机充电

    android 电池(一):锂电池基本原理篇 android 电池(二):android关机充电流程.充电画面显示 android 电池(三):android电池系统 android电池(四):电池 ...

  8. android 电池(二):android关机充电流程、充电画面显示【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下a ...

  9. android 关机充电流程

    点击打开链接 0.主要流程 usb插入通过传递cmdline给init解析从而启动充电进程 1. LK lk\app\aboot\aboot.c update_cmdline ---------- i ...

随机推荐

  1. 1-JVM基础

    1-JVM基础 java源码文件,通过javac 转换成class文件. 找到.java文件 词法分析器 tokens流 语法分析器 语义分析器 字节码生成器 转成.class文件 装载 根据全限定路 ...

  2. 神奇的Kivy,让Python快速开发移动app

    随着移动互联网的不断发展,手机.Pad等移动终端已经被普遍使用,充斥在人们的工作.学习和生活中,越来越多的程序都转向移动终端,各类app应用相拥而至. Kivy作为Python的Android和IOS ...

  3. 取代 Python 多进程!伯克利开源分布式框架 Ray

    Ray 由伯克利开源,是一个用于并行计算和分布式 Python 开发的开源项目.本文将介绍如何使用 Ray 轻松构建可从笔记本电脑扩展到大型集群的应用程序. 并行和分布式计算是现代应用程序的主要内容. ...

  4. PHP中级篇 Apache配置httpd-vhosts虚拟主机总结及注意事项

    经常使用Apache虚拟主机进行开发和测试,但每次需要配置虚拟主机时都习惯性的ctrl+c和ctrl+v,这次由于重装系统,需要配置一个新的PHP开发环境虚拟主机,于是总结一下Apaceh配置http ...

  5. python学习04数据

    #1.**幂 //返回商的整数部分x=5y=3print(x**y)print(x//y)print(5/2)#2.复数a+bjc=2+5jprint(c.real)#返回复数的实部print(c.i ...

  6. 动画图解Git命令

    ​Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理,是目前使用范围最广的版本管理工具 尽管Git是一个非常强大的工具,但我认为大多数人都会同意我的说法,即它也可以 ...

  7. vue2.x学习笔记(三十)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12682902.html. 状态管理 类Flux状态管理的官方实现 由于状态零散地分布在许多组件和组件之间的交互中, ...

  8. 每天认识几个HTTP 响应码

    HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成. 1xx信息响应 1xx 的响应结果表明接收的请求正在处理 2xx成功响应 2XX 的响应结果表明请求被正常处理了 3xx重定向 3xx ...

  9. 【集群实战】NFS网络文件共享服务

    1. NFS介绍 1.1 什么是NFS? NFS是Network File System的缩写,中文意思是网络文件系统. 它的主要功能是通过网络(一般是局域网)让不同的主机系统之间可以共享文件或目录. ...

  10. centos分配IP脚本--写的第一个shell脚本

    IDC小菜鸟一枚,非科班出身.常常有客户的centos服务器需要分配15个IP甚至30个IP.每次需要手动分配十分麻烦,于是花了一天时间学了shell脚本,写了这个脚本. #!/bin/bash re ...