关机充电动画:流程与定制

关机充电动画:流程与定制

基于MTK平台Android 11分析

生成logo.bin

关机充电动画是由一系列的bmp图片组成的,这些图片资源存在于vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo目录下(当然不仅保护关机充电动画,还包括开机logo)。根据设备屏幕的不同,分别制作了适合不同分辨率的图片。这些图片在编译过程中会被制作成logo.bin文件刷入设备。

该目录下,存在一个子目录tool,存放了用于格式转换及压缩打包的工具。还存在名为rules.mk的文件,该文件定义了生成logo.bin文件的规则。

请添加图片描述

vendor/mediatek/proprietary/bootable/bootloader/lk/scripts下,存放了用于制作logo.bin的工具。

请添加图片描述

下面先来看一下logo.bin具体是怎么制作的。

vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk

LOCAL_DIR := $(GET_LOCAL_DIR)
BOOT_LOGO_DIR := $(LOCAL_DIR)

#fix no boot_logo config
#LOCAL_CFLAGS += -DBOOT_LOGO=wvga

ifeq ($(strip $(BOOT_LOGO)),)
  BOOT_LOGO = fwvga
endif

ifeq ($(strip $(MTK_LK_CAMERA_SUPPORT)), yes)
  BOOT_LOGO = fhd
endif

$(info BOOT_LOGO = $(BOOT_LOGO))
$(info lk/logo/dir=$(LOCAL_DIR),builddir=$(BUILDDIR))

# 定义工具的位置
ifeq ($(HOST_OS),darwin)
BMP_TO_RAW := $(BOOT_LOGO_DIR)/tool/bmp_to_raw.darwin
ZPIPE := $(BOOT_LOGO_DIR)/tool/zpipe.darwin
MKIMG := $(LOCAL_DIR)/../../scripts/mkimage.darwin
else
BMP_TO_RAW := $(BOOT_LOGO_DIR)/tool/bmp_to_raw
ZPIPE := $(BOOT_LOGO_DIR)/tool/zpipe
MKIMG := $(LOCAL_DIR)/../../scripts/mkimage
endif
IMG_HDR_CFG := $(LOCAL_DIR)/img_hdr_logo.cfg

EMPTY :=
UNDER_LINE := _
TEMP := $(strip $(subst $(UNDER_LINE), $(EMPTY), $(BOOT_LOGO)))
COUNT := $(words $(TEMP))
BASE_LOGO := $(word $(COUNT),$(TEMP))
EXIST := $(shell if [ -e $(BOOT_LOGO_DIR)/$(BASE_LOGO) ]; then echo "exist"; else echo "noexist"; fi;)
ifeq ($(EXIST), "noexist")
  BASE_LOGO := $(BOOT_LOGO)
endif

# 是否支持快充
SUPPORT_PUMP_EXPRESS = no
ifeq ($(strip $(MTK_PUMP_EXPRESS_SUPPORT)), yes)
  SUPPORT_PUMP_EXPRESS = yes
else
  ifeq ($(strip $(MTK_PUMP_EXPRESS_PLUS_SUPPORT)), yes)
    SUPPORT_PUMP_EXPRESS = yes
  endif
endif

# 打包后的文件
BOOT_LOGO_RESOURCE := $(BUILDDIR)/$(BOOT_LOGO_DIR)/boot_logo.raw
# 产物名
LOGO_IMAGE := $(BUILDDIR)/logo.bin


define generate_logo_executable

ifneq ($(strip $(MACH_TYPE)), 2701)
ifneq ($(strip $(MTK_ALPS_BOX_SUPPORT)), yes)
# 资源文件列表,有顺序,索引值从0开始
RESOURCE_OBJ_LIST +=   \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_uboot.raw  \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_battery.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_charger_ov.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_1.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_2.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_3.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_4.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_5.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_6.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_7.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_8.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_9.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_num_percent.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_03.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_04.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_05.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_06.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_07.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_08.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_09.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_animation_10.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_03.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_04.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_05.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_06.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_07.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_08.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_09.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_10_10.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_bg.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_img.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_100.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_kernel.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery_remind.raw
endif
endif

# 如果支持快充
ifeq ($(strip $(SUPPORT_PUMP_EXPRESS)), yes)
RESOURCE_OBJ_LIST +=   \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_100.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-03.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-04.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-05.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_ani-06.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_00.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_03.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_04.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_05.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_06.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_07.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_08.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_09.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_fast_charging_percent.raw
endif

# 如果支持无线充电
ifeq ($(strip $(MTK_WIRELESS_CHARGER_SUPPORT)), yes)
RESOURCE_OBJ_LIST +=   \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_00.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_01.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_02.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_03.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_04.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_05.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_06.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_07.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_08.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_09.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_num_percent.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_10_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_10_1.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_10_2.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_10_3.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_30_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_30_1.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_30_2.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_30_3.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_60_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_60_1.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_60_2.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_60_3.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_90_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_90_1.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_90_2.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_90_3.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_0.raw \
            $(BOOT_LOGO_DIR)/$(1)/$(1)_wireless_bat_100.raw
endif

endef

$(foreach BASE_LOGO,$(BOOT_LOGO),$(eval $(call generate_logo_executable,$(BASE_LOGO))))


GENERATED += \
            $(BOOT_LOGO_RESOURCE) \
            $(LOGO_IMAGE) \
            $(addprefix $(BUILDDIR)/,$(RESOURCE_OBJ_LIST))

# 目标
all:: $(LOGO_IMAGE)

#logo.bin具体的的制作命令
$(LOGO_IMAGE):$(MKIMG) $(BOOT_LOGO_RESOURCE)
	@echo "MKING $(LOGO_IMAGE) start"
	@echo $(MKIMG)
	@echo $(BOOT_LOGO_RESOURCE)
	@echo $(LOGO_IMAGE)
	$(MKIMG) $(BOOT_LOGO_RESOURCE) $(IMG_HDR_CFG) > $(LOGO_IMAGE)

# 压缩打包
$(BOOT_LOGO_RESOURCE): $(addprefix $(BUILDDIR)/,$(RESOURCE_OBJ_LIST)) $(ZPIPE)
	@$(MKDIR)
	@echo "zpiping "
	$(ZPIPE) -l 9 $@ $(addprefix $(BUILDDIR)/,$(RESOURCE_OBJ_LIST))

# 格式转换
$(BUILDDIR)/%.raw: %.bmp $(BMP_TO_RAW)
	@$(MKDIR)
	@echo "Compiling_BMP_TO_RAW $<"
	$(BMP_TO_RAW) $@ $<


从编译Log中可以看到更详细过程:

  • 将bmp图像格式转换成raw格式

请添加图片描述

  • 压缩raw文件,最终打包成boot_logo.raw文件

请添加图片描述

  • 生成logo.bin镜像

请添加图片描述

实际刷入机器的并不是这个logo.bin,还需要签名,形成logo-verified.bin

请添加图片描述

充电动画main()函数

充电动画的入口函数,由init进程启动。负责处理充电动画和充电期间的按键控制。

/vendor/mediatek/proprietary/external/charger/main.cpp

#include <sys/resource.h>
#include "main.h"

// add prefer power and backlight keys in below arrays.
int pwrkeys[] = {KEY_POWER, KEY_END};

void exit_charger(int reason)	//退出充电的几种情况
{
    KPOC_LOGI("exit_charger: %d \n", reason);

    switch(reason) {
        case EXIT_ALARM_BOOT:
        case EXIT_POWER_UP:
        case EXIT_REBOOT_UBOOT:
            reboot(RB_AUTOBOOT);
            break;
        case EXIT_CHARGING_MODE:
        case EXIT_ERROR_SHUTDOWN:
        case EXIT_NORMAL_SHUTDOWN:
        default:
            reboot(RB_POWER_OFF);
            break;
    }
}


int main(__attribute__((unused))int argc, __attribute__((unused))char *argv[])
{
    set_draw_anim_mode(1);	//设置充电动画绘制模式(DRAW_ANIM_MODE_FB)。
    pthread_mutex_init(&lights_mutex, NULL); //互斥锁,与灯光控制相关。

    setpriority(PRIO_PROCESS, 0, -20); //设置了进程的优先级。
    FILE *oom_adj = fopen("/proc/self/oom_score_adj", "w");
    if (oom_adj) {
        if (fputs("-17", oom_adj) == EOF) {
           KPOC_LOGI("fputs error\n");
        }
        fclose(oom_adj);
    }

    health_service_init();	//初始化health服务,跟电池健康、充电状态有关。
    light_init();	//灯光初始化。
    //stop_backlight();
    KPOC_LOGI("stop_backlight 1\n");
    bootlogo_init();	//充电动画初始化。

    charging_control();	//充电的相关控制逻辑。

    unsigned int i;
    for (i=0; i< ARRAY_SIZE(pwrkeys); i++)
        KPOC_LOGI("pwrkeys[%d]:%d\n",i,pwrkeys[i]);

    key_control(pwrkeys, ARRAY_SIZE(pwrkeys)); //will loop inside	//充电期间的按键处理。

    return 0;
}

set_draw_anim_mode()函数

根据running_mode设置动画绘制模式。最终会修改vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp中的全局变量
draw_anim_mode,由于running_mode被写死为1,所以动画绘制模式永远为DRAW_ANIM_MODE_FB

vendor/mediatek/proprietary/external/charger/bootlogo.cpp

/*
 *  Set charging animation drawing method according to running mode:
 *  running IPO : using surface flinger , DRAW_ANIM_MODE_SURFACE 
 *  running KPOC: using framebuffer     , DRAW_ANIM_MODE_FB
 */

//传入的running_mode为1
void set_draw_anim_mode(int running_mode)
{
    int draw_anim_mode = DRAW_ANIM_MODE_SURFACE;
    KPOC_LOGD("[ChargingAnimation %s %d]kpoc flag == 1 ? : running_mode = %d \n ",__FUNCTION__,__LINE__ ,running_mode);
    if(running_mode == 1) {
        draw_anim_mode = DRAW_ANIM_MODE_FB;
        KPOC_LOGD("[ChargingAnimation %s %d]under kernel power off charging mode, use fb to draw animation!",__FUNCTION__,__LINE__ );
    } else {
        draw_anim_mode = DRAW_ANIM_MODE_SURFACE; 
    }        

    set_draw_mode(draw_anim_mode);
//    set_draw_mode(DRAW_ANIM_MODE_SURFACE);
}

/home/mh/mediatek/proprietary/external/libshowlogo/charging_animation.cpp

...
static int draw_anim_mode = DRAW_ANIM_MODE_SURFACE;
...

/*
 * Set charging animation drawing method
 *
 */
void set_draw_mode(int draw_mode)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]0 --use framebuffer, 1--use surface flinger ,draw_anim_mode =  :%d",__FUNCTION__,__LINE__ ,draw_mode);
    }
    if ((draw_mode != (DRAW_ANIM_MODE_FB)) && (draw_mode != (DRAW_ANIM_MODE_SURFACE))) {
        draw_anim_mode = DRAW_ANIM_MODE_SURFACE;
    } else {
        draw_anim_mode = draw_mode;
    }
}

bootlogo_init()函数

bootlogo_init()函数主要做了两件事情:

  1. 设置充电动画的样式
  2. 充电动画的初始化

/mediatek/proprietary/external/charger/bootlogo.cpp

/*
 * Init charging animation version , drawing method and other parameters
 *
 */
void bootlogo_init()
{
    KPOC_LOGI("[ChargingAnimation: %s %d]\n",__FUNCTION__,__LINE__);
    sync_anim_version();
    anim_init();
}

sync_anim_version()函数

sync_anim_version()函数用于设置充电动画的样式。

/mediatek/proprietary/external/charger/bootlogo.cpp

/*
 * Read charging animation feature option, and set charging animation version
 *
 * version 0: show 4 recatangle growing animation without battery number 
 * version 1: show wave animation with  battery number                   
 */
//这里注释少写一个version 2,是无线充电的样式。
void sync_anim_version()
{
    KPOC_LOGI("[ChargingAnimation: %s %d]\n",__FUNCTION__,__LINE__);

    if (is_wireless_charging())
    {
        set_anim_version(VERION_WIRELESS_CHARGING_ANIMATION);     
    } else {
#ifdef ANIMATION_NEW
        set_anim_version(VERION_NEW_ANIMATION);       
#else
        set_anim_version(VERION_OLD_ANIMATION);
        KPOC_LOGI("[ChargingAnimation %s %d]not define ANIMATION_NEW:show old animation \n",__FUNCTION__,__LINE__); 
#endif 
    }
}

