android 电池(二):android关机充电流程、充电画面显示

ZZZ:http://blog.csdn.net/xubin341719/article/details/8498580

分类:S5PXX(三星) 14511人阅读 评论(15) 收藏 举报

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

作者:xubin341719(欢迎转载,请注明作者)

欢迎指正错误,共同学习、共同进步!!


android 电池(一):锂电池基本原理篇

android 电池(二):android关机充电流程、充电画面显示

android 电池(三):android电池系统

android电池(四):电池 电量计(MAX17040)驱动分析篇

android电池(五):电池 充电IC(PM2301)驱动分析篇


上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下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

[cpp] view plain copy
  1. intboard_late_init(void)
  2. {
  3. intkeystate=0;
  4. printf("checkstartmode\n");
  5. if((*(int*)0x10020800==0x19721212)||(*(int*)0x10020804==0x19721212)
  6. ||(*(int*)0x10020808==0x19721212))//(1)、检查是否有DC插入;
  7. {
  8. setenv("bootargs","");//(2)、没有DC插入;
  9. }else{//DC插入
  10. inttmp=*(int*)0x11000c08;
  11. *(int*)0x10020800=*(int*)0x10020804=0x19721212;
  12. *(int*)0x11000c08=(tmp&(~0xc000))|0xc000;
  13. udelay(10000);
  14. if((*(int*)0x11000c04&0x80)!=0x80&&INF_REG4_REG!=0xf){
  15. setenv("bootargs","androidboot.mode=charger");//(3)、设定bootargs为charger状态
  16. printf("chargermode\n");
  17. }else{
  18. setenv("bootargs","");
  19. }
  20. *(int*)0x11000c08=tmp;
  21. }
  22. #ifdefCONFIG_CPU_EXYNOS4X12
  23. intcharge_status=CheckBatteryLow();//(4)、检查电池电量;
  24. keystate=board_key_check();//(5)、检查按键状态;
  25. //fusebootloader
  26. if(second_boot_info!=0){
  27. boot_symbol=1;
  28. INF_REG2_REG=0x8;
  29. run_command(CONFIG_BOOTCMD_FUSE_BOOTLOADER,NULL);
  30. }
  31. if((INF_REG4_REG==0xd)){
  32. //rebootdefault
  33. charbuf[10];
  34. sprintf(buf,"%d",CONFIG_BOOTDELAY);
  35. setenv("bootdelay",buf);
  36. setenv("reserved",NULL);
  37. saveenv();
  38. }elseif((INF_REG4_REG==0xe)||keystate==(0x1|0x2)){//(6)、按键进入fastboot模式;
  39. //rebootbootloader
  40. boot_symbol=1;
  41. INF_REG2_REG=0x8;
  42. printf("BOOTLOADER-FASTBOOT\n");
  43. setenv("reserved","fastboot");
  44. setenv("bootdelay","0");
  45. }elseif((INF_REG4_REG==0xf)||keystate==(0x1|0x2|0x4)){//(7)、按键进入recovery模式;
  46. //rebootrecovery
  47. printf("BOOTLOADER-RECOVERY\n");
  48. boot_symbol=1;
  49. INF_REG2_REG=0x8;
  50. setenv("reserved",CONFIG_BOOTCMD_RECOVERY);
  51. setenv("bootdelay","0");
  52. }else
  53. if(keystate==(0x1|0x4)||second_boot_info!=0||partition_check()){//(8)、按键进入卡升级模式;
  54. //2ndboot
  55. printf("BOOTLOADER-2NDBOOTDEVICE\n");
  56. boot_symbol=1;
  57. INF_REG2_REG=0x8;
  58. setenv("bootcmd",CONFIG_BOOTCOMMAND);
  59. setenv("reserved",CONFIG_BOOTCMD_FUSE_RELEASE);
  60. setenv("bootdelay","0");
  61. }else{//(9)、正常启动;
  62. //normalcase
  63. charbuf[10];
  64. sprintf(buf,"%d",CONFIG_BOOTDELAY);
  65. setenv("bootdelay",buf);
  66. }
  67. INF_REG4_REG=0;
  68. return0;
  69. }

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

[cpp] view plain copy
  1. if((*(int*)0x10020800==0x19721212)||(*(int*)0x10020804==0x19721212)
  2. (*(int*)0x10020808==0x19721212))

这部分检查寄存器的值。

(2)、没有DC插入;

(3)、设定bootargs为charger状态

[cpp] view plain copy
  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

