现在的位置: 首页 > 综合 > 正文

android关机充电流程、充电画面显示

2018年08月25日 ⁄ 综合 ⁄ 共 16742字 ⁄ 字号 评论关闭

关键词:android
电池关机充电
androidboot.mode charger 关机充电 充电画面显示
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0

平台:S5PV310(samsungexynos 4210)

电池的基本原理;

android关机充电流程、充电画面显示;

Android开机充电流程,电池电量、低电信息是怎么处理的;

上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下android关机充电是怎么、充电画面显示是怎么实现的,这个在工作中也比较有用,我们开始做这一块的时候也走了不少的弯路。我记得我们做adnroid2.3的时候,关机状态和充电logo显示是在uboot中做的。应该是有两种做法,回头我再看下uboot中做画面显示那一块是怎么做的,这一节我们重点说系统中的充电logo显示。

一、android正常开机流程、关机充电流程

在写这篇文章之前我们先看两个流程:正常开机流程,关机充电系统启动流程

1、正常开机流程,按开机键。

可大致分成三部分

(1)、OS_level:UBOOT、kenrel、init这三步完成系统启动;

(2)、Android_level:这部分完成android部的初始化;

(3)、Home Screen:这部分就是我们看到的launcher部分。

2、关机充电系统启动流程

       与前面相比,这个流程只走到init这一部分,就没有往后走了,这部分我们会在后面的代码中分析。

二、关机充电逻辑硬件逻辑

1、插入DC,charger IC从硬件上唤醒系统,相当于长按开机键开机。

下面这部分是charger IC连接系统的控制部分。

三、软件逻辑。

DC插入,其实相当于关机状态下“按开机键”开机。第一步要走UBOOT、kernel 、android init这一流程。

1、UBOOT

       UBOOT启动代码我们不在这里详细分析,这里我们只要注意二个问题:

a:如何判断是DC插入;

b:设定setenv("bootargs", "androidboot.mode=charger"),androidboot.mode这个参数相当重要,这个参数决定系统是正常启动、还是关机充电状态。