vendor/mediatek/proprietary/bootable/bootloader/lk/lib/libshowlogo/cust_display.h

/* The option of new charging animation */
#define ANIMATION_NEW

vendor/mediatek/proprietary/external/charger/bootlogo.cpp

#define VERION_OLD_ANIMATION 0
#define VERION_NEW_ANIMATION 1
#define VERION_WIRELESS_CHARGING_ANIMATION  2

anim_init()函数

该函数主要有4个作用:

  1. 通过"ro.charge_animation.rotation"属性获取充电动画的方向。
  2. 初始化充电动画的UI参数。
  3. 加载充电动画资源到内存。
  4. 初始化framebuffer。

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp

/*
 * Charging animation init
 *
 */

void anim_init()
{    
    charge_animation_rotation = getValue("ro.charge_animation.rotation", "");
    init_charging_animation_ui_dimension();
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]\n",__FUNCTION__,__LINE__);
    }
    anim_logo_init();

    if (draw_anim_mode == (DRAW_ANIM_MODE_FB)) {
        anim_fb_init();
    } else {
        anim_surface_init();
    }
}
init_charging_animation_ui_dimension()函数

根据屏幕尺寸的不同,初始化charging_anim_ui_dimension结构体,其定义了充电动画界面的UI元素尺寸。

该结构体的定义在vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.

struct charging_anim_ui_dimension {
	int cap_left;
	int cap_top;
	int cap_right;
	int cap_bottom;
	int num_left;
	int num_top;
	int num_right;
	int num_bottom;
	int percent_left;
	int percent_top;
	int percent_right;
	int percent_bottom;
	int top_anim_left;
	int top_anim_top;
	int top_anim_right;
	int top_anim_bottom;
	int bar_left;
	int bar_top;
	int bar_right;
	int bar_bottom;
    int num_width_fast;
    int num_height_fast;
    int top_margin_fast;
}  ;
struct charging_anim_ui_dimension charg_anim_ui_dimen ;
/*
 * Fill resolution structure based on lcd size
 *
 */
