Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1385697
  • 博文数量: 478
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4833
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-28 11:12
文章分类

全部博文(478)

文章存档

2019年(1)

2018年(27)

2017年(21)

2016年(171)

2015年(258)

我的朋友

分类: Android平台

2015-08-22 22:27:37

http://blog.csdn.net/huangyabin001/article/details/42673217


 

Android recovery UI实现分析

分类: Android OTA(MTK) 468人阅读 评论(0) 收藏 举报
转载地址:http://blog.csdn.net/u010223349/article/details/40392789
关于这个问题, baidu上已经有无数的答案,不理解的朋友先补习一下。从纯技术角度来讲, recovery和android本质上是两个独立的rootfs,  只是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分。 
 recovery作为一个简单的rootfs, 提供了非常有限的几个功能,只包含了几个简单的库,UI的显示采用的是直接刷framebuffer的形式,作为android framework及app层的码农,对这种形式相对陌生,特抽点时间梳理了一番。
 
首先,浏览一下reocvery的main函数代码中UI相关的语句
  1. main(int argc, char **argv) {  
  2.   
  3.     ......  
  4.   
  5.     Device* device = make_device();          
  6.     ui = device->GetUI();  
  7.     gCurrentUI = ui;  
  8.   
  9.     ui->Init();  
  10.     ui->SetLocale(locale);  
  11.     ui->SetBackground(RecoveryUI::NONE);  
  12.     if (show_text) ui->ShowText(true);  
  13.   
  14.     ......  
  15.   
  16.     if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {  
  17.         prompt_and_wait(device, status);  
  18.     }  
  19.   
  20.     ......  
  21. }  
1、首先新建了一个Device类的对象, Device类封装了一些操作,包括UI的操作
2、调用Device类的GetUI()返回一个DefaultUI对象,recovery中涉及到三个UI类,三个类之间为继承关系,分别为DefaultUI、
   ScreenRecoveryUI、RecoveryUI
3、调用DefaultUI类的Init(), DefaultUI类没有Init()方法,因此将调用它的父类ScreenRecoveryUI的Init()
4、同理,调用ScreenRecoveryUI类的SetLocale()来标识几个比较特别的区域
5、同理,调用ScreenRecoveryUI类的SetBackground()设置初始状态的背景图
6、显示recovery的主界面,即一个选择菜单

 

  1. void ScreenRecoveryUI::Init()  
  2. {  
  3.     gr_init();  
  4.   
  5.     gr_font_size(&char_width, &char_height);  
  6.   
  7.     text_col = text_row = 0;  
  8.     text_rows = gr_fb_height() / char_height;  
  9.     if (text_rows > kMaxRows) text_rows = kMaxRows;  
  10.     text_top = 1;  
  11.   
  12.     text_cols = gr_fb_width() / char_width;  
  13.     if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;  
  14.   
  15.     LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);  
  16.     backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];  
  17.     LoadBitmap("icon_error", &backgroundIcon[ERROR]);  
  18.     backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];  
  19.   
  20.     LoadBitmap("progress_empty", &progressBarEmpty);  
  21.     LoadBitmap("progress_fill", &progressBarFill);  
  22.   
  23.     LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);  
  24.     LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);  
  25.     LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);  
  26.     LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);  
  27.   
  28.     int i;  
  29.   
  30.     progressBarIndeterminate = (gr_surface*)malloc(indeterminate_frames *  
  31.                                                     sizeof(gr_surface));  
  32.     for (i = 0; i < indeterminate_frames; ++i) {  
  33.         char filename[40];  
  34.         // "indeterminate01.png", "indeterminate02.png", ...  
  35.         sprintf(filename, "indeterminate%02d", i+1);  
  36.         LoadBitmap(filename, progressBarIndeterminate+i);  
  37.     }  
  38.   
  39.     if (installing_frames > 0) {  
  40.         installationOverlay = (gr_surface*)malloc(installing_frames *  
  41.                                                    sizeof(gr_surface));  
  42.         for (i = 0; i < installing_frames; ++i) {  
  43.             char filename[40];  
  44.             // "icon_installing_overlay01.png",  
  45.             // "icon_installing_overlay02.png", ...  
  46.             sprintf(filename, "icon_installing_overlay%02d", i+1);  
  47.             LoadBitmap(filename, installationOverlay+i);  
  48.         }  
  49.     } else {  
  50.         installationOverlay = NULL;  
  51.     }  
  52.   
  53.     pthread_create(&progress_t, NULL, progress_thread, NULL);  
  54.   
  55.     RecoveryUI::Init();  
  56. }  


 

