Android recovery和android本质上是两个独立的rootfs, 只是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分。 recovery作为一个简单的rootfs, 提供了非常有限的几个功能,只包含了几个简单的库,UI的显示采用的是直接刷framebuffer的形式,作为android framework及app层的码农,对这种形式相对陌生,特抽点时间梳理了一番。 首先,浏览一下reocvery的main函数代码中UI相关的语句
main(int argc, char **argv) {    ......    Device* device = make_device();            ui = device->GetUI();    gCurrentUI = ui;    ui->Init();    ui->SetLocale(locale);    ui->SetBackground(RecoveryUI::NONE);    if (show_text) ui->ShowText(true);    ......    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {        prompt_and_wait(device, status);    }    ......}
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的主界面,即一个选择菜单

void ScreenRecoveryUI::Init(){    gr_init();    gr_font_size(&char_width, &char_height);    text_col = text_row = 0;    text_rows = gr_fb_height() / char_height;    if (text_rows > kMaxRows) text_rows = kMaxRows;    text_top = 1;    text_cols = gr_fb_width() / char_width;    if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;    LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);    backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];    LoadBitmap("icon_error", &backgroundIcon[ERROR]);    backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];    LoadBitmap("progress_empty", &progressBarEmpty);    LoadBitmap("progress_fill", &progressBarFill);    LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);    LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);    LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);    LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);    int i;    progressBarIndeterminate = (gr_surface*)malloc(indeterminate_frames *                                                    sizeof(gr_surface));    for (i = 0; i  0) {        installationOverlay = (gr_surface*)malloc(installing_frames *                                                   sizeof(gr_surface));        for (i = 0; i 

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(),初始化输入事件处理。

void ScreenRecoveryUI::SetLocale(const char* locale) {    if (locale) {        char* lang = strdup(locale);        for (char* p = lang; *p; ++p) {            if (*p == '_') {                *p = '\0';                break;            }        }        // A bit cheesy: keep an explicit list of supported languages        // that are RTL.        if (strcmp(lang, "ar") == 0 ||   // Arabic            strcmp(lang, "fa") == 0 ||   // Persian (Farsi)            strcmp(lang, "he") == 0 ||   // Hebrew (new language code)            strcmp(lang, "iw") == 0 ||   // Hebrew (old language code)            strcmp(lang, "ur") == 0) {   // Urdu            rtl_locale = true;        }        free(lang);    }}

ScreenRecoveryUI类的SetLocale, 该函数根据locale判断所用的字体是否属于阿拉伯语系,阿拉伯语的书写习惯是从右到左,如果是阿拉伯语系的话,就设置一个标志,后面根据这个标志决定从右到左显示文字或进度条。SetLocale的参数locale赋值逻辑是这样的,先从command文件中读取, command文件中设置locale的命令如"--locale=zh_CN“,如果没有传入locale,初始化过程中会尝试从/cache/recovery/last_locale中读取locale, 如果该文件也没有,则locale不会被赋值,就默认用English.
void ScreenRecoveryUI::SetBackground(Icon icon){    pthread_mutex_lock(&updateMutex);    // Adjust the offset to account for the positioning of the    // base image on the screen.    if (backgroundIcon[icon] != NULL) {        gr_surface bg = backgroundIcon[icon];        gr_surface text = backgroundText[icon];        overlay_offset_x = install_overlay_offset_x + (gr_fb_width() - gr_get_width(bg)) / 2;        overlay_offset_y = install_overlay_offset_y +            (gr_fb_height() - (gr_get_height(bg) + gr_get_height(text) + 40)) / 2;    }    currentIcon = icon;    update_screen_locked();    pthread_mutex_unlock(&updateMutex);}
SetBackground函数比较简洁,关键部分在update_screen_locked,下面我们重点分析一下。 update_screen_locked和update_progress_locked是recovery的UI部分的关键函数,update_screen_locked用来更新背景, update_progress_locked用来更新进度条,因为显示的画面会一直在更新,所以这两个函数会在不同的地方被反复调用
void ScreenRecoveryUI::update_screen_locked(){    draw_screen_locked();    gr_flip();}
update_screen_locked包含两个操作,一是更新screen, 二是切换前后buffer。
void ScreenRecoveryUI::draw_screen_locked(){    draw_background_locked(currentIcon);    draw_progress_locked();    if (show_text) {        SetColor(TEXT_FILL);        gr_fill(0, 0, gr_fb_width(), gr_fb_height());        int y = 0;        int i = 0;        if (show_menu) {            SetColor(HEADER);            for (; i  y+2 && count  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上进行渲染。 
void ScreenRecoveryUI::draw_progress_locked(){    if (currentIcon == ERROR) return;    if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {        draw_install_overlay_locked(installingFrame);    }    if (progressBarType != EMPTY) {        int iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);        int width = gr_get_width(progressBarEmpty);        int height = gr_get_height(progressBarEmpty);        int dx = (gr_fb_width() - width)/2;        int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;        // Erase behind the progress bar (in case this was a progress-only update)        gr_color(0, 0, 0, 255);        gr_fill(dx, dy, width, height);        if (progressBarType == DETERMINATE) {            float p = progressScopeStart + progress * progressScopeSize;            int pos = (int) (p * width);            if (rtl_locale) {                // Fill the progress bar from right to left.                if (pos > 0) {                    gr_blit(progressBarFill, width-pos, 0, pos, height, dx+width-pos, dy);                }                if (pos  0) {                    gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);                }                if (pos  draw_progress_locked函数的原理与 update_screen_locked函数类似, 最终是将进度条的surface输出到渲染buffer, recovery中各个场景的画面,就是由背景、文字、进度条的重叠,不同的是所用的surface 以及surface的坐标。 recovery main函数中的UI代码基本上已经分析过了,最后一点主菜单的显示,就是通过上面介绍的这些接口将文字图片显示出来,因此就不再多讲。总的来说,recovery的UI显示部分难度不大,应用层调用minui库实现了图形的描绘以及固定大小的文字显示,minui库调用了Pixelflinger库来进行渲染。 附上minui部分接口的说明,供参考
int gr_init(void);             /* 初始化图形显示,主要是打开设备、分配内存、初始化一些参数 */  void gr_exit(void);            /* 注销图形显示,关闭设备并释放内存 */    int gr_fb_width(void);         /* 获取屏幕的宽度 */  int gr_fb_height(void);        /* 获取屏幕的高度 */  gr_pixel *gr_fb_data(void);    /* 获取显示数据缓存的地址 */  void gr_flip(void);            /* 刷新显示内容 */  void gr_fb_blank(bool blank);  /* 清屏 */    void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);  /* 设置字体颜色 */  void gr_fill(int x, int y, int w, int h);  /* 填充矩形区域,参数分别代表起始坐标、矩形区域大小 */  int gr_text(int x, int y, const char *s);  /* 显示字符串 */  int gr_measure(const char *s);             /* 获取字符串在默认字库中占用的像素长度 */  void gr_font_size(int *x, int *y);         /* 获取当前字库一个字符所占的长宽 */    void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);  /* 填充由source指定的图片 */  unsigned int gr_get_width(gr_surface surface);   /* 获取图片宽度 */  unsigned int gr_get_height(gr_surface surface);  /* 获取图片高度 */  /* 根据图片创建显示资源数据,name为图片在mk文件指定的相对路径 */  int res_create_surface(const char* name, gr_surface* pSurface);  void res_free_surface(gr_surface surface);       /* 释放资源数据 */  

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. android中wifi原理及流程分析
  4. 在控件的任意位置显示图片
  5. Android异步消息处理机制Handler完全解析
  6. android 退出应用程序
  7. android textview 中超出屏幕宽度的字符 省略号显示
  8. 在做Android中GIF遇到不能显示的问题
  9. (翻译) Backward Compatibility for Applications

随机推荐

  1. Android中文API(126) —— Message
  2. Android(安卓)单选组合框
  3. android 单例
  4. android 权限设置
  5. 收集整理的Android(安卓)color.xml文件的
  6. Android下调用收发短信邮件等
  7. android应用程序的安装位置
  8. Android(安卓)调用手机系统照相机拍照
  9. android 编写简单浏览器带下载
  10. [Android(安卓)UI] ActionBar 自定义属性