[cpp] view plain copy
  1. intmain(intargc,char**argv)
  2. {
  3. ………………
  4. action_for_each_trigger("early-init",action_add_queue_tail);
  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. /*executeallthebootactionstogetusstarted*/
  11. action_for_each_trigger("init",action_add_queue_tail);
  12. /*skipmountingfilesystemsinchargermode*/
  13. if(strcmp(bootmode,"charger")!=0){//(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;
  14. action_for_each_trigger("early-fs",action_add_queue_tail);
  15. action_for_each_trigger("fs",action_add_queue_tail);
  16. action_for_each_trigger("post-fs",action_add_queue_tail);
  17. action_for_each_trigger("post-fs-data",action_add_queue_tail);
  18. }
  19. queue_builtin_action(property_service_init_action,"property_service_init");
  20. queue_builtin_action(signal_init_action,"signal_init");
  21. queue_builtin_action(check_startup_action,"check_startup");
  22. if(!strcmp(bootmode,"charger")){//(3)、如果为charger,则调用charger.c。
  23. action_for_each_trigger("charger",action_add_queue_tail);
  24. }else{
  25. action_for_each_trigger("early-boot",action_add_queue_tail);
  26. action_for_each_trigger("boot",action_add_queue_tail);
  27. }
  28. ……………………
  29. }

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

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

[cpp] view plain copy
  1. staticintconsole_init_action(intnargs,char**args)
  2. {
  3. intfd;
  4. chartmp[PROP_VALUE_MAX];
  5. if(console[0]){
  6. snprintf(tmp,sizeof(tmp),"/dev/%s",console);
  7. console_name=strdup(tmp);
  8. }
  9. fd=open(console_name,O_RDWR);
  10. if(fd>=0)
  11. have_console=1;
  12. close(fd);
  13. if(load_565rle_image(INIT_IMAGE_FILE)){//这里定义rle文件的名称#defineINIT_IMAGE_FILE"/initlogo.rle"
  14. fd=open("/dev/tty0",O_WRONLY);
  15. if(fd>=0){//如果没有这张图片,就显示android字样,在屏幕左上角;
  16. constchar*msg;
  17. msg="\n"
  18. "\n"
  19. "\n"//consoleis40colsx30lines
  20. "\n"
  21. "\n"
  22. "\n"
  23. "\n"
  24. "\n"
  25. "\n"
  26. "\n"
  27. "ANDROID";
  28. write(fd,msg,strlen(msg));
  29. close(fd);
  30. }
  31. }
  32. return0;
  33. }

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

[cpp] view plain copy
  1. /*skipmountingfilesystemsinchargermode*/
  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);
  7. }

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

[cpp] view plain copy
  1. action_for_each_trigger("charger",action_add_queue_tail);

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

4、charger.c

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

system\core\charger\charger.c

[cpp] view plain copy
  1. intmain(intargc,char**argv)
  2. {
  3. ………………
  4. klog_set_level(CHARGER_KLOG_LEVEL);
  5. dump_last_kmsg();
  6. LOGI("---------------STARTINGCHARGERMODE---------------\n");
  7. gr_init();
  8. gr_font_size(&char_width,&char_height);//(1)、初始化graphics,包括buf大小;
  9. ev_init(input_callback,charger);//(2)初始化按键;
  10. fd=uevent_open_socket(64*1024,true);
  11. if(fd>=0){
  12. fcntl(fd,F_SETFL,O_NONBLOCK);
  13. ev_add_fd(fd,uevent_callback,charger);
  14. }
  15. charger->uevent_fd=fd;
  16. coldboot(charger,"/sys/class/power_supply","add");//(3)、创建/sys/class/power_supply结点,把socket信息通知应用层;
  17. ret=res_create_surface("charger/battery_fail",&charger->surf_unknown);
  18. if(ret<0){
  19. LOGE("Cannotloadimage\n");
  20. charger->surf_unknown=NULL;
  21. }
  22. for(i=0;i<charger->batt_anim->num_frames;i++){//(4)、这里是显示chargerlogo,res_create_surface显示图片函数;
  23. structframe*frame=&charger->batt_anim->frames[i];
  24. ret=res_create_surface(frame->name,&frame->surface);
  25. if(ret<0){
  26. LOGE("Cannotloadimage%s\n",frame->name);
  27. /*TODO:freethealreadyallocatedsurfaces...*/
  28. charger->batt_anim->num_frames=0;
  29. charger->batt_anim->num_cycles=1;
  30. break;
  31. }
  32. }
  33. ev_sync_key_state(set_key_callback,charger);
  34. gr_fb_blank(true);
  35. charger->next_screen_transition=now-1;
  36. charger->next_key_check=-1;
  37. charger->next_pwr_check=-1;
  38. reset_animation(charger->batt_anim);
  39. kick_animation(charger->batt_anim);
  40. event_loop(charger);//(5)、event_loop循环,电池状态,检测按键是否按下;
  41. return0;
  42. }

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

android/bootable/recovery/minui/graphics.c

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