void init_charging_animation_ui_dimension() {
    int lcm_width, lcm_height;
    struct fb_var_screeninfo vinfo;
    display_fd = open("/dev/graphics/fb0", O_RDONLY);
    if (display_fd < 0) {

      SLOGD("[show_animation_common: %s %d]open mtkfb fail...\n",__FUNCTION__,__LINE__);

    }

    if (ioctl(display_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
      close(display_fd);
      SLOGD("[show_animation_common: %s %d]ioctl FBIOGET_VSCREENINFO failed\n",__FUNCTION__,__LINE__);
    }
    close(display_fd);
    lcm_width = vinfo.xres;	//实际的横向分辨率
    lcm_height = vinfo.yres;  //实际的纵向分辨率

   // int rotation = getRotation();
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, charge_animation_rotation);
    }
    if ((270 == charge_animation_rotation)|| (90 == charge_animation_rotation)){
        lcm_width = vinfo.yres;
        lcm_height = vinfo.xres;
    }
    SLOGD("[show_animation_common: %s %d] lcm_width and lcm_height= %d , %d \n",__FUNCTION__,__LINE__,lcm_width,lcm_height);

    if((lcm_width == 1080) && (lcm_height == 1920)) { // Special handling for FHD
      
      SLOGD("[show_animation_common: %s %d]Inside 1080*1920 \n",__FUNCTION__,__LINE__);
      
      
       charg_anim_ui_dimen.cap_left =387;
       charg_anim_ui_dimen.cap_right= 691;
       charg_anim_ui_dimen.num_left=395;
       charg_anim_ui_dimen.num_right=395+84;
       charg_anim_ui_dimen.percent_left=395+84+84;
       charg_anim_ui_dimen.percent_right=395+84+84+108;
       charg_anim_ui_dimen.top_anim_left=387;
       charg_anim_ui_dimen.top_anim_right=691;
       charg_anim_ui_dimen.bar_left=470;
       charg_anim_ui_dimen.bar_top=356;
       charg_anim_ui_dimen.bar_right=610;
       charg_anim_ui_dimen.bar_bottom=678;
       charg_anim_ui_dimen.cap_top= 802;
       charg_anim_ui_dimen.cap_bottom= 1292 ;
       charg_anim_ui_dimen.num_top=479;
       charg_anim_ui_dimen.num_bottom=600;
       charg_anim_ui_dimen.percent_top=479;
       charg_anim_ui_dimen.percent_bottom=600;
       charg_anim_ui_dimen.top_anim_top=100;
       charg_anim_ui_dimen.top_anim_bottom=152;
       charg_anim_ui_dimen.num_width_fast = 108;
       charg_anim_ui_dimen.num_height_fast = 192;
       charg_anim_ui_dimen.top_margin_fast = 240;
    }
  
   else if((lcm_width == 1080) && (lcm_height == 2160)) { // Special handling for FHD+
      
      SLOGD("[show_animation_common: %s %d]Inside 1080*2160 \n",__FUNCTION__,__LINE__);
       charg_anim_ui_dimen.cap_left =387;
       charg_anim_ui_dimen.cap_right= 691;
       charg_anim_ui_dimen.num_left=395;
       charg_anim_ui_dimen.num_right=395+84;
       charg_anim_ui_dimen.percent_left=395+84+84;
       charg_anim_ui_dimen.percent_right=395+84+84+108;
       charg_anim_ui_dimen.top_anim_left=387;
       charg_anim_ui_dimen.top_anim_right=691;
       charg_anim_ui_dimen.bar_left=470;
       charg_anim_ui_dimen.bar_top=356;
       charg_anim_ui_dimen.bar_right=610;
       charg_anim_ui_dimen.bar_bottom=678;
       charg_anim_ui_dimen.cap_top= 922;
       charg_anim_ui_dimen.cap_bottom= 1413 ;
       charg_anim_ui_dimen.num_top=599;
       charg_anim_ui_dimen.num_bottom=720;
       charg_anim_ui_dimen.percent_top=599;
       charg_anim_ui_dimen.percent_bottom=720;
       charg_anim_ui_dimen.top_anim_top=100;
       charg_anim_ui_dimen.top_anim_bottom=152;
       charg_anim_ui_dimen.num_width_fast = 108;
       charg_anim_ui_dimen.num_height_fast = 192;
       charg_anim_ui_dimen.top_margin_fast = 240;
      
    }

    else if(lcm_width==1080) {
        charg_anim_ui_dimen.cap_left =408;
        charg_anim_ui_dimen.cap_right= 671;
        charg_anim_ui_dimen.num_left=445;
        charg_anim_ui_dimen.num_right=445+45;
        charg_anim_ui_dimen.percent_left=445+90;
        charg_anim_ui_dimen.percent_right=445+90+57;
        charg_anim_ui_dimen.top_anim_left=408;
        charg_anim_ui_dimen.top_anim_right=671;
        charg_anim_ui_dimen.bar_left=470;
        charg_anim_ui_dimen.bar_top=356;
        charg_anim_ui_dimen.bar_right=610;
        charg_anim_ui_dimen.bar_bottom=678;
        charg_anim_ui_dimen.num_width_fast = 72;
        charg_anim_ui_dimen.num_height_fast = 128;
        charg_anim_ui_dimen.top_margin_fast = 300;
      
        if (lcm_height == 2280) {
           SLOGD("[show_animation_common: %s %d]Inside 1080*2280 \n",__FUNCTION__,__LINE__);
           charg_anim_ui_dimen.cap_top= 992;
           charg_anim_ui_dimen.cap_bottom= 1473 ;
           charg_anim_ui_dimen.num_top=659;
           charg_anim_ui_dimen.num_bottom=780;
           charg_anim_ui_dimen.percent_top=659;
           charg_anim_ui_dimen.percent_bottom=780;
           charg_anim_ui_dimen.top_anim_top=100;
           charg_anim_ui_dimen.top_anim_bottom=147;
       }
       else if (lcm_height == 2300) {
         SLOGD("[show_animation_common: %s %d]Inside 1080*2300 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 1002;
         charg_anim_ui_dimen.cap_bottom= 1498;
         charg_anim_ui_dimen.num_top=669;
         charg_anim_ui_dimen.num_bottom=790;
         charg_anim_ui_dimen.percent_top=669;
         charg_anim_ui_dimen.percent_bottom=790;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=147;
       }
       else if (lcm_height == 2340) {
         SLOGD("[show_animation_common: %s %d]Inside 1080*2340 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 1012;
         charg_anim_ui_dimen.cap_bottom= 1503 ;
         charg_anim_ui_dimen.num_top=689;
         charg_anim_ui_dimen.num_bottom=810;
         charg_anim_ui_dimen.percent_top=689;
         charg_anim_ui_dimen.percent_bottom=810;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=147;
       }
       else if (lcm_height == 2400) {
         SLOGD("[show_animation_common: %s %d]Inside 1080*2340 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 1042;
         charg_anim_ui_dimen.cap_bottom= 1533 ;
         charg_anim_ui_dimen.num_top=729;
         charg_anim_ui_dimen.num_bottom=840;
         charg_anim_ui_dimen.percent_top=729;
         charg_anim_ui_dimen.percent_bottom=840;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=147;
       }
       else if (lcm_height == 2520) {
         SLOGD("[show_animation_common: %s %d]Inside 1080*2520 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 1112;
         charg_anim_ui_dimen.cap_bottom= 1593 ;
         charg_anim_ui_dimen.num_top=819;
         charg_anim_ui_dimen.num_bottom=819+64;
         charg_anim_ui_dimen.percent_top=819;
         charg_anim_ui_dimen.percent_bottom=819+64;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=147;
       }
    }
    else if(lcm_width ==720) {
       charg_anim_ui_dimen.cap_left =278;
       charg_anim_ui_dimen.cap_right= 441;
       charg_anim_ui_dimen.num_left=290;
       charg_anim_ui_dimen.num_right=335;
       charg_anim_ui_dimen.percent_left=380;
       charg_anim_ui_dimen.percent_right=437;
       charg_anim_ui_dimen.top_anim_left=278;
       charg_anim_ui_dimen.top_anim_right=441;
       charg_anim_ui_dimen.bar_left=313;
       charg_anim_ui_dimen.bar_top=238;
       charg_anim_ui_dimen.bar_right=406;
       charg_anim_ui_dimen.bar_bottom=453;
       charg_anim_ui_dimen.num_width_fast = 72;
       charg_anim_ui_dimen.num_height_fast = 128;
       charg_anim_ui_dimen.top_margin_fast = 180;

       if(lcm_height == 1280) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1280 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 556;
         charg_anim_ui_dimen.cap_bottom= 817 ;
         charg_anim_ui_dimen.num_top=386;
         charg_anim_ui_dimen.num_bottom=450;
         charg_anim_ui_dimen.percent_top=386;
         charg_anim_ui_dimen.percent_bottom=450;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
       }
       else if(lcm_height == 1440) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1440 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 636;
         charg_anim_ui_dimen.cap_bottom= 898 ;
         charg_anim_ui_dimen.num_top=465;
         charg_anim_ui_dimen.num_bottom=529;
         charg_anim_ui_dimen.percent_top=465;
         charg_anim_ui_dimen.percent_bottom=529;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
      }
      else if(lcm_height == 1500) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1500 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 640;
         charg_anim_ui_dimen.cap_bottom= 955 ;
         charg_anim_ui_dimen.num_top=450;
         charg_anim_ui_dimen.num_bottom=515;
         charg_anim_ui_dimen.percent_top=450;
         charg_anim_ui_dimen.percent_bottom=515;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
      }
      else if(lcm_height == 1520) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1520 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 653;
         charg_anim_ui_dimen.cap_bottom= 970 ;
         charg_anim_ui_dimen.num_top=460;
         charg_anim_ui_dimen.num_bottom=535;
         charg_anim_ui_dimen.percent_top=460;
         charg_anim_ui_dimen.percent_bottom=535;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
      }
      else if(lcm_height == 1560) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1560 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 678;
         charg_anim_ui_dimen.cap_bottom= 1000 ;
         charg_anim_ui_dimen.num_top=480;
         charg_anim_ui_dimen.num_bottom=575;
         charg_anim_ui_dimen.percent_top=480;
         charg_anim_ui_dimen.percent_bottom=575;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
      }
      else if(lcm_height == 1600) {
         SLOGD("[show_animation_common: %s %d]Inside 720*1600 \n",__FUNCTION__,__LINE__);
         charg_anim_ui_dimen.cap_top= 703;
         charg_anim_ui_dimen.cap_bottom= 1030 ;
         charg_anim_ui_dimen.num_top=500;
         charg_anim_ui_dimen.num_bottom=615;
         charg_anim_ui_dimen.percent_top=500;
         charg_anim_ui_dimen.percent_bottom=615;
         charg_anim_ui_dimen.top_anim_top=100;
         charg_anim_ui_dimen.top_anim_bottom=129;
      }
    }
   
    else if(lcm_width==1440 && lcm_height==2560) {
      SLOGD("[show_animation_common: %s %d]Inside 1440*2560 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =556;
      charg_anim_ui_dimen.cap_top= 1112;
      charg_anim_ui_dimen.cap_right= 882;
      charg_anim_ui_dimen.cap_bottom= 1630 ;
      charg_anim_ui_dimen.num_left=570;
      charg_anim_ui_dimen.num_top=770;
      charg_anim_ui_dimen.num_right=660;
      charg_anim_ui_dimen.num_bottom=898;
      charg_anim_ui_dimen.percent_left=750;
      charg_anim_ui_dimen.percent_top=770;
      charg_anim_ui_dimen.percent_right=864;
      charg_anim_ui_dimen.percent_bottom=898;
      charg_anim_ui_dimen.top_anim_left=556;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=882;
      charg_anim_ui_dimen.top_anim_bottom=158;
      charg_anim_ui_dimen.bar_left=443;
      charg_anim_ui_dimen.bar_top=337;
      charg_anim_ui_dimen.bar_right=574;
      charg_anim_ui_dimen.bar_bottom=641;
    }
    else if(lcm_width==480 && lcm_height==854) {
      SLOGD("[show_animation_common: %s %d]Inside 480*854 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =172;
      charg_anim_ui_dimen.cap_top= 357;
      charg_anim_ui_dimen.cap_right= 307;
      charg_anim_ui_dimen.cap_bottom= 573 ;
      charg_anim_ui_dimen.num_left=172;
      charg_anim_ui_dimen.num_top=213;
      charg_anim_ui_dimen.num_right=210;
      charg_anim_ui_dimen.num_bottom=267;
      charg_anim_ui_dimen.percent_left=248;
      charg_anim_ui_dimen.percent_top=213;
      charg_anim_ui_dimen.percent_right=296;
      charg_anim_ui_dimen.percent_bottom=267;
      charg_anim_ui_dimen.top_anim_left=172;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=307;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=184;
      charg_anim_ui_dimen.bar_top=227;
      charg_anim_ui_dimen.bar_right=294;
      charg_anim_ui_dimen.bar_bottom=437;
    }
    else if(lcm_width==540 && lcm_height==960) {
      SLOGD("[show_animation_common: %s %d]Inside 540*960 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =202;
      charg_anim_ui_dimen.cap_top= 410;
      charg_anim_ui_dimen.cap_right= 337;
      charg_anim_ui_dimen.cap_bottom= 626 ;
      charg_anim_ui_dimen.num_left=202;
      charg_anim_ui_dimen.num_top=266;
      charg_anim_ui_dimen.num_right=240;
      charg_anim_ui_dimen.num_bottom=320;
      charg_anim_ui_dimen.percent_left=278;
      charg_anim_ui_dimen.percent_top=266;
      charg_anim_ui_dimen.percent_right=326;
      charg_anim_ui_dimen.percent_bottom=320;
      charg_anim_ui_dimen.top_anim_left=202;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=337;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=235;
      charg_anim_ui_dimen.bar_top=179;
      charg_anim_ui_dimen.bar_right=305;
      charg_anim_ui_dimen.bar_bottom=340;
    }
    else if(lcm_width==480 && lcm_height==800) {
      SLOGD("[show_animation_common: %s %d]Inside 480*800 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =172;
      charg_anim_ui_dimen.cap_top= 330;
      charg_anim_ui_dimen.cap_right= 307;
      charg_anim_ui_dimen.cap_bottom= 546 ;
      charg_anim_ui_dimen.num_left=178;
      charg_anim_ui_dimen.num_top=190;
      charg_anim_ui_dimen.num_right=216;
      charg_anim_ui_dimen.num_bottom=244;
      charg_anim_ui_dimen.percent_left=254;
      charg_anim_ui_dimen.percent_top=190;
      charg_anim_ui_dimen.percent_right=302;
      charg_anim_ui_dimen.percent_bottom=244;
      charg_anim_ui_dimen.top_anim_left=172;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=307;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=209;
      charg_anim_ui_dimen.bar_top=149;
      charg_anim_ui_dimen.bar_right=271;
      charg_anim_ui_dimen.bar_bottom=282;
    }
    else if(lcm_width==480 && lcm_height==960) { // default wuvga 480*960
      
      SLOGD("[show_animation_common: %s %d]Inside 480*960 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =172;
      charg_anim_ui_dimen.cap_top= 410;
      charg_anim_ui_dimen.cap_right= 307;
      charg_anim_ui_dimen.cap_bottom= 626 ;
      charg_anim_ui_dimen.num_left=172;
      charg_anim_ui_dimen.num_top=266;
      charg_anim_ui_dimen.num_right=210;
      charg_anim_ui_dimen.num_bottom=320;
      charg_anim_ui_dimen.percent_left=248;
      charg_anim_ui_dimen.percent_top=266;
      charg_anim_ui_dimen.percent_right=296;
      charg_anim_ui_dimen.percent_bottom=320;
      charg_anim_ui_dimen.top_anim_left=172;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=307;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=184;
      charg_anim_ui_dimen.bar_top=227;
      charg_anim_ui_dimen.bar_right=294;
      charg_anim_ui_dimen.bar_bottom=437;
    }
    else if(lcm_width==320 && lcm_height==480) {
      SLOGD("[show_animation_common: %s %d]Inside 320*480 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =109;
      charg_anim_ui_dimen.cap_top= 189;
      charg_anim_ui_dimen.cap_right= 211;
      charg_anim_ui_dimen.cap_bottom= 350 ;
      charg_anim_ui_dimen.num_left=126;
      charg_anim_ui_dimen.num_top=95;
      charg_anim_ui_dimen.num_right=153;
      charg_anim_ui_dimen.num_bottom=131;
      charg_anim_ui_dimen.percent_left=180;
      charg_anim_ui_dimen.percent_top=95;
      charg_anim_ui_dimen.percent_right=212;
      charg_anim_ui_dimen.percent_bottom=131;
      charg_anim_ui_dimen.top_anim_left=109;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=211;
      charg_anim_ui_dimen.top_anim_bottom=118;
      charg_anim_ui_dimen.bar_left=129;
      charg_anim_ui_dimen.bar_top=128;
      charg_anim_ui_dimen.bar_right=190;
      charg_anim_ui_dimen.bar_bottom=245;
    }
    else if(lcm_width==240 && lcm_height==240) {
      SLOGD("[show_animation_common: %s %d]Inside 240*240 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =82;
      charg_anim_ui_dimen.cap_top= 62;
      charg_anim_ui_dimen.cap_right= 158;
      charg_anim_ui_dimen.cap_bottom= 179 ;
      charg_anim_ui_dimen.num_left=92;
      charg_anim_ui_dimen.num_top=8;
      charg_anim_ui_dimen.num_right=108;
      charg_anim_ui_dimen.num_bottom=31;
      charg_anim_ui_dimen.percent_left=124;
      charg_anim_ui_dimen.percent_top=8;
      charg_anim_ui_dimen.percent_right=144;
      charg_anim_ui_dimen.percent_bottom=31;
      charg_anim_ui_dimen.top_anim_left=82;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=158;
      charg_anim_ui_dimen.top_anim_bottom=113;
      charg_anim_ui_dimen.bar_left=97;
      charg_anim_ui_dimen.bar_top=96;
      charg_anim_ui_dimen.bar_right=140;
      charg_anim_ui_dimen.bar_bottom=184;
    }
    else if(lcm_width==600 && lcm_height==1024) {
      SLOGD("[show_animation_common: %s %d]Inside 600*1024 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =232;
      charg_anim_ui_dimen.cap_top= 442;
      charg_anim_ui_dimen.cap_right= 367;
      charg_anim_ui_dimen.cap_bottom= 658 ;
      charg_anim_ui_dimen.num_left=250;
      charg_anim_ui_dimen.num_top=300;
      charg_anim_ui_dimen.num_right=288;
      charg_anim_ui_dimen.num_bottom=354;
      charg_anim_ui_dimen.percent_left=326;
      charg_anim_ui_dimen.percent_top=300;
      charg_anim_ui_dimen.percent_right=374;
      charg_anim_ui_dimen.percent_bottom=354;
      charg_anim_ui_dimen.top_anim_left=232;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=367;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=260;
      charg_anim_ui_dimen.bar_top=190;
      charg_anim_ui_dimen.bar_right=338;
      charg_anim_ui_dimen.bar_bottom=360;
    }
    else if(lcm_width==1024 && lcm_height==600) {
      SLOGD("[show_animation_common: %s %d]Inside 1024*600 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =444;
      charg_anim_ui_dimen.cap_top= 230;
      charg_anim_ui_dimen.cap_right= 579;
      charg_anim_ui_dimen.cap_bottom= 446 ;
      charg_anim_ui_dimen.num_left=466;
      charg_anim_ui_dimen.num_top=90;
      charg_anim_ui_dimen.num_right=504;
      charg_anim_ui_dimen.num_bottom=144;
      charg_anim_ui_dimen.percent_left=542;
      charg_anim_ui_dimen.percent_top=90;
      charg_anim_ui_dimen.percent_right=590;
      charg_anim_ui_dimen.percent_bottom=144;
      charg_anim_ui_dimen.top_anim_left=444;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=579;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=414;
      charg_anim_ui_dimen.bar_top=186;
      charg_anim_ui_dimen.bar_right=608;
      charg_anim_ui_dimen.bar_bottom=477;
    }
    else if(lcm_width==1280 && lcm_height==800) {
      SLOGD("[show_animation_common: %s %d]Inside 1280*800 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =558;
      charg_anim_ui_dimen.cap_top= 265;
      charg_anim_ui_dimen.cap_right= 721;
      charg_anim_ui_dimen.cap_bottom= 525 ;
      charg_anim_ui_dimen.num_left=585;
      charg_anim_ui_dimen.num_top=95;
      charg_anim_ui_dimen.num_right=630;
      charg_anim_ui_dimen.num_bottom=159;
      charg_anim_ui_dimen.percent_left=675;
      charg_anim_ui_dimen.percent_top=95;
      charg_anim_ui_dimen.percent_right=732;
      charg_anim_ui_dimen.percent_bottom=159;
      charg_anim_ui_dimen.top_anim_left=558;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=721;
      charg_anim_ui_dimen.top_anim_bottom=129;
      charg_anim_ui_dimen.bar_left=525;
      charg_anim_ui_dimen.bar_top=250;
      charg_anim_ui_dimen.bar_right=755;
      charg_anim_ui_dimen.bar_bottom=640;
    }
    else if(lcm_width==1366 && lcm_height==768) {
      SLOGD("[show_animation_common: %s %d]Inside 1366*768 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =558;
      charg_anim_ui_dimen.cap_top= 265;
      charg_anim_ui_dimen.cap_right= 721;
      charg_anim_ui_dimen.cap_bottom= 525 ;
      charg_anim_ui_dimen.num_left=585;
      charg_anim_ui_dimen.num_top=95;
      charg_anim_ui_dimen.num_right=630;
      charg_anim_ui_dimen.num_bottom=159;
      charg_anim_ui_dimen.percent_left=675;
      charg_anim_ui_dimen.percent_top=95;
      charg_anim_ui_dimen.percent_right=732;
      charg_anim_ui_dimen.percent_bottom=159;
      charg_anim_ui_dimen.top_anim_left=558;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=721;
      charg_anim_ui_dimen.top_anim_bottom=129;
      charg_anim_ui_dimen.bar_left=525;
      charg_anim_ui_dimen.bar_top=250;
      charg_anim_ui_dimen.bar_right=755;
      charg_anim_ui_dimen.bar_bottom=640;
    }
    else if(lcm_width==800 && lcm_height==1280) {
      SLOGD("[show_animation_common: %s %d]Inside 800*1280 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =318;
      charg_anim_ui_dimen.cap_top= 556;
      charg_anim_ui_dimen.cap_right= 481;
      charg_anim_ui_dimen.cap_bottom= 815 ;
      charg_anim_ui_dimen.num_left=345;
      charg_anim_ui_dimen.num_top=385;
      charg_anim_ui_dimen.num_right=390;
      charg_anim_ui_dimen.num_bottom=449;
      charg_anim_ui_dimen.percent_left=435;
      charg_anim_ui_dimen.percent_top=385;
      charg_anim_ui_dimen.percent_right=492;
      charg_anim_ui_dimen.percent_bottom=449;
      charg_anim_ui_dimen.top_anim_left=318;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=481;
      charg_anim_ui_dimen.top_anim_bottom=129;
      charg_anim_ui_dimen.bar_left=348;
      charg_anim_ui_dimen.bar_top=238;
      charg_anim_ui_dimen.bar_right=453;
      charg_anim_ui_dimen.bar_bottom=452;
    }
    else if(lcm_width==1920 && lcm_height==1200) {
      SLOGD("[show_animation_common: %s %d]Inside 600*1024 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =806;
      charg_anim_ui_dimen.cap_top= 443;
      charg_anim_ui_dimen.cap_right= 1110;
      charg_anim_ui_dimen.cap_bottom= 929 ;
      charg_anim_ui_dimen.num_left=855;
      charg_anim_ui_dimen.num_top=124;
      charg_anim_ui_dimen.num_right=939;
      charg_anim_ui_dimen.num_bottom=245;
      charg_anim_ui_dimen.percent_left=1023;
      charg_anim_ui_dimen.percent_top=124;
      charg_anim_ui_dimen.percent_right=1131;
      charg_anim_ui_dimen.percent_bottom=245;
      charg_anim_ui_dimen.top_anim_left=806;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=1110;
      charg_anim_ui_dimen.top_anim_bottom=152;
      charg_anim_ui_dimen.bar_left=890;
      charg_anim_ui_dimen.bar_top=357;
      charg_anim_ui_dimen.bar_right=1030;
      charg_anim_ui_dimen.bar_bottom=678;
    }
    else if(lcm_width==1200 && lcm_height==1920) {
      SLOGD("[show_animation_common: %s %d]Inside 1200*1920 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =447;
      charg_anim_ui_dimen.cap_top= 803;
      charg_anim_ui_dimen.cap_right= 751;
      charg_anim_ui_dimen.cap_bottom= 1289 ;
      charg_anim_ui_dimen.num_left=494;
      charg_anim_ui_dimen.num_top=481;
      charg_anim_ui_dimen.num_right=578;
      charg_anim_ui_dimen.num_bottom=602;
      charg_anim_ui_dimen.percent_left=662;
      charg_anim_ui_dimen.percent_top=481;
      charg_anim_ui_dimen.percent_right=770;
      charg_anim_ui_dimen.percent_bottom=602;
      charg_anim_ui_dimen.top_anim_left=447;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=751;
      charg_anim_ui_dimen.top_anim_bottom=152;
      charg_anim_ui_dimen.bar_left=529;
      charg_anim_ui_dimen.bar_top=357;
      charg_anim_ui_dimen.bar_right=672;
      charg_anim_ui_dimen.bar_bottom=680;
    }
    else if(lcm_width==768 && lcm_height==1024) {
      SLOGD("[show_animation_common: %s %d]Inside 768*1024 \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =316;
      charg_anim_ui_dimen.cap_top= 442;
      charg_anim_ui_dimen.cap_right= 451;
      charg_anim_ui_dimen.cap_bottom= 658 ;
      charg_anim_ui_dimen.num_left=338;
      charg_anim_ui_dimen.num_top=300;
      charg_anim_ui_dimen.num_right=376;
      charg_anim_ui_dimen.num_bottom=354;
      charg_anim_ui_dimen.percent_left=414;
      charg_anim_ui_dimen.percent_top=300;
      charg_anim_ui_dimen.percent_right=462;
      charg_anim_ui_dimen.percent_bottom=354;
      charg_anim_ui_dimen.top_anim_left=316;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=451;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=334;
      charg_anim_ui_dimen.bar_top=243;
      charg_anim_ui_dimen.bar_right=434;
      charg_anim_ui_dimen.bar_bottom=463;
    }
    else { // default wvga 480*800
      SLOGD("[show_animation_common: %s %d]default case final else \n",__FUNCTION__,__LINE__);
      charg_anim_ui_dimen.cap_left =172;
      charg_anim_ui_dimen.cap_top= 330;
      charg_anim_ui_dimen.cap_right= 307;
      charg_anim_ui_dimen.cap_bottom= 546 ;
      charg_anim_ui_dimen.num_left=178;
      charg_anim_ui_dimen.num_top=190;
      charg_anim_ui_dimen.num_right=216;
      charg_anim_ui_dimen.num_bottom=244;
      charg_anim_ui_dimen.percent_left=254;
      charg_anim_ui_dimen.percent_top=290;
      charg_anim_ui_dimen.percent_right=302;
      charg_anim_ui_dimen.percent_bottom=244;
      charg_anim_ui_dimen.top_anim_left=172;
      charg_anim_ui_dimen.top_anim_top=100;
      charg_anim_ui_dimen.top_anim_right=307;
      charg_anim_ui_dimen.top_anim_bottom=124;
      charg_anim_ui_dimen.bar_left=209;
      charg_anim_ui_dimen.bar_top=149;
      charg_anim_ui_dimen.bar_right=271;
      charg_anim_ui_dimen.bar_bottom=282;
   }
 }

请添加图片描述

anim_logo_init()

加载动画资源到内存。

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp

/*
 * Charging animation logo.bin related init
 *
 */
void anim_logo_init(void)
{
    // read and de-compress logo data here
    int fd = 0;
    int len = 0;
    Fstab fstab;

    if (!ReadDefaultFstab(&fstab)) {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("failed to open fstab\n");
        }
        error_flag = 1;
        return;
    }

    auto rec = GetEntryForMountPoint(&fstab, LOGO_MNT_POINT);	//获取logo挂载点
    if (rec == nullptr) {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("failed to get entry for %s\n", LOGO_MNT_POINT);
        }
        error_flag = 1;
        return;
    }

    // "rec->blk_device" is the path
    fd = open(rec->blk_device.c_str(), O_RDONLY);	//只读方式打开rec->blk_device.c_str()文件
    // get logo patition from fstab end
    if(fd < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("[libshowlogo: %s %d]open logo partition device file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
        }
        goto error_return;
    }

    logo_addr = (unsigned int*)malloc(LOGO_BUFFER_SIZE);
    if(logo_addr == NULL)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("[libshowlogo: %s %d]allocate logo buffer fail, size=0x%08x \n",__FUNCTION__,__LINE__ , LOGO_BUFFER_SIZE);
        }
        goto error_return;
    }

    // (1) skip the image header
    len = read(fd, logo_addr, 512);
    if (len < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("[libshowlogo: %s %d]read from logo addr for 512B is failed! \n",__FUNCTION__,__LINE__);
        }
        goto error_return;
    }
    // get the image
    len = read(fd, logo_addr, LOGO_BUFFER_SIZE - 512);	//获取logo数据到logo_addr指向的内存,前512字节跳过
    if (len < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("[libshowlogo: %s %d]read from logo addr for buffer is failed! \n",__FUNCTION__,__LINE__);
        }
        goto error_return;
    }
    close(fd);

    if (show_animationm_ver > 0)
    {
        unsigned int *pinfo = (unsigned int*)logo_addr;
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[libshowlogo: %s %d]pinfo[0]=%d, pinfo[1]=%d\n", __FUNCTION__,__LINE__, pinfo[0], pinfo[1]);
        }

        if ((show_animationm_ver == VERION_WIRELESS_CHARGING_ANIMATION) && (pinfo[0] < ANIM_V2_LOGO_NUM))
        {
            set_anim_version(VERION_NEW_ANIMATION);
        }
        if (pinfo[0] < ANIM_V1_LOGO_NUM)
        {
            kernel_logo_position = ANIM_V0_LOGO_NUM - 1;
            set_anim_version(VERION_OLD_ANIMATION);
        }
    }
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]show_animationm_ver =  :%d",__FUNCTION__,__LINE__ ,show_animationm_ver);
    }
    return;

error_return:
    if(fd >= 0)
    {
        close(fd);
    }
    free_fstab();
    sleep(3);
    error_flag = 1;
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d] error return !!!\n",__FUNCTION__,__LINE__);
    }
    // to prevent interlace operation with MD reset
}
anim_fb_init()

framebuffer初始化、设置屏幕信息等。

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp

/*
 * Charging animation framebuffer related init
 *
 */
int anim_fb_init(void)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]\n",__FUNCTION__,__LINE__);
    }

    fb_fd = open(FB_NODE_PATH, O_RDWR);
    if(fb_fd < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("[libshowlogo: %s %d]open dev file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
        }
        close(fb_fd);
        error_flag = 1;

        return -1;
    }

#ifndef MTK_HWC_USE_DRM_DEVICE
	///dual add begin
	memset((void *)&fb_info, 0, sizeof(fb_info));
    if (ioctl(fb_fd, MTKFB_GET_DISPLAY_PATH_INFO, &fb_info) < 0)
        SLOGD("ioctl error %s size %d\n", strerror(errno), sizeof(struct fb_display_path_info));

    pathcnt = fb_info.path_cnt;
    SLOGD("[libshowlogo: %s %d] pathcnt = %d\n",__FUNCTION__,__LINE__, pathcnt);
#endif
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
    ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);

    fb_size  = finfo.line_length * vinfo.yres;
    dec_logo_addr = (unsigned int*) malloc(fb_size);
