zoukankan      html  css  js  c++  java
  • Android 8.1 关机充电动画(三)Android模式

    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
    ", animation_desc_path);
            parse_success = false;
        }
        if (!parse_success) {		
            LOGW("Could not parse animation description. Using default animation.
    ");
            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:
    ");
        LOGW("  animation: %d %d '%s' (%d)
    ", battery_animation.num_cycles,
             battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
             battery_animation.num_frames);
        LOGW("  fail_file: '%s'
    ", battery_animation.fail_file.c_str());
        LOGW("  clock: %d %d %d %d %d %d '%s'
    ", 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'
    ", 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
    ", 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 ---------------
    ");
        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.
    ");
            ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
            if (ret < 0) {
                LOGE("Cannot load built in battery_fail image
    ");
                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.
    ",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;
    ",
    					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
    ");
    			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)
    ", 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进行修改,或者更高级可以自己画充电动画出来也未尝不可。

  • 相关阅读:
    Entity Framework版本历史概览
    Windows客户端C/C++编程规范“建议”——风格
    Bitbucket免费的私有仓库
    呵呵!手把手带你在 IIS 上运行 Python(转)
    RDLC系列之七 条码打印
    WCF 、Web API 、 WCF REST 和 Web Service 的区别
    使用DataAnnotations实现数据验证
    WPF:如何为程序添加splashScreen(初始屏幕)
    无法解析此远程名称: 'www.***.com' 解决办法 请求因 HTTP 状态 417 失败
    关于“服务器提交了协议冲突. Section=ResponseStatusLine"问题
  • 原文地址:https://www.cnblogs.com/unclemac/p/12783398.html
Copyright © 2011-2022 走看看