Uboot/board/samsung/smdk4212/smkd4212.c

  1. int
    board_late_init (
    void

  2.    

    int
    keystate = 0; 
  3.     printf("check start
    mode\n"
    ); 
  4.  

    if
    ((*(int
    *)0x10020800==0x19721212) || (*(
    int
    *)0x10020804==0x19721212) 
  5. || (*(int
    *)0x10020808==0x19721212))
    //(1)、检查是否有DC插入; 

  6.     setenv ("bootargs",
    "");//(2)、没有DC插入; 
  7.   }

    else
      {//DC插入 
  8.        

    int
    tmp=*(int
    *)0x11000c08; 
  9.     *(int
    *)0x10020800=*(
    int
    *)0x10020804=0x19721212; 
  10.     *(int
    *)0x11000c08=(tmp&(~0xc000))|0xc000; 
  11.     udelay(10000); 
  12.    

    if
    ((*(int
    *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) { 
  13.         setenv ("bootargs",
    "androidboot.mode=charger");//(3)、设定bootargs为charger状态 
  14.         printf("charger
    mode\n"
    ); 
  15.     }

    else

  16.         setenv ("bootargs",
    ""); 
  17.     } 
  18.     *(int
    *)0x11000c08=tmp; 
  19.   } 
  20. #ifdef CONFIG_CPU_EXYNOS4X12 
  21.    

    int
    charge_status=CheckBatteryLow();//(4)、检查电池电量; 
  22.     keystate=board_key_check();//(5)、检查按键状态; 
  23.    

    // fuse bootloader
     
  24.    

    if
    (second_boot_info != 0) { 
  25.         boot_symbol=1; 
  26.         INF_REG2_REG =0x8; 
  27.         run_command(CONFIG_BOOTCMD_FUSE_BOOTLOADER, NULL); 
  28.     } 
  29.    

    if
    ((INF_REG4_REG == 0xd)) { 
  30.        

    // reboot default
     
  31.        

    char
    buf[10]; 
  32.         sprintf(buf,

    "%d"
    , CONFIG_BOOTDELAY); 
  33.         setenv ("bootdelay",
    buf); 
  34.         setenv ("reserved",
    NULL); 
  35.         saveenv(); 
  36.     }

    else

    if((INF_REG4_REG
    == 0xe) || keystate == (0x1 | 0x2)) {
    //(6)、按键进入fastboot模式; 
  37.        

    // reboot bootloader
     
  38.         boot_symbol=1; 
  39.         INF_REG2_REG =0x8; 
  40.         printf("BOOTLOADER
    - FASTBOOT\n"
    ); 
  41.         setenv ("reserved",
    "fastboot"); 
  42.         setenv ("bootdelay",
    "0"); 
  43.     }

    else

    if((INF_REG4_REG
    == 0xf) || keystate == (0x1 | 0x2 | 0x4)) {
    //(7)、按键进入recovery模式; 
  44.        

    // reboot recovery
     
  45.         printf("BOOTLOADER
    - RECOVERY\n"
    ); 
  46.         boot_symbol=1; 
  47.         INF_REG2_REG =0x8; 
  48.         setenv ("reserved",
    CONFIG_BOOTCMD_RECOVERY); 
  49.         setenv ("bootdelay",
    "0"); 
  50.     }

    else
     
  51.    

    if
    (keystate == (0x1 | 0x4) || second_boot_info != 0 || partition_check()) {//(8)、按键进入卡升级模式; 
  52.        

    // 2nd boot
     
  53.         printf("BOOTLOADER
    - 2ND BOOT DEVICE\n"
    ); 
  54.         boot_symbol=1; 
  55.         INF_REG2_REG =0x8; 
  56.         setenv ("bootcmd",
    CONFIG_BOOTCOMMAND); 
  57.         setenv ("reserved",
    CONFIG_BOOTCMD_FUSE_RELEASE); 
  58.         setenv ("bootdelay",
    "0"); 
  59.     }

    else
    {//(9)、正常启动; 
  60.        

    // normal case
     
  61.        

    char
    buf[10]; 
  62.         sprintf(buf,

    "%d"
    , CONFIG_BOOTDELAY); 
  63.         setenv ("bootdelay",
    buf); 
  64.     } 
  65.     INF_REG4_REG = 0; 
  66.    

    return
    0; 

(1)、检查是否有DC插入;

  1. if
    ((*(
    int
    *)0x10020800==0x19721212) || (*(
    int
    *)0x10020804==0x19721212) 
  2. (*(int
    *)0x10020808==0x19721212))  

这部分检查寄存器的值。

(2)、没有DC插入;

(3)、设定bootargs为charger状态

  1. if
    ((*(
    int
    *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) { 
  2.         setenv ("bootargs",
    "androidboot.mode=charger"); 

这是这部分的重点,如果能过寄存器判断是DC插入,把androidboot.mode设定为charger状态。

以下这部分根据需要加入,通过判断不同的情况进入不同的功能,如fastboot\revovery…………,这部分不做详细解释。

(4)、检查电池电量;

    这个在正常开机状态下,如果检测电量太低,则不开机,这部分代码就不做分析。

(5)、检查按键状态;

      我们这个平台有几种模式:fastboot\recovery\卡升级等……

(6)、按键进入fastboot模式;

(7)、按键进入recovery模式;

(8)、按键进入卡升级模式

(9)、正常启动;

2、kernel

这部分和正常启动是一样的。

3、init

前面所有的描述其实只有一点和正常启动不太一样,那就是在UBOOT中把androidboot.mode设定为charger状态,内核正常流程启动,然后到init时要对charger这种状态处理。

system\core\init\init.c

  1. int
    main(
    int
    argc,
    char
    **argv) 

  2.     ……………… 
  3.     action_for_each_trigger("early-init",
    action_add_queue_tail); 
  4.  
  5.     queue_builtin_action(wait_for_coldboot_done_action,

    "wait_for_coldboot_done"
    ); 
  6.     queue_builtin_action(property_init_action,

    "property_init"
    ); 
  7.     queue_builtin_action(keychord_init_action,

    "keychord_init"
    ); 
  8.     queue_builtin_action(console_init_action,

    "console_init"
    ); 
    //(1)、显示initlogo.rle,也就是android第二张图片; 
  9.     queue_builtin_action(set_init_properties_action,

    "set_init_properties"
    ); 
  10.  
  11.    

    /* execute all the boot actions to get us started */
     
  12.     action_for_each_trigger("init",
    action_add_queue_tail); 
  13.  
  14.    

    /* skip mounting filesystems in charger mode */
     
  15.    

    if
    (strcmp(bootmode,
    "charger") != 0) {//(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化; 
  16.         action_for_each_trigger("early-fs",
    action_add_queue_tail); 
  17.         action_for_each_trigger("fs",
    action_add_queue_tail); 
  18.         action_for_each_trigger("post-fs",
    action_add_queue_tail); 
  19.         action_for_each_trigger("post-fs-data",
    action_add_queue_tail); 
  20.     } 
  21.  
  22.     queue_builtin_action(property_service_init_action,

    "property_service_init"
    ); 
  23.     queue_builtin_action(signal_init_action,

    "signal_init"
    ); 
  24.     queue_builtin_action(check_startup_action,

    "check_startup"
    ); 
  25.  
  26.    

    if
    (!strcmp(bootmode,
    "charger")) {//(3)、如果为charger,则调用charger.c。 
  27.         action_for_each_trigger("charger",
    action_add_queue_tail); 
  28.     }

    else

  29.         action_for_each_trigger("early-boot",
    action_add_queue_tail); 
  30.         action_for_each_trigger("boot",
    action_add_queue_tail); 
  31.     } 
  32. …………………… 

(1)、显示initlogo.rle,也就是android第二张图片;

queue_builtin_action(console_init_action,"console_init");调用console_init_action

  1. static
    int
    console_init_action(
    int
    nargs,
    char
    **args) 

  2.    

    int
    fd; 
  3.    

    char
    tmp[PROP_VALUE_MAX]; 
  4.    

    if
    (console[0]) { 
  5.         snprintf(tmp,

    sizeof
    (tmp),
    "/dev/%s", console); 
  6.         console_name = strdup(tmp); 
  7.     } 
  8.     fd = open(console_name, O_RDWR); 
  9.    

    if
    (fd >= 0) 
  10.         have_console = 1; 
  11.     close(fd); 
  12.    

    if
    ( load_565rle_image(INIT_IMAGE_FILE) ) {//这里定义rle文件的名称#define
    INIT_IMAGE_FILE "/initlogo.rle"
     
  13.         fd = open("/dev/tty0",
    O_WRONLY); 
  14.        

    if
    (fd >= 0) {//如果没有这张图片,就显示android字样,在屏幕左上角; 
  15.            

    const

    char
    *msg; 
  16.                 msg =

    "\n"
     
  17.            

    "\n"
     
  18.            

    "\n"
     
    // console is 40 cols x 30 lines 
  19.            

    "\n"
     
  20.            

    "\n"
     
  21.            

    "\n"
     
  22.            

    "\n"
     
  23.            

    "\n"
     
  24.            

    "\n"
     
  25.            

    "\n"
     
  26.            

    "             A N D R O I D "

  27.             write(fd, msg, strlen(msg)); 
  28.             close(fd); 
  29.         } 
  30.     } 
  31.    

    return
    0; 

(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;

  1. /*
    skip mounting filesystems in charger mode */
     
  2. if
    (strcmp(bootmode,
    "charger")
    != 0) { 
  3.     action_for_each_trigger("early-fs",
    action_add_queue_tail); 
  4.     action_for_each_trigger("fs",
    action_add_queue_tail); 
  5.     action_for_each_trigger("post-fs",
    action_add_queue_tail); 
  6.     action_for_each_trigger("post-fs-data",
    action_add_queue_tail); 

(3)、如果为charger,则调用charger.c

  1. action_for_each_trigger("charger",
    action_add_queue_tail); 

我们在后面细分charger这部分。

4、charger.c

这部分就是我们充电部分,充电画面显示的实现。

system\core\charger\charger.c

  1. int
    main(
    int
    argc,
    char
    **argv) 

  2. ……………… 
  3.     klog_set_level(CHARGER_KLOG_LEVEL); 
  4.     dump_last_kmsg(); 
  5.     LOGI("---------------
    STARTING CHARGER MODE ---------------\n"
    ); 
  6.  
  7.     gr_init(); 
  8.     gr_font_size(&char_width, &char_height);

    //(1)、初始化graphics,包括buf大小;
     
  9.  
  10.     ev_init(input_callback, charger);//(2)初始化按键; 
  11.     
  12. fd = uevent_open_socket(64*1024,

    true
    ); 
  13.    

    if
    (fd >= 0) { 
  14.         fcntl(fd, F_SETFL, O_NONBLOCK); 
  15.         ev_add_fd(fd, uevent_callback, charger); 
  16.     } 
  17.  
  18.     charger->uevent_fd = fd; 
  19.     coldboot(charger,

    "/sys/class/power_supply"
    ,
    "add");//(3)、创建/sys/class/power_supply结点,把socket信息通知应用层; 
  20.      
  21. ret = res_create_surface("charger/battery_fail",
    &charger->surf_unknown); 
  22.    

    if
    (ret < 0) { 
  23.         LOGE("Cannot
    load image\n"
    ); 
  24.         charger->surf_unknown = NULL; 
  25.     } 
  26.    

    for
    (i = 0; i < charger->batt_anim->num_frames; i++) {//(4)、这里是显示charger
    logo,res_create_surface显示图片函数;
     
  27.        

    struct
    frame *frame = &charger->batt_anim->frames[i]; 
  28.         ret = res_create_surface(frame->name, &frame->surface); 
  29.        

    if
    (ret < 0) { 
  30.             LOGE("Cannot
    load image %s\n"
    , frame->name); 
  31.            

    /* TODO: free the already allocated surfaces... */
     
  32.             charger->batt_anim->num_frames = 0; 
  33.             charger->batt_anim->num_cycles = 1; 
  34.            

    break

  35.         } 
  36.     } 
  37. ev_sync_key_state(set_key_callback, charger); 
  38.     gr_fb_blank(true); 
  39.  
  40.     charger->next_screen_transition = now - 1; 
  41.     charger->next_key_check = -1; 
  42.     charger->next_pwr_check = -1; 
  43.     reset_animation(charger->batt_anim); 
  44.     kick_animation(charger->batt_anim); 
  45.     event_loop(charger);//(5)、event_loop循环,电池状态,检测按键是否按下; 
  46.    

    return
    0; 
  47.  

(1)、初始化graphics,包括buf大小

android/bootable/recovery/minui/graphics.c

gr_init():minui/graphics.c[settty0 to graphic mode, open fb0],设制tty0为图形模式,打开fb0;

  1. int
    gr_init(
    void

  2.     gglInit(&gr_context); 
  3.     GGLContext *gl = gr_context; 
  4.     gr_init_font(); 
  5.     gr_vt_fd = open("/dev/tty0",
    O_RDWR | O_SYNC); 
  6.    

    if
    (gr_vt_fd < 0) { 
  7.        

    // This is non-fatal; post-Cupcake kernels don't have tty0.
     
  8.         perror("can't
    open /dev/tty0"
    ); 
  9.  
  10.     }

    else

    if
    (ioctl(gr_vt_fd, KDSETMODE, (
    void*)
    KD_GRAPHICS)) { 
  11.        

    // However, if we do open tty0, we expect the ioctl to work.
     
  12.         perror("failed
    KDSETMODE to KD_GRAPHICS on tty0"
    ); 
  13.         gr_exit(); 
  14.        

    return
    -1; 
  15.     } 
  16.     gr_fb_fd = get_framebuffer(gr_framebuffer); 
  17.    

    if
    (gr_fb_fd < 0) { 
  18.         gr_exit(); 
  19.        

    return
    -1; 
  20.     } 
  21.     get_memory_surface(&gr_mem_surface); 
  22.     fprintf(stderr,

    "framebuffer: fd %d (%d x %d)\n"

  23.             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); 
  24.        

    /* start with 0 as front (displayed) and 1 as back (drawing) */
     
  25.     gr_active_fb = 0; 
  26.     set_active_framebuffer(0); 
  27.     gl->colorBuffer(gl, &gr_mem_surface); 
  28.     gl->activeTexture(gl, 0); 
  29.     gl->enable(gl, GGL_BLEND); 
  30.     gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA); 
  31.     gr_fb_blank(true); 
  32.     gr_fb_blank(false); 
  33.    

    return
    0; 
  34.  

(2)android/bootable/recovery/minui/events.c

ev_init():minui/events.c[open /dev/input/event*]打开 /dev/input/event*

这部分是在,充电状态下,按键操作的初始化,比如:短按显示充电logo,长按开机,初始化代码如下。

  1. int
    ev_init(ev_callback input_cb,
    void
    *data) 

  2.     DIR *dir; 
  3.    

    struct
    dirent *de; 
  4.    

    int
    fd; 
  5.     dir = opendir("/dev/input");//打开驱动结点; 
  6.    

    if
    (dir != 0) { 
  7.        

    while
    ((de = readdir(dir))) { 
  8.             unsigned

    long
    ev_bits[BITS_TO_LONGS(EV_MAX)]; 
  9. //           
    fprintf(stderr,"/dev/input/%s\n", de->d_name);
     
  10.            

    if
    (strncmp(de->d_name,"event",5))
    continue
  11.             fd = openat(dirfd(dir), de->d_name, O_RDONLY); 
  12.            

    if
    (fd < 0)
    continue
  13.            

    /* read the evbits of the input device */
     
  14.            

    if
    (ioctl(fd, EVIOCGBIT(0,
    sizeof(ev_bits)),
    ev_bits) < 0) { 
  15.                 close(fd); 
  16.                

    continue

  17.             } 
  18.            

    /* TODO: add ability to specify event masks. For now, just assume

  19.             
    * that only EV_KEY and EV_REL event types are ever needed. */
     
  20.            

    if
    (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) { 
  21.                 close(fd); 
  22.                

    continue

  23.             } 
  24.             ev_fds[ev_count].fd = fd; 
  25.             ev_fds[ev_count].events = POLLIN; 
  26.             ev_fdinfo[ev_count].cb = input_cb; 
  27.             ev_fdinfo[ev_count].data = data; 
  28.             ev_count++; 
  29.             ev_dev_count++; 
  30.            

    if
    (ev_dev_count == MAX_DEVICES)
    break
  31.         } 
  32.     } 
  33.    

    return
    0; 

(3)、创建/sys/class/power_supply结点,把socket信息通知应用层

uevent_open_socket这个函数是通过kobject_uevent的方式通知的应用层,就是往一个socket广播一个消息,只需要在应用层打开socket监听NETLINK_KOBJECT_UEVENT组的消息,就可以收到了,主要是创建了socket接口获得uevent的文件描述符,然后触发/sys/class/power_supply目录及其子目录下的uevent,然后接受并创建设备节点,至此设备节点才算创建。

(4)、这里显示charger logo,res_create_surface显示图片函数;

res_create_surface:minui/resource.c[create surfaces for all bitmaps used later, include icons, bmps]

创建surface为所以的位图,包括图标、位图。  这些图片的位置为:system\core\charger\images

(5)、event_loop循环,电池状态,检测按键是否按下;

5、event_loop

       这个函数判断按键状态,DC是否插拔。如果长按开机:执行android_reboot(ANDROID_RB_RESTART,0, 0);如果拔出DC:执行android_reboot(ANDROID_RB_POWEROFF,0, 0);

  1. static
    void
    event_loop(
    struct
    charger *charger) 

  2.    

    int
    ret; 
  3.    

    while
    (true)
  4.         int64_t now = curr_time_ms();//(1)、获得当前时间; 
  5.         LOGV("[%lld]
    event_loop()\n"
    , now); 
  6.         handle_input_state(charger, now);//(2)、检查按键状态; 
  7.         handle_power_supply_state(charger, now);//
    (3)、检查DC是否拔出;
     
  8.        

    /* do screen update last in case any of the above want to start

  9.         
    * screen transitions (animations, etc)
  10.         
    */
     
  11.         update_screen_state(charger, now);//(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;
     
  12.         wait_next_event(charger, now); 
  13.     } 

(1)、获得当前时间;

   int64_t now = curr_time_ms();

       这个时间来判断,有没有屏幕超时,如果超时关闭屏幕充电logo显示。

(2)、检查按键状态;

  1. static
    void
    handle_input_state(
    struct
    charger *charger, int64_t now) 

  2.     process_key(charger, KEY_POWER, now); 
  3.    

    if
    (charger->next_key_check != -1 && now > charger->next_key_check) 
  4.         charger->next_key_check = -1; 

  5. 我们再看下:process_key(charger, KEY_POWER, now); 
  6. static
    void
    process_key(
    struct
    charger *charger,
    int
    code, int64_t now) 

  7. ……………… 
  8.    

    if
    (code == KEY_POWER) { 
  9.        

    if
    (key->down) { 
  10.             int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME; 
  11.            

    if
    (now >= reboot_timeout) {//如果长按power键,就重新启动,也就是重启开机; 
  12.                 LOGI("[%lld]
    rebooting\n"
    , now); 
  13.                 android_reboot(ANDROID_RB_RESTART, 0, 0);//重启命令; 
  14.             } 
  15.     ……………… 
  16.     } 
  17.  
  18.     key->pending =

    false


(3)、检查DC是否拔出;

handle_power_supply_state(charger, now);

  1. static
    void
    handle_power_supply_state(
    struct
    charger *charger, int64_t now) 

  2.    

    if
    (charger->num_supplies_online == 0) { 
  3.        

    if
    (charger->next_pwr_check == -1) { 
  4.             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; 
  5.             LOGI("[%lld]
    device unplugged: shutting down in %lld (@ %lld)\n"

  6.                  now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check); 
  7.         }

    else

    if
    (now >= charger->next_pwr_check) { 
  8.             LOGI("[%lld]
    shutting down\n"
    , now); 
  9.             android_reboot(ANDROID_RB_POWEROFF, 0, 0);//如果DC拔出,则关机; 
  10.         }  
  11. ……………… 

(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;

  update_screen_state(charger, now);

这个函数比较长了,其实做用就是:我们在状态的过程中,充电logo的电量是要增加的,比如电量是20%时,要从第一格开始闪烁;如果是80%时,则要从第三格开始闪烁,电量显示就是通过这个函数来计算实现的。

  1. static
    void
    update_screen_state(
    struct
    charger *charger, int64_t now) 

  2.    

    struct
    animation *batt_anim = charger->batt_anim; 
  3.    

    int
    cur_frame; 
  4.    

    int
    disp_time; 
  5.  
  6.    

    if
    (!batt_anim->run || now < charger->next_screen_transition) 
  7.        

    return

  8.  
  9.    

    /* animation is over, blank screen and leave */
     
  10.    

    if
    (batt_anim->cur_cycle == batt_anim->num_cycles) { 
  11.         reset_animation(batt_anim); 
  12.         charger->next_screen_transition = -1; 
  13.         gr_fb_blank(true); 
  14.         LOGV("[%lld]
    animation done\n"
    , now); 
  15.        

    return

  16.     } 
  17.  
  18.     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time; 
  19.  
  20.    

    /* animation starting, set up the animation */
     
  21.    

    if
    (batt_anim->cur_frame == 0) { 
  22.        

    int
    batt_cap; 
  23.        

    int
    ret; 
  24.  
  25.         LOGV("[%lld]
    animation starting\n"
    , now); 
  26.         batt_cap = get_battery_capacity(charger); 
  27.        

    if
    (batt_cap >= 0 && batt_anim->num_frames != 0) { 
  28.            

    int
    i; 
  29.  
  30.            

    /* find first frame given current capacity */
     
  31.            

    for
    (i = 1; i < batt_anim->num_frames; i++) { 
  32.                

    if
    (batt_cap < batt_anim->frames[i].min_capacity) 
  33.                    

    break

  34.             } 
  35.             batt_anim->cur_frame = i - 1; 
  36.  
  37.            

    /* show the first frame for twice as long */
     
  38.             disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2; 
  39.         } 
  40.  
  41.         batt_anim->capacity = batt_cap; 
  42.     } 
  43.  
  44.    

    /* unblank the screen  on first cycle */
     
  45.    

    if
    (batt_anim->cur_cycle == 0) 
  46.         gr_fb_blank(false); 
  47.  
  48.    

    /* draw the new frame (@ cur_frame) */
     
  49.     redraw_screen(charger); 
  50.  
  51.    

    /* if we don't have anim frames, we only have one image, so just bump

  52.     
    * the cycle counter and exit
  53.     
    */
     
  54.    

    if
    (batt_anim->num_frames == 0 || batt_anim->capacity < 0) { 
  55.         LOGV("[%lld]
    animation missing or unknown battery status\n"
    , now); 
  56.         charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME; 
  57.         batt_anim->cur_cycle++; 
  58.        

    return

  59.     } 
  60.  
  61.    

    /* schedule next screen transition */
     
  62.     charger->next_screen_transition = now + disp_time; 
  63.  
  64.    

    /* advance frame cntr to the next valid frame

  65.     
    * if necessary, advance cycle cntr, and reset frame cntr
  66.     
    */
     
  67.     batt_anim->cur_frame++; 
  68.  
  69.    

    /* if the frame is used for level-only, that is only show it when it's

  70.     
    * the current level, skip it during the animation.
  71.     
    */
     
  72.    

    while
    (batt_anim->cur_frame < batt_anim->num_frames && 
  73.            batt_anim->frames[batt_anim->cur_frame].level_only) 
  74.         batt_anim->cur_frame++; 
  75.    

    if
    (batt_anim->cur_frame >= batt_anim->num_frames) { 
  76.         batt_anim->cur_cycle++; 
  77.         batt_anim->cur_frame = 0; 
  78.  
  79.        

    /* don't reset the cycle counter, since we use that as a signal

  80.         
    * in a test above to check if animation is over
  81.         
    */
     
  82.     } 

下面是不能容量时显示logo的函数:

  1. static
    struct
    frame batt_anim_frames[] = { 
  2.     { 
  3.         .name =

    "charger/battery_0"

  4.         .disp_time = 750, 
  5.         .min_capacity = 0, 
  6.     }, 
  7.     { 
  8.         .name =

    "charger/battery_1"

  9.         .disp_time = 750, 
  10.         .min_capacity = 20, 
  11.     }, 
  12.     { 
  13.         .name =

    "charger/battery_2"

  14.         .disp_time = 750, 
  15.         .min_capacity = 40, 
  16.     }, 
  17.     { 
  18.         .name =

    "charger/battery_3"

  19.         .disp_time = 750, 
  20.         .min_capacity = 60, 
  21.     }, 
  22.     { 
  23.         .name =

    "charger/battery_4"

  24.         .disp_time = 750, 
  25.         .min_capacity = 80, 
  26.         .level_only =

    true

  27.     }, 
  28.     { 
  29.         .name =

    "charger/battery_5"

  30.         .disp_time = 750, 
  31.         .min_capacity = BATTERY_FULL_THRESH, 
  32.     }, 
  33. }; 

抱歉!评论已关闭.