#ifndef MTK_HWC_USE_DRM_DEVICE
    if (pathcnt > 1) {
        lk_fb_addr =(unsigned int*)mmap(0, fb_size*6, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    } else {
        lk_fb_addr =(unsigned int*)mmap(0, fb_size*3, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    }
#else
    lk_fb_addr =(unsigned int*)mmap(0, fb_size*3, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
#endif
    charging_fb_addr = (unsigned int*)((unsigned int)lk_fb_addr + fb_size);
    kernel_fb_addr = (unsigned int*)((unsigned int)charging_fb_addr + fb_size);
    fb_addr = lk_fb_addr;
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]vinfo:xres  = %d, yres = %d, xres_virtual =%d, bits_per_pixel = %d,red.offset = %d,blue.offset = %d\n"
                ,__FUNCTION__, __LINE__, vinfo.xres,vinfo.yres, vinfo.xres_virtual, vinfo.bits_per_pixel,vinfo.red.offset,vinfo.blue.offset);

        SLOGD("[libshowlogo: %s %d]fb_size =%d, fb_addr = %p,charging_fb_addr=%p\n"
                ,__FUNCTION__, __LINE__, fb_size,fb_addr, charging_fb_addr);
    }

    if(fb_addr == NULL || charging_fb_addr == NULL)
    {
        if (MTK_LOG_ENABLE == 1) {
            SLOGE("ChargingAnimation mmap fail\n");
        }
#ifndef MTK_HWC_USE_DRM_DEVICE
        if (pathcnt > 1) {
            munmap(lk_fb_addr, fb_size*6);
        } else {
            munmap(lk_fb_addr, fb_size*2);
        }
#else
        munmap(lk_fb_addr, fb_size*2);
#endif
        close(fb_fd);
        error_flag = 1;

        return -1;
    }

    phical_screen.bits_per_pixel = vinfo.bits_per_pixel;
    phical_screen.fill_dst_bits = vinfo.bits_per_pixel;
    phical_screen.red_offset = vinfo.red.offset;
    phical_screen.blue_offset = vinfo.blue.offset;

    phical_screen.width = vinfo.xres;
    phical_screen.height = vinfo.yres;

    phical_screen.allignWidth = finfo.line_length/(vinfo.bits_per_pixel/8);

    phical_screen.needAllign = 1;
    phical_screen.need180Adjust = 1;
    phical_screen.fb_size = fb_size;
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION);
    }
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]charge_animation_rotation = %d\n",__FUNCTION__,__LINE__, charge_animation_rotation);
    }

    if(270 == charge_animation_rotation){//270
        phical_screen.rotation = 270;
    } else if(90 == charge_animation_rotation){//90
        phical_screen.rotation = 90;
    } else if((180 == charge_animation_rotation) && (phical_screen.need180Adjust == 1)){//180
        phical_screen.rotation = 180;
    } else {
        phical_screen.rotation = 0;
    }

