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.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 永远锁屏解决方法
  3. 创建 cocos2d-x+lua for android 步骤
  4. 修改ZXing for Android为竖屏模式
  5. Android中通过Intent 调用图片、视频、音频、录音、拍照
  6. android解决坚屏拍照和保存图片旋转90度的问题,并兼容4.0
  7. android 背景圆角以及图片圆角处理
  8. android ubuntu下NDK的开发
  9. Android(安卓)滑动效果入门篇(二)

随机推荐

  1. Android 6.0关于电话的各种Call和Connect
  2. Android内嵌H5(2)
  3. android的进度条使用
  4. 面向忙碌开发者的 Android 知识点收录
  5. android.security.identity Kotlin |Java
  6. Android下 布局加边框 指定背景色 半透明
  7. android登录窗口――基础编
  8. Android控件开发之TextView
  9. Android - ToDoList(fragment) 详解
  10. Android(安卓)UI 开发入门—线性布局练习