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

news2025/1/21 21:55:08

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

基于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. 效果

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

北漂新媒体从业者的一天

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 本文纯属虚构 小李通过努力考上了一所北京的大学&#xff0c;毕业后就留在了北京&#xff0c;做新媒体运营&#xff0c;在天通苑租了一个单间&#xff0c;月租2500&#xff0c;业余时间做自媒体&#xff0c;也算是…

vue element-ui 车牌号选择组件

实现效果 carnumber.vue <template><div class"car_no_popover"><div class"row_div"><div class"every_div" v-for"item in area"><button click"selectCarNo(item)">{{ item }}</butto…

如何编辑扫描的 PDF 文档

无论您从事哪个行业&#xff08;医疗保健、房地产、现场服务管理或金融服务&#xff09;&#xff0c;您都很有可能使用在线表格和调查来培训员工、收集客户反馈、授权付款和注册活动参与者。使用合适的软件&#xff0c;这些表格很容易创建、编辑和填写。此外&#xff0c;您还可…

【文献阅读】Partially Adaptive Array Techniques

Abstract 文章研究了在多窄带干扰环境下&#xff0c;辅助阵元的选择&#xff0c;为部分自适应天线阵&#xff0c;以达到性能优化的目的。推导了双干扰问题的显式解。这个案例足以说明多个干扰的相互作用&#xff0c;同时也为更复杂的问题提供了一定程度的理解。本文还提出并讨…

如何为自己的项目生成changelog

背景 在github上看到人家的更新日志感觉很cool&#xff0c;怎么能给自己项目来一套呢 环境信息 tdstdsdeMacBook-Pro demo-doc % node -v v14.18.1 tdstdsdeMacBook-Pro demo-doc % npm -v 6.14.15硬件信息 型号名称&#xff1a;MacBook Pro版本&#xff1a; 12.6.9芯片&…

nginx反向代理动静分离和负载均衡

一.nginx 反向代理简要介绍 1.什么是反向代理 反向代理是一种服务器&#xff0c;在这种设置中&#xff0c;代理服务器接收客户端的请求&#xff0c;并将这些请求转发给一个或多个后端服务器&#xff08;例如应用服务器、数据库服务器等&#xff09;。然后&#xff0c;后端服务…

Transformer预测 | 基于Transformer+LSTM股票价格预测时间序列预测(Pytorch)

效果一览 基本介绍 股票行情是引导交易市场变化的一大重要因素,若能够掌握股票行情的走势,则对于个人和企业的投资都有巨大的帮助。然而,股票走势会受到多方因素的影响,因此难以从影响因素入手定量地进行衡量。但如今,借助于机器学习,可以通过搭建网络,学习一定规模的股…

Unity URP下通过相机让部分Render不受后处理渲染

我们有时候不想某些对象受到后处理影响&#xff0c;找到了这样一个决绝办法&#xff0c;通过增加一个Overlay相机只照射这个模型来实现&#xff0c;下面看看如何实现。 第一步 首先我们拖一个测试场景&#xff0c;有如下一些元素 一个盒子&#xff0c;以后后处理&#xff0c…

海思SS928/SD3403开发笔记1——使用串口调试开发板

该板子使用串口可以调试&#xff0c;下面是win11 调试 该板子步骤 1、给板子接入鼠标、键盘、usb转串口 2、下载SecureCRT&#xff0c;并科学使用 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/11dIkZVstvHQUhE8uS1YO0Q 提取码&#xff1a;vinv 3、安装c…

计算机毕业设计Python+Flask弹幕情感分析 B站视频数据可视化 B站爬虫 机器学习 深度学习 人工智能 NLP文本分类 数据可视化 大数据毕业设计

首先安装需要的python库&#xff0c; 安装完之后利用navicat导入数据库文件bili100.sql到mysql中&#xff0c; 再在pycharm编译器中连接mysql数据库&#xff0c;并在设置文件中将密码修改成你的数据库密码。最后运行app.py&#xff0c;打开链接&#xff0c;即可运行。 B站爬虫数…

Springboot整合Kafka消息队列服务实例