#ifndef MTK_HWC_USE_DRM_DEVICE
    if (pathcnt > 1) {
	    for(unsigned int i = 0; i < pathcnt; i++)
	    {
	        phical_screenArr[i].width = fb_info.xres[i];
	        phical_screenArr[i].height = fb_info.yres[i];
	        phical_screenArr[i].needAllign = 1;
	        phical_screenArr[i].need180Adjust = 1;

	        fb_addrArr[i] = (unsigned int*)((unsigned int)kernel_fb_addr + fb_size * i);

	        phical_screenArr[i].bits_per_pixel = vinfo.bits_per_pixel;
	        phical_screenArr[i].fill_dst_bits = vinfo.bits_per_pixel;
	        phical_screenArr[i].red_offset = vinfo.red.offset;
	        phical_screenArr[i].blue_offset = vinfo.blue.offset;

	        phical_screenArr[i].allignWidth = fb_info.line_length[i]/(vinfo.bits_per_pixel/8);
	        phical_screenArr[i].fb_size = fb_info.line_length[i] * fb_info.yres[i];
	        dec_logo_addrArr[i] = (unsigned int*) malloc(phical_screenArr[i].fb_size);

	        SLOGD("[libshowlogo: %s %d] x = %d, y= %d , fb_info.line_length=%d , fb_size=%d addr 0x%p\n",__FUNCTION__,__LINE__,
	                fb_info.xres[i], fb_info.yres[i], fb_info.line_length[i], phical_screenArr[i].fb_size, fb_addrArr[i]);
	        if(ORIENTATION_270 == charge_animation_rotation)
	        {
	            phical_screenArr[i].rotation = 270;
	        } else if(ORIENTATION_90 == charge_animation_rotation){
	            phical_screenArr[i].rotation = 90;
	        } else if((ORIENTATION_180 == charge_animation_rotation) && (phical_screen.need180Adjust == 1)){//180
	            phical_screenArr[i].rotation = 180;
	        } else {
	            phical_screenArr[i].rotation = 0;
	        }

	    }
    }
#endif
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo]phical_screen: width= %d,height= %d,bits_per_pixel =%d,needAllign = %d,allignWidth=%d rotation =%d ,need180Adjust = %d\n",
                phical_screen.width, phical_screen.height,
                phical_screen.bits_per_pixel, phical_screen.needAllign,
                phical_screen.allignWidth, phical_screen.rotation, phical_screen.need180Adjust);
        SLOGD("[libshowlogo: %s %d]show old animtion= 1, running show_animationm_ver %d\n",__FUNCTION__,__LINE__, show_animationm_ver);
        SLOGD("[libshowlogo: %s %d]draw_anim_mode = 1, running mode %d\n",__FUNCTION__,__LINE__, draw_anim_mode);
    }

    return 0;
}

charging_control()函数

充电指示灯及充电动画显示的控制。

/mediatek/proprietary/external/charger/charging_control.cpp

void charging_control()
{
	int ret = 0;
	pthread_attr_t attr, attrd, attrl;
	pthread_t uevent_thread, draw_thread;

	//charging led control
	if (!is_charging_source_available()) {	//return (usb_online || ac_online || wireless_online || vchr >= 2500);
		lights_exit();
	}

	pthread_mutex_init(&mutexlstate, NULL);

	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	pthread_attr_init(&attr);
	pthread_attr_init(&attrd);
	pthread_attr_init(&attrl);

	inDraw = 0;

	ret = pthread_create(&uevent_thread, &attr, uevent_thread_routine, NULL);	//创建处理充电事件的线程
	if (ret != 0)
	{
		KPOC_LOGI("create uevt pthread failed.\n");
		exit_charger(EXIT_ERROR_SHUTDOWN);
	}

	firstTime = 1;
	ret = pthread_create(&draw_thread, &attrd, draw_thread_routine, NULL);	//创建处理充电动画绘制的线程
	if (ret != 0)
	{
		KPOC_LOGI("create draw pthread failed.\n");
		exit_charger(EXIT_ERROR_SHUTDOWN);
	}
}

uevent_thread_routine()函数

监听系统事件,当事件为电池状态变化时,根据当前充电状态和电池电量调整充电指示灯的状态。

static void* uevent_thread_routine(__attribute__((unused))void *arg)
{
	char buf[1024];
	int len;

	if (!uevent_init())
	{
		KPOC_LOGI("uevent_init failed.\n");
		return 0;
	}

	while (1)
	{
		len = uevent_next_event(buf, sizeof(buf) - 1);
		if (len > 0) {
			if (!on_uevent(buf, len))
				break;
		}
	}
	pthread_exit(NULL);
	return NULL;
}


static int on_uevent(const char *buf, __attribute__((unused))int len_buf)
{
#ifdef VERBOSE_OUTPUT
	KPOC_LOGI("on_uevent, %s\n", buf);
#endif
	if (!strcasestr(buf, UEVENT_BATTERY_CHANGE))
		return 1;

	//if ac or usb online
	if (is_charging_source_available())
	{
		bc = get_capacity();

		if (bc >= 90) {
			lights_full();
		} else {
			if (nCurrentState != LIGHTS_STATE_CHGON)
                set_light_state(LIGHTS_CHGON);
			lights_on();
		}
	}
	else
        exit_charger(EXIT_CHARGING_MODE);

	return 1;
}

draw_thread_routine()函数

vendor/mediatek/proprietary/external/charger/charging_control.cpp

static void* draw_thread_routine(__attribute__((unused))void *arg)
{
	int bc;
	int fd_fb, err =0;
	char filename[32] = {0};

	do {	//死循环
		KPOC_LOGI("draw thread working2...\n");
        // move here to avoid suspend when syncing with surfaceflinger

        if(firstTime){
            // make sure charging source online when in KPOC mode
            // add 2s tolerance
            if(wait_until(is_charging_source_available,
                        charging_source_waiting_duration_ms,
                        charging_source_waiting_interval_ms))
            {
                KPOC_LOGI("wait until charging source available\n");
            }else{
                KPOC_LOGI("charging source not available for %d ms at KPOC starup\n",
                        charging_source_waiting_duration_ms);
            }
            firstTime = 0;
        }

		inDraw = 1;

		// check the bc offest value
		bc = get_capacity();	//获取电池电量
		draw_with_interval(bootlogo_show_charging, bc, nChgAnimDuration_msec, nCbInterval_msec);	//nChgAnimDuration_msec = 6000; nCbInterval_msec = 200;
		stop_backlight();	//关闭背光

        // @@@ draw fb again to refresh ddp
        bootlogo_show_charging(bc, 1);

		/* make fb blank */
		err = snprintf(filename, sizeof(filename), "/dev/graphics/fb0");
		if (err < 0) {
			KPOC_LOGI("Failed at snprintf: %s\n", strerror(errno));
			break;
		}
		fd_fb = open(filename, O_RDWR);
		if (fd_fb < 0) {
			KPOC_LOGI("Failed to open fb0 device: %s", strerror(errno));
			break;
		}
		err = ioctl(fd_fb, FBIOBLANK, FB_BLANK_POWERDOWN);
		if (err < 0) {
			KPOC_LOGI("Failed to blank fb0 device: %s", strerror(errno));
		}
		if (fd_fb >= 0)
			close(fd_fb);
		request_suspend(true);

		inDraw = 0;

        pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond, &mutex);
		pthread_mutex_unlock(&mutex);
	} while(1);
	pthread_exit(NULL);
	return NULL;
}
draw_with_interval()函数

控制动画绘制的时长和间隔。total_time_msec = 6000; interval_msec = 200;

// total_time : ms
// interval : ms
static void draw_with_interval(void (*func)(int, int), int bc, int total_time_msec, int interval_msec)
{
	struct timeval start;
	int resume_started = 0, backlight_started = 0, cnt = 0;
	int fd_fb, err = 0;
	char filename[32] = {0};
	gettimeofday(&start, NULL);	//Get the current time of day, putting it into *TV.

	while(!time_exceed(start, total_time_msec) && !key_trigger_suspend)	//只要不超时就循环绘制
	{
        // check if need to draw animation before performing drawing
		if (!is_charging_source_available())
			return;
		if (!resume_started) {
			resume_started = 1;
			request_suspend(false);
			/* make fb unblank */
			err = snprintf(filename, sizeof(filename), "/dev/graphics/fb0");
			if (err < 0) {
				KPOC_LOGI("Failed at snprintf: %s\n", strerror(errno));
				return;
			}
			fd_fb = open(filename, O_RDWR);
			if (fd_fb < 0) {
				KPOC_LOGI("Failed to open fb0 device: %s", strerror(errno));
			}
			err = ioctl(fd_fb, FBIOBLANK, FB_BLANK_UNBLANK);
			if (err < 0) {
				KPOC_LOGI("Failed to unblank fb0 device: %s", strerror(errno));
			}
			if (fd_fb >= 0)
				close(fd_fb);
		}

		func(bc, ++cnt);
		if (!backlight_started) {
			backlight_started = 1;
			usleep(1000);
			start_backlight();
		}
		KPOC_LOGI("draw_with_interval... key_trigger_suspend = %d\n",key_trigger_suspend);
		usleep(interval_msec*1000);
	}
}
bool time_exceed(struct timeval start, int duration_msec)
{
	struct timeval now;
	gettimeofday(&now, NULL);

	if((now.tv_sec - start.tv_sec)*1000000 + now.tv_usec - start.tv_usec > duration_msec*1000)	//单位转换后再比较
		return true;
	else
		return false;
}

timeval结构体

/* A time value that is accurate to the nearest
   microsecond but also has a range of years.  */
struct timeval
{
#ifdef __USE_TIME_BITS64
  __time64_t tv_sec;		/* Seconds.  */
  __suseconds64_t tv_usec;	/* Microseconds.  */
#else
  __time_t tv_sec;		/* Seconds.  */
  __suseconds_t tv_usec;	/* Microseconds.  */
#endif
};

bootlogo_show_charging()函数

绘制充电动画的入口函数。

vendor/mediatek/proprietary/external/charger/bootlogo.cpp

/*
 * Show charging animation with battery capacity
 *
 */
void bootlogo_show_charging(int capacity, int cnt)
{
    KPOC_LOGI("[ChargingAnimation: %s %d]%d, %d\n",__FUNCTION__,__LINE__, capacity, cnt);

    if (get_battnotify_status())
    {
        KPOC_LOGI("[ChargingAnimation: %s %d] show_charger_error_logo, get_battnotify_status()= %d \n",__FUNCTION__,__LINE__, get_battnotify_status());
        show_charger_ov_logo();
        return;
    }
    if (showLowBattLogo)
    {
        KPOC_LOGI("[ChargingAnimation: %s %d] show_low_battery , showLowBattLogo = %d \n",__FUNCTION__,__LINE__,showLowBattLogo);
        show_low_battery();
        return;
    }
    show_battery_capacity(capacity);
}
static const char *bat_notify_path[] = {
    "/sys/devices/platform/charger/BatteryNotify",
    "/sys/devices/platform/mt-battery/BatteryNotify",
};

/*
 * return value:
 *     1: abnormal status
 *     0: normal status
 *     If path is not found, return 0
 */
int get_battnotify_status()
{
    int i = 0;
    int bat_status = 0;

    /* Find path for battery status */
    for (i = 0; i < ARRAY_SIZE(bat_notify_path); i++) {
        bat_status = get_int_value(bat_notify_path[i]);
        if (bat_status != -1)
            break;
    }
    KPOC_LOGI("charger battStatus=%d, idx=%d\n", bat_status, i);

    if (bat_status > 0)
        return 1;

    return 0;
}

请添加图片描述

请添加图片描述

show_battery_capacity()函数

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp

/*
 * Show charging animation with battery capacity
 *
 */