[cpp] view plain copy
  1. intgr_init(void)
  2. {
  3. gglInit(&gr_context);
  4. GGLContext*gl=gr_context;
  5. gr_init_font();
  6. gr_vt_fd=open("/dev/tty0",O_RDWR|O_SYNC);
  7. if(gr_vt_fd<0){
  8. //Thisisnon-fatal;post-Cupcakekernelsdon'thavetty0.
  9. perror("can'topen/dev/tty0");
  10. }elseif(ioctl(gr_vt_fd,KDSETMODE,(void*)KD_GRAPHICS)){
  11. //However,ifwedoopentty0,weexpecttheioctltowork.
  12. perror("failedKDSETMODEtoKD_GRAPHICSontty0");
  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(%dx%d)\n",
  23. gr_fb_fd,gr_framebuffer[0].width,gr_framebuffer[0].height);
  24. /*startwith0asfront(displayed)and1asback(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. return0;
  34. }

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

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

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

[cpp] view plain copy
  1. intev_init(ev_callbackinput_cb,void*data)
  2. {
  3. DIR*dir;
  4. structdirent*de;
  5. intfd;
  6. dir=opendir("/dev/input");//打开驱动结点;
  7. if(dir!=0){
  8. while((de=readdir(dir))){
  9. unsignedlongev_bits[BITS_TO_LONGS(EV_MAX)];
  10. //fprintf(stderr,"/dev/input/%s\n",de->d_name);
  11. if(strncmp(de->d_name,"event",5))continue;
  12. fd=openat(dirfd(dir),de->d_name,O_RDONLY);
  13. if(fd<0)continue;
  14. /*readtheevbitsoftheinputdevice*/
  15. if(ioctl(fd,EVIOCGBIT(0,sizeof(ev_bits)),ev_bits)<0){
  16. close(fd);
  17. continue;
  18. }
  19. /*TODO:addabilitytospecifyeventmasks.Fornow,justassume
  20. *thatonlyEV_KEYandEV_RELeventtypesareeverneeded.*/
  21. if(!test_bit(EV_KEY,ev_bits)&&!test_bit(EV_REL,ev_bits)){
  22. close(fd);
  23. continue;
  24. }
  25. ev_fds[ev_count].fd=fd;
  26. ev_fds[ev_count].events=POLLIN;
  27. ev_fdinfo[ev_count].cb=input_cb;
  28. ev_fdinfo[ev_count].data=data;
  29. ev_count++;
  30. ev_dev_count++;
  31. if(ev_dev_count==MAX_DEVICES)break;
  32. }
  33. }
  34. return0;
  35. }

(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);

[cpp] view plain copy
  1. staticvoidevent_loop(structcharger*charger)
  2. {
  3. intret;
  4. while(true){
  5. int64_tnow=curr_time_ms();//(1)、获得当前时间;
  6. LOGV("[%lld]event_loop()\n",now);
  7. handle_input_state(charger,now);//(2)、检查按键状态;
  8. handle_power_supply_state(charger,now);//(3)、检查DC是否拔出;
  9. /*doscreenupdatelastincaseanyoftheabovewanttostart
  10. *screentransitions(animations,etc)
  11. */
  12. update_screen_state(charger,now);//(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;
  13. wait_next_event(charger,now);
  14. }
  15. }

(1)、获得当前时间;

int64_t now = curr_time_ms();

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

(2)、检查按键状态;