一、Kafka相关概念 1、关于Kafka的描述 Kafka是由Apache开源&#xff0c;具有分布式、分区的、多副本的、多订阅者&#xff0c;基于Zookeeper协调的分布式处理平台&#xff0c;由Scala和Java语言编写。通常用来搜集用户在应用服务中产生的动作日志数据&#xff0c;并高速的处…

创建Docker容器与外部机通信(独立IP的方式)

需求&#xff1a;希望外部可以直接通过不同IP地址访问宿主机上的Docker容器&#xff0c;而不需要端口映射&#xff08;同一个IP不同的端口与外部通讯&#xff09;&#xff0c;这通常涉及到在宿主机的网络层面进行更高级的配置&#xff0c;比如使用IP伪装&#xff08;IP masquer…

前端网站(二)-- 菜单页面【附源码直接可用】

菜单页面 开篇&#xff08;请大家看完&#xff09;&#xff1a;此网站写给挚爱&#xff0c;后续页面还会慢慢更新&#xff0c;大家敬请期待~ ~ ~ 轻舟所编写这个前端框架的设计初衷&#xff0c;纯粹是为了哄对象开心。除此之外&#xff0c;并无其它任何用途或目的。 此前端框…

《系统架构设计师教程(第2版)》第11章-未来信息综合技术-04-边缘计算

文章目录 1. 概述1.1 简介1.2 三类落地形态1.2.1 云边缘1.2.2 边缘云1.2.3 云化网关 2. 边缘计算的特点2.1 联接性2.2 数据第一入口2.3 约束性2.4 分布性 3. 边云协同3.1 概述3.2 六种协同3.2.1 资源协同3.2.2 数据协同3.2.3 智能协同3.2.4 应用管理协同3.2.5 业务管理协同3.2.…

STM32单片机USART串口详解

文章目录 1. 通信接口概述 2. 串口通信 3. 硬件电路 4. 电平标准 5. 串口参数及时序 5.1 数据帧的组成 5.2 起始位 5.3 数据位 5.4 校验位 5.5 停止位 5.6 波特率 5.7 数据帧传输过程示例 6. 串口时序 7. USART概述 8. USART框图 9. USART基本结构 10. 数据帧…

Java | Leetcode Java题解之第146题LRU缓存

题目&#xff1a; 题解&#xff1a; public class LRUCache {class DLinkedNode {int key;int value;DLinkedNode prev;DLinkedNode next;public DLinkedNode() {}public DLinkedNode(int _key, int _value) {key _key; value _value;}}private Map<Integer, DLinkedNode…

UE4_材质_雨滴涟漪效果ripple effect_ben教程

学习笔记&#xff0c;不喜勿喷&#xff01;侵权立删&#xff0c;祝愿生活越来越好&#xff01; 雨水落下时会产生这些非常漂亮的同心环波纹&#xff0c;我们要做的第一件事是创建一个单个的圆环遮罩动画&#xff0c;我们希望环在开始的时候在中心很小&#xff0c;然后放大&…

45岁TVB女星惊爆与大15岁老公离婚

45岁的姚嘉妮今日被传媒爆出与结婚18年老公林祖辉离婚&#xff0c;她接受其他传媒访问时&#xff0c;指两人分开不涉及第三者&#xff0c;而一对子女亦会共同抚养&#xff0c;而更令人惊讶的是&#xff0c;两人已经离婚多年&#xff0c;女方形容大家现在关系为家人。 不过9年前…

MBR40100CT-ASEMI无人机专用MBR40100CT

编辑&#xff1a;ll MBR40100CT-ASEMI无人机专用MBR40100CT 型号&#xff1a;MBR40100CT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;40A 最大循环峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;100V…

深入Node.js:实现网易云音乐数据自动化抓取

随着互联网技术的飞速发展&#xff0c;数据已成为企业和个人获取信息、洞察市场趋势的重要资源。音频数据&#xff0c;尤其是来自流行音乐平台如网易云音乐的数据&#xff0c;因其丰富的用户交互和内容多样性&#xff0c;成为研究用户行为和市场动态的宝贵资料。本文将深入探讨…