void show_battery_capacity(unsigned int capacity)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]capacity =%d\n",__FUNCTION__,__LINE__, capacity);
    }

    if (draw_anim_mode == (DRAW_ANIM_MODE_FB)) {
        anim_fb_addr_switch();	//切换缓冲区
#if defined(MSSI_MTK_PUMP_EXPRESS_SUPPORT) || defined(MSSI_MTK_PUMP_EXPRESS_PLUS_SUPPORT) || defined(MSSI_MTK_PUMP_EXPRESS_PLUS_20_SUPPORT) //快充相关
        if (2 != show_animationm_ver && get_fast_charging_state()) {
            fill_animation_battery_fast_charging(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen, draw_anim_mode);
        } else {
            fill_animation_battery_by_ver(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen, show_animationm_ver);
        }
#else
        fill_animation_battery_by_ver(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen, show_animationm_ver);
#endif
        anim_fb_disp_update(); //更新缓冲区
    } else {
        ARect tmpRect;
        tmpRect.left = 0;
        tmpRect.top = 0;
        tmpRect.right = phical_screen.width;
        tmpRect.bottom = phical_screen.height;

        status_t  lockResult = surface->lock(&outBuffer, &tmpRect);
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[libshowlogo: %s %d]outBuffer.bits = %d, surface->lock return =  0x%08x,\n",__FUNCTION__,__LINE__, (int)outBuffer.bits,lockResult);
        }

        if (0 == lockResult)
        {
#if defined(MSSI_MTK_PUMP_EXPRESS_SUPPORT) || defined(MSSI_MTK_PUMP_EXPRESS_PLUS_SUPPORT) || defined(MSSI_MTK_PUMP_EXPRESS_PLUS_20_SUPPORT)
            if (2 != show_animationm_ver && get_fast_charging_state()) {
                fill_animation_battery_fast_charging(capacity, (void *)outBuffer.bits, dec_logo_addr, logo_addr, phical_screen, draw_anim_mode);
            } else {
                fill_animation_battery_by_ver(capacity, (void *)outBuffer.bits, dec_logo_addr, logo_addr, phical_screen, show_animationm_ver);
            }
#else
            fill_animation_battery_by_ver(capacity, (void *)outBuffer.bits, dec_logo_addr, logo_addr, phical_screen, show_animationm_ver);
#endif
            surface->unlockAndPost();
        }
    }
}

切换缓冲区的主要目的是在显示动画时实现平滑的画面刷新。

在双缓冲模式下,通常会使用两块帧缓冲区,一块用于显示当前画面,另一块用于准备下一帧的画面。当当前帧显示完成时,就可以立即切换到另一块缓冲区继续显示,而不必等待下一帧数据准备完毕。这样可以避免出现画面撕裂或者闪烁的现象,提高了显示的流畅度和质量。

static unsigned int *charging_fb_addr = NULL;
static unsigned int *kernel_fb_addr = NULL;
static unsigned int use_double_addr = 0;

/*
 * Charging animation framebuffer switch buffer
 *
 */
void anim_fb_addr_switch(void)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]use_double_addr =%d \n",__FUNCTION__,__LINE__,use_double_addr);
    }
    if(use_double_addr == 0) {
        use_double_addr++;
        fb_addr = kernel_fb_addr;
    } else {
        use_double_addr = 0;
        fb_addr = charging_fb_addr;
    }
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[libshowlogo: %s %d]fb_addr =%d \n",__FUNCTION__,__LINE__, (int)fb_addr);
    }
}

fill_animation_battery_by_ver()函数

通过传入的show_animationm_ver参数选择不同的绘制样式。

VERION_OLD_ANIMATION: show 4 recatangle growing animation without battery number
VERION_NEW_ANIMATION: show wave animation with battery number
VERION_WIRELESS_CHARGING_ANIMATION: show wireless charging animation

这里show_animationm_ver = VERION_NEW_ANIMATION

vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c

/*
 * Show charging animation by version
 *
 */
void fill_animation_battery_by_ver(int capacity, void *fill_addr, void * dec_logo_addr, void * logo_addr,
                        LCM_SCREEN_T phical_screen, int version)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]version : %d\n",__FUNCTION__,__LINE__, version);
    }
    switch (version)
    {
        case VERION_OLD_ANIMATION:
            fill_animation_battery_old(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);

            break;
        case VERION_NEW_ANIMATION:
            fill_animation_battery_new(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);

            break;
        case VERION_WIRELESS_CHARGING_ANIMATION:
            fill_animation_battery_wireless_charging(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);

            break;
        default:
            fill_animation_battery_old(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);

            break;
    }
}

fill_animation_battery_new()函数

通过大量fill_animation_xxx()函数,绘制了不同的UI元素。大同小异,拿fill_animation_logo(FULL_BATTERY_INDEX, fill_addr, dec_logo_addr, logo_addr,phical_screen)举例:

index:logo的索引值。
fill_addr:填充屏幕的位置。
dec_logo_addr:解压后的logo地址。
logo_addr:原始logo地址。
phical_screen:LCM屏幕参数。

/*
 * Show new charging animation
 *
 */
void fill_animation_battery_new(int capacity, void *fill_addr, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]capacity : %d\n",__FUNCTION__,__LINE__, capacity);
    }
    //图片分配地址并初始化
    if (percent_pic_addr==NULL) {
        percent_pic_addr=(unsigned short*)malloc(((charg_anim_ui_dimen.percent_right - charg_anim_ui_dimen.percent_left)*(charg_anim_ui_dimen.percent_bottom - charg_anim_ui_dimen.percent_top)*4)*sizeof(unsigned short));
        memset(percent_pic_addr,0,(((charg_anim_ui_dimen.percent_right - charg_anim_ui_dimen.percent_left)*(charg_anim_ui_dimen.percent_bottom - charg_anim_ui_dimen.percent_top)*4)*sizeof(unsigned short)));
    }
    if (top_animation_addr==NULL) {
        top_animation_addr=(unsigned short*)malloc(((charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*(charg_anim_ui_dimen.top_anim_bottom - charg_anim_ui_dimen.top_anim_top)*4)*sizeof(unsigned short));
        memset(top_animation_addr,0,(((charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*(charg_anim_ui_dimen.top_anim_bottom - charg_anim_ui_dimen.top_anim_top)*4)*sizeof(unsigned short)));
    }
    RECT_REGION_T percent_location_rect = {charg_anim_ui_dimen.percent_left,charg_anim_ui_dimen.percent_top,charg_anim_ui_dimen.percent_right,charg_anim_ui_dimen.percent_bottom};

    if (capacity >= 100) {
        //show_logo(37); // battery 100
        fill_animation_logo(FULL_BATTERY_INDEX, fill_addr, dec_logo_addr, logo_addr,phical_screen);	//显示满电时的logo,满电logo是一个单独的图片

    } else if (capacity < 10) { //显示低电时logo,低电logo由橙色波浪的电量图片、单个电量数字和百分号组成
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]charging_low_index = %d\n",__FUNCTION__,__LINE__, charging_low_index);
        }
        charging_low_index ++ ;

        fill_animation_logo(LOW_BAT_ANIM_START_0 + charging_low_index, fill_addr, dec_logo_addr, logo_addr,phical_screen);
        fill_animation_number(NUMBER_PIC_START_0 + capacity, 1, fill_addr, logo_addr, phical_screen);
        fill_animation_dynamic(NUMBER_PIC_PERCENT, percent_location_rect, fill_addr, percent_pic_addr, logo_addr, phical_screen);

        if (charging_low_index >= 9) charging_low_index = 0;

    } else { //显示非低电时logo,非低电logo由电池背景,蓝色线条、两个电量数字和百分号组成

        unsigned int capacity_grids = 0;
        //static RECT_REGION_T battery_rect = {CAPACITY_LEFT,CAPACITY_TOP,CAPACITY_RIGHT,CAPACITY_BOTTOM};
        capacity_grids = charg_anim_ui_dimen.cap_bottom - (charg_anim_ui_dimen.cap_bottom - charg_anim_ui_dimen.cap_top) * (capacity - 10) / 90;  //电量格数
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]capacity_grids : %d,charging_animation_index = %d\n"
                     ,__FUNCTION__,__LINE__, capacity_grids,charging_animation_index);
        }

        //background
        fill_animation_logo(ANIM_V1_BACKGROUND_INDEX, fill_addr, dec_logo_addr, logo_addr,phical_screen);

        fill_animation_line(ANIM_LINE_INDEX, capacity_grids, fill_addr,  logo_addr, phical_screen);
        fill_animation_number(NUMBER_PIC_START_0 + (capacity/10), 0, fill_addr, logo_addr, phical_screen);
        fill_animation_number(NUMBER_PIC_START_0 + (capacity%10), 1, fill_addr, logo_addr, phical_screen);
        fill_animation_dynamic(NUMBER_PIC_PERCENT, percent_location_rect, fill_addr, percent_pic_addr, logo_addr, phical_screen);


         if (capacity <= 90)
         {
            RECT_REGION_T top_animation_rect = {charg_anim_ui_dimen.top_anim_left, capacity_grids - (charg_anim_ui_dimen.top_anim_bottom - charg_anim_ui_dimen.top_anim_top), charg_anim_ui_dimen.top_anim_right, capacity_grids};
            //top_animation_rect.bottom = capacity_grids;
            //top_animation_rect.top = capacity_grids - top_animation_height;
            charging_animation_index++;
            //show_animation_dynamic(15 + charging_animation_index, top_animation_rect, top_animation_addr);
            
             //播放蓝色的充电波浪
            fill_animation_dynamic(BAT_ANIM_START_0 + charging_animation_index, top_animation_rect, fill_addr,
                            top_animation_addr, logo_addr, phical_screen);

            if (charging_animation_index >= 9) charging_animation_index = 0;
         }
    }

}

fill_animation_logo()函数

从屏幕左上角零点处绘制图像。

/*
 * Fill a screen size buffer with logo content
 *
 */
void fill_animation_logo(int index, void *fill_addr, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
    LOGO_PARA_T logo_info;
    int logo_width;
    int logo_height;
    int raw_data_size;
    int logo_index = index;
    int logo_offset = -1;
    g_dec_logo_addr = dec_logo_addr;
    logo_offset = calculate_logo_offset(index, dec_logo_addr, logo_addr, phical_screen);
    if(logo_offset == -1){
        SLOGD("[calculate_logo_offset: %s %d]Resolution not supported\n",__FUNCTION__,__LINE__);
        return;
    }
    logo_index = logo_index + logo_offset;
    //检查logo索引的有效性
    if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK)
        return;

    //资源文件大小
    raw_data_size = decompress_logo((void*)logo_info.inaddr, dec_logo_addr, logo_info.logolen, phical_screen.fb_size);
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]raw_data_size = %d\n",__FUNCTION__,__LINE__, raw_data_size);
    }
    //RECT_REGION_T rect = {0, 0, phical_screen.width, phical_screen.height};
    logo_width =phical_screen.width;
    logo_height = phical_screen.height;
    if (phical_screen.rotation == 270 || phical_screen.rotation == 90) {
        logo_width = phical_screen.height;
        logo_height = phical_screen.width;
    }
    //单个像素点的大小(32位)
    if (0 == bits) {
        if (raw_data_size == logo_width*logo_height*4) {
            bits = 32;
        } else if (raw_data_size == logo_width*logo_height*2) {
            bits = 16;
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGE("[show_animation_common: %s %d]Logo data error\n",__FUNCTION__,__LINE__);
            }
            return;
        }
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
        }
    }

    RECT_REGION_T rect = {0, 0, logo_width, logo_height};

    fill_rect_with_content(fill_addr, rect, dec_logo_addr, phical_screen, bits);
}

fill_animation_number()函数

绘制电量百分数的图像。多位数会根据number_position的不同,绘制在不同的地方。

/*
 * Fill a rectangle  with number logo content
 *
 * number_position: 0~1st number, 1~2nd number
 */