[cpp] view plain copy
  1. staticvoidhandle_input_state(structcharger*charger,int64_tnow)
  2. {
  3. process_key(charger,KEY_POWER,now);
  4. if(charger->next_key_check!=-1&&now>charger->next_key_check)
  5. charger->next_key_check=-1;
  6. }
  7. 我们再看下:process_key(charger,KEY_POWER,now);
  8. staticvoidprocess_key(structcharger*charger,intcode,int64_tnow)
  9. {
  10. ………………
  11. if(code==KEY_POWER){
  12. if(key->down){
  13. int64_treboot_timeout=key->timestamp+POWER_ON_KEY_TIME;
  14. if(now>=reboot_timeout){//如果长按power键,就重新启动,也就是重启开机;
  15. LOGI("[%lld]rebooting\n",now);
  16. android_reboot(ANDROID_RB_RESTART,0,0);//重启命令;
  17. }
  18. ………………
  19. }
  20. key->pending=false;
  21. }

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

handle_power_supply_state(charger, now);

[cpp] view plain copy
  1. staticvoidhandle_power_supply_state(structcharger*charger,int64_tnow)
  2. {
  3. if(charger->num_supplies_online==0){
  4. if(charger->next_pwr_check==-1){
  5. charger->next_pwr_check=now+UNPLUGGED_SHUTDOWN_TIME;
  6. LOGI("[%lld]deviceunplugged:shuttingdownin%lld(@%lld)\n",
  7. now,UNPLUGGED_SHUTDOWN_TIME,charger->next_pwr_check);
  8. }elseif(now>=charger->next_pwr_check){
  9. LOGI("[%lld]shuttingdown\n",now);
  10. android_reboot(ANDROID_RB_POWEROFF,0,0);//如果DC拔出,则关机;
  11. }
  12. ………………
  13. }

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

update_screen_state(charger, now);

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

[cpp] view plain copy
  1. staticvoidupdate_screen_state(structcharger*charger,int64_tnow)
  2. {
  3. structanimation*batt_anim=charger->batt_anim;
  4. intcur_frame;
  5. intdisp_time;
  6. if(!batt_anim->run||now<charger->next_screen_transition)
  7. return;
  8. /*animationisover,blankscreenandleave*/
  9. if(batt_anim->cur_cycle==batt_anim->num_cycles){
  10. reset_animation(batt_anim);
  11. charger->next_screen_transition=-1;
  12. gr_fb_blank(true);
  13. LOGV("[%lld]animationdone\n",now);
  14. return;
  15. }
  16. disp_time=batt_anim->frames[batt_anim->cur_frame].disp_time;
  17. /*animationstarting,setuptheanimation*/
  18. if(batt_anim->cur_frame==0){
  19. intbatt_cap;
  20. intret;
  21. LOGV("[%lld]animationstarting\n",now);
  22. batt_cap=get_battery_capacity(charger);
  23. if(batt_cap>=0&&batt_anim->num_frames!=0){
  24. inti;
  25. /*findfirstframegivencurrentcapacity*/
  26. for(i=1;i<batt_anim->num_frames;i++){
  27. if(batt_cap<batt_anim->frames[i].min_capacity)
  28. break;
  29. }
  30. batt_anim->cur_frame=i-1;
  31. /*showthefirstframefortwiceaslong*/
  32. disp_time=batt_anim->frames[batt_anim->cur_frame].disp_time*2;
  33. }
  34. batt_anim->capacity=batt_cap;
  35. }
  36. /*unblankthescreenonfirstcycle*/
  37. if(batt_anim->cur_cycle==0)
  38. gr_fb_blank(false);
  39. /*drawthenewframe(@cur_frame)*/
  40. redraw_screen(charger);
  41. /*ifwedon'thaveanimframes,weonlyhaveoneimage,sojustbump
  42. *thecyclecounterandexit
  43. */
  44. if(batt_anim->num_frames==0||batt_anim->capacity<0){
  45. LOGV("[%lld]animationmissingorunknownbatterystatus\n",now);
  46. charger->next_screen_transition=now+BATTERY_UNKNOWN_TIME;
  47. batt_anim->cur_cycle++;
  48. return;
  49. }
  50. /*schedulenextscreentransition*/
  51. charger->next_screen_transition=now+disp_time;
  52. /*advanceframecntrtothenextvalidframe
  53. *ifnecessary,advancecyclecntr,andresetframecntr
  54. */
  55. batt_anim->cur_frame++;
  56. /*iftheframeisusedforlevel-only,thatisonlyshowitwhenit's
  57. *thecurrentlevel,skipitduringtheanimation.
  58. */
  59. while(batt_anim->cur_frame<batt_anim->num_frames&&
  60. batt_anim->frames[batt_anim->cur_frame].level_only)
  61. batt_anim->cur_frame++;
  62. if(batt_anim->cur_frame>=batt_anim->num_frames){
  63. batt_anim->cur_cycle++;
  64. batt_anim->cur_frame=0;
  65. /*don'tresetthecyclecounter,sinceweusethatasasignal
  66. *inatestabovetocheckifanimationisover
  67. */
  68. }
  69. }

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

[cpp] view plain copy
  1. staticstructframebatt_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. };

更多相关文章

  1. Android中EditText属性
  2. 图解Android(安卓)- Android(安卓)GUI 系统 (1) - 概论
  3. Android(安卓)EditText 属性汇总
  4. android:maxLines和android:ellipsize同时使用导致显示异常
  5. Android按键添加和处理的方案
  6. Android(安卓)多个Activity选项卡实现
  7. Android(安卓)EditView属性
  8. Android(安卓)的独特shell命令
  9. Android中显示在线PDF

随机推荐

  1. Lottie动画
  2. android permission 访问权限大全
  3. Android(安卓)系统状态栏一体化
  4. android声音调整源代码分析
  5. android手机通讯录备份还原代码
  6. 从Android访问PC端的port (reverse port
  7. Android(安卓)pm命令详解
  8. 【android】android 开发错误集锦4月
  9. 为android-support-v4.jar打包源码
  10. Android系统源码数据库(mmssms.db)