system:Android 8.1
platform:RK3326/PX30
uboot
kernel
system/core/healthd


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


文章目录

    • 前言
    • 文件列表
    • 修改 healthd_mode_charger.cpp
      • init_animation
      • healthd_mode_charger_init
      • 替换图片
    • 总结

前言

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

文件列表

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

Android.mk11-Jun-20185.2 KiBanimation.h11-Jun-20181.7 KiBAnimationParser.cpp11-Jun-20184.8 KiBAnimationParser.h11-Jun-20181 KiBBatteryMonitor.cpp11-Jun-201824 KiBBatteryPropertiesRegistrar.cpp11-Jun-20184 KiBBatteryPropertiesRegistrar.h11-Jun-20181.8 KiBcharger.cpp11-Jun-20182.8 KiBhealthd.cpp11-Jun-20183.8 KiBhealthd_common.cpp11-Jun-20188.6 KiBhealthd_draw.cpp11-Jun-20185.7 KiBhealthd_draw.h11-Jun-20182.3 KiBhealthd_mode_android.cpp11-Jun-20182 KiBhealthd_mode_charger.cpp11-Jun-201820.6 KiBimages/11-Jun-20184 KiBinclude/11-Jun-20184 KiBtests/11-Jun-20184 KiB

修改 healthd_mode_charger.cpp

  1. 在头文件animation.h的结构体animation添加成员变量user_animation_file,如下所示;
struct animation {...#define USER_IMAGE_NUM 5std::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_ANIMATIONbattery_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_ANIMATIONbattery_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);}}#elseGRSurface** 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 8.1 关机充电动画(三)Android模式_第1张图片
然后,在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进行修改,或者更高级可以自己画充电动画出来也未尝不可。

更多相关文章

  1. Android加载/处理超大图片神器!
  2. Android中通过Intent 调用图片、视频、音频、录音、拍照
  3. android解决坚屏拍照和保存图片旋转90度的问题,并兼容4.0
  4. 谁说Android的动画不廉价(三)之共享元素动画
  5. android帧动画
  6. android 动画模块分析
  7. android:定制checkbox 图片
  8. android图片缩放手势检测类--ScaleGestureDetector
  9. Android 自定义充电动画

随机推荐

  1. Android(安卓)搭建环境配置
  2. Android(安卓)Pitfall - Fragment.startA
  3. 获取Android设备电池电量状态
  4. Android解析XML
  5. android camera(一):camera模组CMM介绍
  6. android中GridView关于间距的属性值介绍
  7. Android(安卓)屏幕适配
  8. Android(安卓)底层渲染 - 屏幕刷新机制源
  9. Android多屏幕支持Multi-WindowSupport
  10. Android(安卓)技术专题系列之二 -- telepho