void fill_animation_number(int index, unsigned int number_position, void *fill_addr,  void * logo_addr, LCM_SCREEN_T phical_screen)
{
    int logo_index = index;
    int logo_offset = -1;
    logo_offset = calculate_logo_offset(index, g_dec_logo_addr, logo_addr, phical_screen);
    if(logo_offset == -1){
        SLOGD("[calculate_logo_offset: %s %d]Resolution not supported\n",__FUNCTION__,__LINE__);
        return;
    }
    logo_index = logo_index + logo_offset;
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]index= %d, number_position = %d\n",__FUNCTION__,__LINE__, index, number_position);
    }
    //为数字图片分配内存并初始化
    if(number_pic_addr==NULL) {
        number_pic_addr= (unsigned short*)malloc(((charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*(charg_anim_ui_dimen.num_bottom - charg_anim_ui_dimen.num_top)*4)*sizeof(unsigned short));
        memset(number_pic_addr,0,(((charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*(charg_anim_ui_dimen.num_bottom - charg_anim_ui_dimen.num_top)*4)*sizeof(unsigned short)));
    }
    LOGO_PARA_T logo_info;
    int raw_data_size;
    //检查logo索引的有效性
    if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK)
        return;
    number_pic_size = (charg_anim_ui_dimen.num_right-charg_anim_ui_dimen.num_left)*(charg_anim_ui_dimen.num_bottom-charg_anim_ui_dimen.num_top)*4;
    // draw default number rect,
    raw_data_size = decompress_logo((void*)logo_info.inaddr, (void*)number_pic_addr, logo_info.logolen, number_pic_size);
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]raw_data_size = %d\n",__FUNCTION__,__LINE__, raw_data_size);
    }
    //static RECT_REGION_T number_location_rect = {NUMBER_LEFT,NUMBER_TOP,NUMBER_RIGHT,NUMBER_BOTTOM};

    //数字可能有两个,所以要通过number_position控制个位和十位数字的位置
    RECT_REGION_T battery_number_rect = {charg_anim_ui_dimen.num_left + (charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*number_position,
                            charg_anim_ui_dimen.num_top,
                            charg_anim_ui_dimen.num_right + (charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*number_position,
                            charg_anim_ui_dimen.num_bottom};
    if (0 == bits) {
        if (raw_data_size == (charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*(charg_anim_ui_dimen.num_bottom - charg_anim_ui_dimen.num_top)*4) {
            bits = 32;
        } else if (raw_data_size == (charg_anim_ui_dimen.num_right - charg_anim_ui_dimen.num_left)*(charg_anim_ui_dimen.num_bottom - charg_anim_ui_dimen.num_top)*2) {
            bits = 16;
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGE("[show_animation_common: %s %d]Logo data error\n",__FUNCTION__,__LINE__);
            }
            return;
        }
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
        }
    }
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
    }
    fill_rect_with_content(fill_addr, battery_number_rect, number_pic_addr,phical_screen, bits);
}

fill_animation_dynamic()函数

在特定位置绘制特定图像。

/*
 * Fill a rectangle with logo content
 *
 */
void fill_animation_dynamic(int index, RECT_REGION_T rect, void *fill_addr, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
    LOGO_PARA_T logo_info;
    int raw_data_size;
    int logo_index = index;
    int logo_offset = -1;
    g_dec_logo_addr = dec_logo_addr;
    logo_offset = calculate_logo_offset(index, dec_logo_addr, logo_addr, phical_screen);
    if(logo_offset == -1){
        SLOGD("[calculate_logo_offset: %s %d]Resolution not supported\n",__FUNCTION__,__LINE__);
        return;
    }
    logo_index = logo_index + logo_offset;
    //检查logo索引的有效性
    if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK)
        return;

    raw_data_size = decompress_logo((void*)logo_info.inaddr, (void*)dec_logo_addr, logo_info.logolen, (rect.right-rect.left)*(rect.bottom-rect.top)*4);
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]raw_data_size = %d\n",__FUNCTION__,__LINE__, raw_data_size);
    }
    if (0 == bits) {
        if (raw_data_size == (rect.right-rect.left)*(rect.bottom-rect.top)*4) {
            bits = 32;
        } else if (raw_data_size == (rect.right-rect.left)*(rect.bottom-rect.top)*2) {
            bits = 16;
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGE("[show_animation_common: %s %d]Logo data error\n",__FUNCTION__,__LINE__);
            }
            return;
        }
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
        }
    }
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
    }
    fill_rect_with_content(fill_addr, rect, dec_logo_addr, phical_screen, bits);
}

fill_animation_line()函数

/*
 * Fill a line with special color
 *
 */
void fill_animation_line(int index, unsigned int capacity_grids, void *fill_addr,  void * logo_addr, LCM_SCREEN_T phical_screen)
{

    int logo_index = index;
    int logo_offset = -1;
    logo_offset = calculate_logo_offset(index, g_dec_logo_addr, logo_addr, phical_screen);
    if(logo_offset == -1){
        SLOGD("[calculate_logo_offset: %s %d]Resolution not supported\n",__FUNCTION__,__LINE__);
        return;
    }
    logo_index = logo_index + logo_offset;

    LOGO_PARA_T logo_info;
    int raw_data_size;
  
    if(line_pic_addr==NULL) {
       line_pic_addr=(unsigned short*)malloc(((charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*4)*sizeof(unsigned short));
       memset(line_pic_addr,0,(((charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*4)*sizeof(unsigned short)));
    }
    if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK)
        return;
    line_pic_size= (charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*4;
    raw_data_size = decompress_logo((void*)logo_info.inaddr, (void*)line_pic_addr, logo_info.logolen, line_pic_size);
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_animation_common: %s %d]raw_data_size = %d\n",__FUNCTION__,__LINE__, raw_data_size);
    }
    if (0 == bits) {
        if (raw_data_size == (charg_anim_ui_dimen.top_anim_right - charg_anim_ui_dimen.top_anim_left)*4) {
            bits = 32;
        } else if (raw_data_size == (charg_anim_ui_dimen.top_anim_right  - charg_anim_ui_dimen.top_anim_left)*2) {
            bits = 16;
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGE("[show_animation_common: %s %d]Logo data error\n",__FUNCTION__,__LINE__);
            }
            return;
        }
        if (MTK_LOG_ENABLE == 1) {
            SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
        }
    }
    RECT_REGION_T rect = {charg_anim_ui_dimen.cap_left, charg_anim_ui_dimen.cap_top, charg_anim_ui_dimen.cap_right, charg_anim_ui_dimen.cap_bottom};
    int i = capacity_grids;
    for(; i < charg_anim_ui_dimen.cap_bottom; i++)
    {
        rect.top = i;
        rect.bottom = i+1;
        fill_rect_with_content(fill_addr, rect, line_pic_addr, phical_screen, bits);
    }
}

fill_rect_with_content()函数

指定的矩形区域内填充具有logo内容的像素数据。

/*
 * Draw a rectangle region  with logo content
 *
 *
 *
 */

void fill_rect_with_content(void *fill_addr, RECT_REGION_T rect, void *src_addr, LCM_SCREEN_T phical_screen, unsigned int bits)
{
    if (MTK_LOG_ENABLE == 1) {
        SLOGD("[show_logo_common: %s %d]\n",__FUNCTION__,__LINE__);
    }
    if (check_rect_valid(rect) != CHECK_RECT_OK)
        return;
    if (bits == 32) {
        if (phical_screen.fill_dst_bits == 16) {
            fill_rect_with_content_by_16bit_argb8888((unsigned short *)fill_addr, rect, (unsigned int *)src_addr, phical_screen);
        } else if (phical_screen.fill_dst_bits == 32){
            fill_rect_with_content_by_32bit_argb8888((unsigned int *)fill_addr, rect, (unsigned int *)src_addr, phical_screen, bits);
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGD("[show_logo_common %s %d]unsupported phical_screen.fill_dst_bits =%d\n",__FUNCTION__,__LINE__, phical_screen.fill_dst_bits );
            }
        }
    } else {
        if (phical_screen.fill_dst_bits == 16) {
            fill_rect_with_content_by_16bit_rgb565((unsigned short *)fill_addr, rect, (unsigned short *)src_addr, phical_screen);
        } else if (phical_screen.fill_dst_bits == 32){
            fill_rect_with_content_by_32bit_rgb565((unsigned int *)fill_addr, rect, (unsigned short *)src_addr, phical_screen, bits);
        } else {
            if (MTK_LOG_ENABLE == 1) {
                SLOGD("[show_logo_common %s %d]unsupported phical_screen.fill_dst_bits =%d\n",__FUNCTION__,__LINE__, phical_screen.fill_dst_bits );
            }
        }
    }
}

fill_rect_with_content_by_32bit_argb8888()函数

在一个指定的矩形区域内填充具有logo内容的32位色彩的像素数据。

/*
 * Draw a rectangle region (32 bits perpixel) with logo content
 *
 *
 *
 */
void fill_rect_with_content_by_32bit_argb8888(unsigned int *fill_addr, RECT_REGION_T rect, unsigned int *src_addr, LCM_SCREEN_T phical_screen, unsigned int bits)
{
	LOG_ANIM("[show_logo_common: %s %d]\n",__FUNCTION__,__LINE__);

    int virtual_width = phical_screen.needAllign == 0? phical_screen.width:phical_screen.allignWidth;
    int virtual_height = phical_screen.height;

    int i = 0;
    int j = 0;

    unsigned int * dst_addr = fill_addr;
    unsigned int * color_addr = src_addr;

    for(i = rect.top; i < rect.bottom; i++)
    {
        for(j = rect.left; j < rect.right; j++)
        {
            color_addr = (unsigned int *)src_addr;
            src_addr++;
            switch (phical_screen.rotation)
            {
                case 90:
                    dst_addr = fill_addr + (virtual_width * j  + virtual_width - i - 1);
                    break;
                case 270:
                    dst_addr = fill_addr + ((virtual_width * (virtual_height - j - 1)+ i));
                    break;
                case 180:
                    // adjust fill in address
                    dst_addr = fill_addr + virtual_width * (virtual_height - i)- j-1-(virtual_width-phical_screen.width);
                    break;
                default:
                    dst_addr = fill_addr + virtual_width * i + j;
            }
            fill_point_buffer(dst_addr, *color_addr, phical_screen, bits);
            if((i == rect.top && j == rect.left) || (i == rect.bottom - 1 && j == rect.left) ||
               (i == rect.top && j == rect.right - 1) || (i == rect.bottom - 1 && j == rect.right - 1)){
                LOG_ANIM("[show_logo_common]dst_addr= 0x%08x, color_addr= 0x%08x, i= %d, j=%d\n", *dst_addr, *color_addr, i , j);
            }
        }
    }
}

fill_point_buffer()函数

填充屏幕单个像素点。

/*
 * Fill one point address with  source color and color pixel bits
 *
 * @parameter
 *
 */
void fill_point_buffer(unsigned int *fill_addr, unsigned int src_color, LCM_SCREEN_T phical_screen, unsigned int bits)
{
    if (32 == phical_screen.bits_per_pixel) {
        if (32 == bits) {
            if(16 == phical_screen.blue_offset) {
                *fill_addr = ARGB8888_TO_ABGR8888(src_color);
            } else {
                *fill_addr = src_color;
            }
        } else {
            if(16 == phical_screen.blue_offset) {
                *fill_addr = RGB565_TO_ARGB8888(src_color);
            } else {
                *fill_addr = RGB565_TO_ABGR8888(src_color);
            }
        }
    } else {
        LOG_ANIM("[show_logo_common %s %d]not support bits_per_pixel = %d \n",__FUNCTION__,__LINE__,(int)phical_screen.bits_per_pixel);
    }
}

客户需求定制

关机充电时,在电量小于等于5%时,显示"30分钟充电后打开电源"(韩文)

  1. 预制提示语资源

制作一张带客户需求字样的bmp图片,并以“wxganl”(视项目而定)开头命名,放入对应的目录中。

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\wxganl\

请添加图片描述

将处理后生成的raw文件添加进RESOURCE_OBJ_LIST列表(建议放在列表末尾)。

diff --git a/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk b/vendor/mediatek/proprietary/bootable/bo
otloader/lk/dev/logo/rules.mk
index ab8bb064524..837e8268b27 100644
--- a/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk
+++ b/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk
@@ -95,7 +95,8 @@ RESOURCE_OBJ_LIST +=   \
             $(BOOT_LOGO_DIR)/$(1)/$(1)_kernel.raw \
             $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery01.raw \
             $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery02.raw \