1、gr_init()  初始化图形设备,分配Pixelflinger库渲染的内存

2、gr_font_size()  将字体对应的surface长宽赋值给char_width和char_height

3、LoadBitmap()  将png生成surface, 每个png图片对应一个surface, 所有surface存放在一个数组中
4、LoadLocalizedBitmap()  将区域文字所在的图片中的text信息根据当前的locale提取出来,生成对应的surface, 所以
   surface也存放在一个数组中
6、pthread_create(&progress_t, NULL, progress_thread, NULL) 创建一个线程,该线程的任务是一个死循环,在该循环中不停
   地检测currentIcon以及progressBarType来决定是不是要更新进度条。
7、调用RecoveryUI的Init(),初始化输入事件处理。

 


  1. void ScreenRecoveryUI::SetLocale(const char* locale) {  
  2.     if (locale) {  
  3.         char* lang = strdup(locale);  
  4.         for (char* p = lang; *p; ++p) {  
  5.             if (*p == '_') {  
  6.                 *p = '\0';  
  7.                 break;  
  8.             }  
  9.         }  
  10.   
  11.         // A bit cheesy: keep an explicit list of supported languages  
  12.         // that are RTL.  
  13.         if (strcmp(lang, "ar") == 0 ||   // Arabic  
  14.             strcmp(lang, "fa") == 0 ||   // Persian (Farsi)  
  15.             strcmp(lang, "he") == 0 ||   // Hebrew (new language code)  
  16.             strcmp(lang, "iw") == 0 ||   // Hebrew (old language code)  
  17.             strcmp(lang, "ur") == 0) {   // Urdu  
  18.             rtl_locale = true;  
  19.         }  
  20.         free(lang);  
  21.     }  
  22. }  

 
ScreenRecoveryUI类的SetLocale, 该函数根据locale判断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,如果是阿拉伯语系的话,就设置一个标志,后面根据这个标志决定从右到左显示文字或进度条。
SetLocale的参数locale赋值逻辑是这样的,先从command文件中读取, command文件中设置locale的命令如"--locale=zh_CN“,如果没有传入locale,初始化过程中会尝试从/cache/recovery/last_locale中读取locale, 如果该文件也没有,则locale不会被赋值,就默认用English.
 
 
  1. void ScreenRecoveryUI::SetBackground(Icon icon)  
  2. {  
  3.     pthread_mutex_lock(&updateMutex);  
  4.   
  5.     // Adjust the offset to account for the positioning of the  
  6.     // base image on the screen.  
  7.     if (backgroundIcon[icon] != NULL) {  
  8.         gr_surface bg = backgroundIcon[icon];  
  9.         gr_surface text = backgroundText[icon];  
  10.         overlay_offset_x = install_overlay_offset_x + (gr_fb_width() - gr_get_width(bg)) / 2;  
  11.         overlay_offset_y = install_overlay_offset_y +  
  12.             (gr_fb_height() - (gr_get_height(bg) + gr_get_height(text) + 40)) / 2;  
  13.     }  
  14.   
  15.     currentIcon = icon;  
  16.     update_screen_locked();  
  17.   
  18.     pthread_mutex_unlock(&updateMutex);  
  19. }  
 
SetBackground函数比较简洁,关键部分在update_screen_locked,下面我们重点分析一下。
 