-            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery_remind.raw
+            $(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery_remind.raw \
+            $(BOOT_LOGO_DIR)/$(1)/$(1)_bat_custom.raw
 endif
 endif
  1. 定义自定义图片索引值

根据raw文件在RESOURCE_OBJ_LIST列表中的位置,定义对应的索引值。

diff --git a/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h b/vendor/mediatek/proprietary/external/libshow
logo/cust_display.h
index bf26861ac45..8f8b8830a9a 100644
--- a/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h
+++ b/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h
@@ -140,6 +140,9 @@
 #define LOGOS_COUNT_FAST_CHARGING          18
 #define LOGOS_COUNT_WIRELESS               29

-
+//added by menghui.huang    start
+// custom picture index
+#define CUSTOM_PIC_INDEX        42
+//added by menghui.huang    end

  1. 描述绘制位置

屏幕坐标系是以横屏状态下(视项目而定)左上角为零点,右侧为x轴正方向,下侧为y轴正方向。

请添加图片描述

利用Windows自带的画图工具定位图片位置。本例中,(440, 640)是一个较好的位置。

请添加图片描述

查看图片属性确定下边界和右边界。

下边界 = 起始位置纵坐标 + 图片本身高度;本例中 下边界 = 640 + 39 = 679
右边界 = 起始位置横坐标 + 图片本身宽度; 本例中 右边界 = 440 + 404 = 844

请添加图片描述

在代码中定义对应的位置信息。

diff --git a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.h b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.h
index c9e2ac924bb..e09e514b730 100755
--- a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.h
+++ b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.h
@@ -69,6 +69,14 @@ typedef struct {
 // version_0 animation
 #define ANIM_V0_REGIONS  4
 #define ANIM_V0_SPACE_AFTER_REGION  4
+
+//added by menghui.huang     start
+#define CUSTOM_PIC_LEFT 440
+#define CUSTOM_PIC_TOP 640
+#define CUSTOM_PIC_RIGHT 844
+#define CUSTOM_PIC_BOTTOM 679
+//added by menghui.huang     end
+

定义矩形参数

// define the rectangle parameters
typedef struct {
     int left, top, right, bottom;
} RECT_REGION_T;
diff --git a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_
common.c
index a57a5cafede..9c0ad346569 100755
--- a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c
+++ b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c

RECT_REGION_T percent_location_rect = {charg_anim_ui_dimen.percent_left,charg_anim_ui_dimen.percent_top,charg_anim_ui_dimen.percent_right,charg_anim_ui_dimen.percent_bottom};
+    RECT_REGION_T custom_location_rect = {CUSTOM_PIC_LEFT, CUSTOM_PIC_TOP, CUSTOM_PIC_RIGHT, CUSTOM_PIC_BOTTOM};
  1. 为自定义图片分配内存并初始化
diff --git a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c
index a57a5cafede..9c0ad346569 100755
--- a/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c
+++ b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c
@@ -103,6 +103,7 @@ int getValue(char* key, char* defValue);
+++ b/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c
@@ -103,6 +103,7 @@ int getValue(char* key, char* defValue);
 static unsigned short  *number_pic_addr;
 static unsigned short  *line_pic_addr;
 static unsigned short  *percent_pic_addr;
+static unsigned short  *custom_pic_addr;
 static unsigned short  *top_animation_addr;

 static  int number_pic_size; //size
@@ -1141,11 +1142,18 @@ void fill_animation_battery_new(int capacity, void *fill_addr, void * dec_logo_a
         percent_pic_addr=(unsigned short*)malloc(((charg_anim_ui_dimen.percent_right - charg_anim_ui_dimen.percent_left)*(charg_anim_ui_dimen.percent_bottom - charg_anim_ui_dimen
.percent_top)*4)*sizeof(unsigned short));
         memset(percent_pic_addr,0,(((charg_anim_ui_dimen.percent_right - charg_anim_ui_dimen.percent_left)*(charg_anim_ui_dimen.percent_bottom - charg_anim_ui_dimen.percent_top)*
4)*sizeof(unsigned short)));
     }
+    added by menghui.huang    start
+    if (custom_pic_addr==NULL) {
+        custom_pic_addr=(unsigned short*)malloc(((CUSTOM_PIC_RIGHT - CUSTOM_PIC_LEFT)*(CUSTOM_PIC_BOTTOM - CUSTOM_PIC_TOP)*4)*sizeof(unsigned short));
+        memset(custom_pic_addr,0,(((CUSTOM_PIC_RIGHT - CUSTOM_PIC_LEFT)*(CUSTOM_PIC_BOTTOM - CUSTOM_PIC_TOP)*4)*sizeof(unsigned short)));
+    }
+    //added by menghui.huang    end
  1. 在电量<=5%时,为指定内存区域填充图像数据
@@ -1160,6 +1168,12 @@ void fill_animation_battery_new(int capacity, void *fill_addr, void * dec_logo_a
         fill_animation_logo(LOW_BAT_ANIM_START_0 + charging_low_index, fill_addr, dec_logo_addr, logo_addr,phical_screen);
         fill_animation_number(NUMBER_PIC_START_0 + capacity, 1, fill_addr, logo_addr, phical_screen);
         fill_animation_dynamic(NUMBER_PIC_PERCENT, percent_location_rect, fill_addr, percent_pic_addr, logo_addr, phical_screen);
+        //added by menghui.huang    start
+        if (capacity <= 5)
+        {
+            fill_animation_dynamic(CUSTOM_PIC_INDEX, custom_location_rect, fill_addr, custom_pic_addr, logo_addr, phical_screen);
+        }
+        //added by menghui.huang    end

  1. 效果

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/722943.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶仿真:Carsim转向传动比设置

文章目录 一、转向传动比概念二、设置转向传动比1、C factor概念2、Steer Kinematics概念3、传动比计算公式 三、转向传动比验证 一、转向传动比概念 转向传动比&#xff08;Steering Ratio&#xff09;表示方向盘转动角度与车轮转动角度之间的关系。公式如下&#xff1a; 转向…

乘法与位运算

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 题目描述&#xff1a; 进行一个运算单元的电路设计&#xff0c;A[7:0]*11111011&#xff0c;尽量用最少的资源实现&#xff0c;写出对应的 RTL 代码。 信号示意&#xff1a; A信号输入 B 信号…

[自动驾驶 SoC]-4 特斯拉FSD

FSD, 参考资料来源FSD Chip - Tesla - WikiChip 另外可参考笔者之前分享文章&#xff1a;[自动驾驶技术]-6 Tesla自动驾驶方案之硬件&#xff08;AI Day 2021&#xff09;&#xff0c;​​​​​​​[自动驾驶技术]-8 Tesla自动驾驶方案之硬件&#xff08;AI Day 2022&#xf…

DGit的使用

将Remix连接到远程Git仓库 1.指定克隆的分支和深度 2.清理&#xff0c;如果您不在工作区上工作&#xff0c;请将其删除或推送至 GitHub 或 IPFS 以确保安全。 为了进行推送和拉取&#xff0c;你需要一个 PAT — 个人访问令牌 当使用 dGIT 插件在 GitHub 上推送、拉取、访问私…

Studying-代码随想录训练营day13| 二叉树理论基础、二叉树递归遍历、二叉树迭代遍历、二叉树层序遍历

第十三天&#xff0c;&#x1f4aa;(ง •_•)ง&#x1f4aa;&#xff0c;编程语言&#xff1a;C 目录 二叉树理论基础 二叉树的种类&#xff1a; 二叉树的存储方式 二叉树的遍历方式 二叉树的定义&#xff1a; 二叉树递归遍历 二叉树的迭代遍历 二叉树的层次遍历 …

数据库新技术【分布式数据库】

文章目录 第一章 概述1.1 基本概念1.1.1 分布式数据库1.1.2 数据管理的透明性1.1.3 可靠性1.1.4 分布式数据库与集中式数据库的区别 1.2 体系结构1.3 全局目录1.4 关系代数1.4.1 基操1.4.2 关系表达式1.4.3 查询树 第二章 分布式数据库的设计2.1 设计策略2.2 分布设计的目标2.3…

深度学习入门5——为什么神经网络可以学习?

在理解神经网络的可学习性之前&#xff0c;需要先从数学中的导数、数值微分、偏导数、梯度等概念入手&#xff0c;从而理解为什么神经网络具备学习能力。 1.数值微分的定义 先从导数出发理解什么是梯度。某一点的导数直观理解就是在该点的切线的斜率。在数学中导数表示某个瞬…

Spring的事务步骤

一、事务处理方案&#xff1a; Spring框架中提供的事务处理方案&#xff1a;一共有两种&#xff1a; 1.适合中小项目使用的&#xff0c; 注解方案&#xff1a; 注解的方式做事务用起来简单&#xff0c;灵活&#xff0c;方便&#xff0c;中小型项目中用它比较方便&#xff0c…

白酒:酒文化的教育价值与实践

酒文化作为中国传统文化的重要组成部分&#xff0c;具有丰富的教育价值。云仓酒庄的豪迈白酒作为酒文化的品牌之一&#xff0c;在传承与发展中不断挖掘和发挥酒文化的教育价值。 首先&#xff0c;豪迈白酒有责任传承丰富的历史文化知识。从酒的起源、酿造技艺、酒器文化到酒礼酒…

Github上传大于100M的文件(ubuntu教程)

安装Git-lfs Git Large File Storage (LFS) 使用 Git 内部的文本指针替换音频样本、视频、数据集和图形等大文件&#xff0c;同时将文件内容存储在 GitHub.com 或 GitHub Enterprise 等远程服务器上。官网下载&#xff1a;https://git-lfs.github.com/ ./install.sh上传 比如…

教你如何安装 IntelliJ IDEA

安装 IntelliJ IDEA 的步骤通常如下&#xff0c;这里提供的是基于 Windows 系统的安装指南。 下载 IntelliJ IDEA 1. 访问 JetBrains 官方网站&#xff1a;[https://www.jetbrains.com/idea/download/](Download IntelliJ IDEA – The Leading Java and Kotlin IDE) 2. 选择适…

一文带你入门【论文排版】利器·LaTeX |Macos

小罗碎碎念 我在刚开始写公众号的时候&#xff0c;写过一期推文&#xff0c;详细的讲解过如何使用LaTeX快速的进行论文排版。不过当时用的是windows的系统&#xff0c;这一次把Mac端的教程补上。 windows系统教程 https://zhuanlan.zhihu.com/p/677481269 LaTeX是一种流行的排…

【UIDynamic-动力学-UICollisionBehavior-action Objective-C语言】

一、我们说,这个碰撞行为啊,collision,它里边还有一个属性,叫做action,它能够干什么,它能够实时的去监听, 1.实时的去监听,我们当前的这个view的一个frame的变化, 它会调用action的方法,实际上,action方法,它是一个block,然后呢,view的frame变化的时候,它会一直…

Keil生成bin文件

keil软件默认是只生成hex文件虽然也可以下载但是有时候要用到bin文件 只需要加入以下代码在keil软件中即可 fromelf.exe --bin -o “$LL.bin” “#L” 然后编译 输出信息&#xff0c;可以看到已经生成了bin文件

Nacos从入门到实战

一、Nacos介绍 1.什么是Nacos 官方&#xff1a;一个更易于构建云原生应用的动态服务发现&#xff08;Nacos Discovery&#xff09;、服务配置&#xff08;Nacos Config&#xff09;和服务管理平台 集 注册中心配置中心服务管理 平台 注册中心&#xff1a;把所有的服务注册进去…

第6章 设备驱动程序(3)

目录 6.5 块设备操作 6.5.1 块设备的表示 6.5.2 数据结构 6.5.3 向系统添加磁盘和分区 6.5.4 打开块设备文件 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 6.5 块设备操作 特点&#xff1a; 随机访问任意位置。 固定块大小的传输。 块设备在内…

MySQL进阶——索引【核心】

目录 1索引概述 2索引结构 2.1 B-Tree&#xff08;多路平衡查找树&#xff09; 2.2 BTree 2.3 hash 3索引分类 3.1MySQL中分4类 3.2 InnoDB存储引擎分两类&#xff08;SQL优化中重要&#xff09; 4索引语法 4.1创建和查看索引 4.2删除索引 5 SQL性能分析 5.1 查看执…

Ubuntu安装docker 详细教程

Ubuntu安装docker&#xff0c;以及docker compose踩了一步一步的坑&#xff0c;真的特别抓马&#xff01;&#xff01;&#xff01; 因此分享我的安装教程和踩坑&#xff0c;希望给大家一些帮助吧 安装详细教程 卸载docker停止 docker 运行使用以下命令来卸载 Docker 软件包及其…

国产数据库中读写分离实现机制

在数据库高可用架构下会存在1主多备的部署&#xff0c;备节点可以根据业务场景分发一部分流量以充分利用资源&#xff0c;并减轻主库的压力&#xff0c;因此在数据库的功能上需要读写分离来实现。 充分利用备节点的资源&#xff0c;提升业务的吞吐量&#xff1b;防止运维等非业…

助力低空经济-eVTOL/无人机ADS-B航管应答机选型指南

一、低空经济概述 “低空经济”在今年全国两会首次写入政府工作报告。近日&#xff0c;工业和信息化部、科学技术部、财政部、中国民用航空局印发《通用航空装备创新应用实施方案&#xff08;2024—2030年&#xff09;》&#xff0c;提出到2030年&#xff0c;推动低空经济形成…