update_screen_locked和update_progress_locked是recovery的UI部分的关键函数,update_screen_locked用来更新背景, update_progress_locked用来更新进度条,因为显示的画面会一直在更新,所以这两个函数会在不同的地方被反复调用

  1. void ScreenRecoveryUI::update_screen_locked()  
  2. {  
  3.     draw_screen_locked();  
  4.     gr_flip();  
  5. }  
 
update_screen_locked包含两个操作,一是更新screen, 二是切换前后buffer。
 
  1. void ScreenRecoveryUI::draw_screen_locked()  
  2. {  
  3.     draw_background_locked(currentIcon);  
  4.     draw_progress_locked();  
  5.   
  6.     if (show_text) {  
  7.         SetColor(TEXT_FILL);  
  8.         gr_fill(0, 0, gr_fb_width(), gr_fb_height());  
  9.   
  10.         int y = 0;  
  11.         int i = 0;  
  12.         if (show_menu) {  
  13.             SetColor(HEADER);  
  14.   
  15.             for (; i < menu_top + menu_items; ++i) {  
  16.                 if (i == menu_top) SetColor(MENU);  
  17.   
  18.                 if (i == menu_top + menu_sel) {  
  19.                     // draw the highlight bar  
  20.                     SetColor(MENU_SEL_BG);  
  21.                     gr_fill(0, y-2, gr_fb_width(), y+char_height+2);  
  22.                     // white text of selected item  
  23.                     SetColor(MENU_SEL_FG);  
  24.                     if (menu[i][0]) gr_text(4, y, menu[i], 1);  
  25.                     SetColor(MENU);  
  26.                 } else {  
  27.                     if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top);  
  28.                 }  
  29.                 y += char_height+4;  
  30.             }  
  31.             SetColor(MENU);  
  32.             y += 4;  
  33.             gr_fill(0, y, gr_fb_width(), y+2);  
  34.             y += 4;  
  35.             ++i;  
  36.         }  
  37.   
  38.         SetColor(LOG);  
  39.   
  40.         // display from the bottom up, until we hit the top of the  
  41.         // screen, the bottom of the menu, or we've displayed the  
  42.         // entire text buffer.  
  43.         int ty;  
  44.         int row = (text_top+text_rows-1) % text_rows;  
  45.         for (int ty = gr_fb_height() - char_height, count = 0;  
  46.              ty > y+2 && count < text_rows;  
  47.              ty -= char_height, ++count) {  
  48.             gr_text(4, ty, text[row], 0);  
  49.             --row;  
  50.             if (row < 0) row = text_rows-1;  
  51.         }  
  52.     }  
  53. }  

 
draw_background_locked函数的实现代码中又出现了几个以gr_开头的函数,以gr_开头的函数来自minui库,minui库的代码在recovery源码下的minui目录下,minui提供的接口实现了图形的描绘以及固定大小的文字显示。

gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);  /* 设置字体颜色 */  
gr_fill(int x, int y, int w, int h);  /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */  
gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);  /* 填充由source指定的图片 */  

draw_background_locked函数先将整个渲染buffer填充为黑色,然后计算背景surface的长宽,文字surface的长宽,再结合fb的长宽计算出背景surface以及文字surface显示的坐标,有长宽和坐标就可以调用Pixelflinger的接口在渲染buffer上进行渲染。
 
  1. void ScreenRecoveryUI::draw_progress_locked()  
  2. {  
  3.     if (currentIcon == ERROR) return;  
  4.   
  5.     if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {  
  6.         draw_install_overlay_locked(installingFrame);  
  7.     }  
  8.   
  9.     if (progressBarType != EMPTY) {  
  10.         int iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);  
  11.         int width = gr_get_width(progressBarEmpty);  
  12.         int height = gr_get_height(progressBarEmpty);  
  13.   
  14.         int dx = (gr_fb_width() - width)/2;  
  15.         int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;  
  16.   
  17.         // Erase behind the progress bar (in case this was a progress-only update)  
  18.         gr_color(0, 0, 0, 255);  
  19.         gr_fill(dx, dy, width, height);  
  20.   
  21.         if (progressBarType == DETERMINATE) {  
  22.             float p = progressScopeStart + progress * progressScopeSize;  
  23.             int pos = (int) (p * width);  
  24.   
  25.             if (rtl_locale) {  
  26.                 // Fill the progress bar from right to left.  
  27.                 if (pos > 0) {  
  28.                     gr_blit(progressBarFill, width-pos, 0, pos, height, dx+width-pos, dy);  
  29.                 }  
  30.                 if (pos < width-1) {  
  31.                     gr_blit(progressBarEmpty, 0, 0, width-pos, height, dx, dy);  
  32.                 }  
  33.             } else {  
  34.                 // Fill the progress bar from left to right.  
  35.                 if (pos > 0) {  
  36.                     gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);  
  37.                 }  
  38.                 if (pos < width-1) {  
  39.                     gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);  
  40.                 }  
  41.             }  
  42.         }  
  43.   
  44.         if (progressBarType == INDETERMINATE) {  
  45.             static int frame = 0;  
  46.             gr_blit(progressBarIndeterminate[frame], 0, 0, width, height, dx, dy);  
  47.             // in RTL locales, we run the animation backwards, which  
  48.             // makes the spinner spin the other way.  
  49.             if (rtl_locale) {  
  50.                 frame = (frame + indeterminate_frames - 1) % indeterminate_frames;  
  51.             } else {  
  52.                 frame = (frame + 1) % indeterminate_frames;  
  53.             }  
  54.         }  
  55.     }  
  56. }  

 
draw_progress_locked函数的原理与 update_screen_locked函数类似, 最终是将进度条的surface输出到渲染buffer, 
recovery中各个场景的画面,就是由背景、文字、进度条的重叠,不同的是所用的surface 以及surface的坐标。
 
recovery main函数中的UI代码基本上已经分析过了,最后一点主菜单的显示,就是通过上面介绍的这些接口将文字图片显示出来,因此就不再多讲。总的来说,recovery的UI显示部分难度不大,应用层调用minui库实现了图形的描绘以及固定大小的文字显示,minui库调用了Pixelflinger库来进行渲染。
 
附上minui部分接口的说明,供参考
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int gr_init(void);             /* 初始化图形显示,主要是打开设备、分配内存、初始化一些参数 */    
  2. void gr_exit(void);            /* 注销图形显示,关闭设备并释放内存 */    
  3.     
  4. int gr_fb_width(void);         /* 获取屏幕的宽度 */    
  5. int gr_fb_height(void);        /* 获取屏幕的高度 */    
  6. gr_pixel *gr_fb_data(void);    /* 获取显示数据缓存的地址 */    
  7. void gr_flip(void);            /* 刷新显示内容 */    
  8. void gr_fb_blank(bool blank);  /* 清屏 */    
  9.     
  10. void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);  /* 设置字体颜色 */    
  11. void gr_fill(int x, int y, int w, int h);  /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */    
  12. int gr_text(int x, int y, const char *s);  /* 显示字符串 */    
  13. int gr_measure(const char *s);             /* 获取字符串在默认字库中占用的像素长度 */    
  14. void gr_font_size(int *x, int *y);         /* 获取当前字库一个字符所占的长宽 */    
  15.     
  16. void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);  /* 填充由source指定的图片 */    
  17. unsigned int gr_get_width(gr_surface surface);   /* 获取图片宽度 */    
  18. unsigned int gr_get_height(gr_surface surface);  /* 获取图片高度 */    
  19. /* 根据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */    
  20. int res_create_surface(const char* name, gr_surface* pSurface);    
  21. void res_free_surface(gr_surface surface);       /* 释放资源数据 */    
阅读(1261) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~