Android recovery UI实现分析
从纯技术角度来讲, recovery和android本质上是两个独立的rootfs, 仅仅是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分。
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); } ...... }
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 < indeterminate_frames; ++i) { char filename[40]; // "indeterminate01.png", "indeterminate02.png", ... sprintf(filename, "indeterminate%02d", i+1); LoadBitmap(filename, progressBarIndeterminate+i); } if (installing_frames > 0) { installationOverlay = (gr_surface*)malloc(installing_frames * sizeof(gr_surface)); for (i = 0; i < installing_frames; ++i) { char filename[40]; // "icon_installing_overlay01.png", // "icon_installing_overlay02.png", ... sprintf(filename, "icon_installing_overlay%02d", i+1); LoadBitmap(filename, installationOverlay+i); } } else { installationOverlay = NULL; } pthread_create(&progress_t, NULL, progress_thread, NULL); RecoveryUI::Init(); }
1、gr_init() 初始化图形设备,分配Pixelflinger库渲染的内存
2、gr_font_size() 将字体相应的surface长宽赋值给char_width和char_height
创建一个线程,该线程的任务是一个死循环,在该循环中不停
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); } }
假设该文件也没有,则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); }
void ScreenRecoveryUI::update_screen_locked() { draw_screen_locked(); gr_flip(); }
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 < menu_top + menu_items; ++i) { if (i == menu_top) SetColor(MENU); if (i == menu_top + menu_sel) { // draw the highlight bar SetColor(MENU_SEL_BG); gr_fill(0, y-2, gr_fb_width(), y+char_height+2); // white text of selected item SetColor(MENU_SEL_FG); if (menu[i][0]) gr_text(4, y, menu[i], 1); SetColor(MENU); } else { if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top); } y += char_height+4; } SetColor(MENU); y += 4; gr_fill(0, y, gr_fb_width(), y+2); y += 4; ++i; } SetColor(LOG); // display from the bottom up, until we hit the top of the // screen, the bottom of the menu, or we\'ve displayed the // entire text buffer. int ty; int row = (text_top+text_rows-1) % text_rows; for (int ty = gr_fb_height() - char_height, count = 0; ty > y+2 && count < text_rows; ty -= char_height, ++count) { gr_text(4, ty, text[row], 0); --row; if (row < 0) row = text_rows-1; } } }
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 < width-1) { gr_blit(progressBarEmpty, 0, 0, width-pos, height, dx, dy); } } else { // Fill the progress bar from left to right. if (pos > 0) { gr_blit(progressBarFill, 0, 0, pos, height, dx, dy); } if (pos < width-1) { gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy); } } } if (progressBarType == INDETERMINATE) { static int frame = 0; gr_blit(progressBarIndeterminate[frame], 0, 0, width, height, dx, dy); // in RTL locales, we run the animation backwards, which // makes the spinner spin the other way. if (rtl_locale) { frame = (frame + indeterminate_frames - 1) % indeterminate_frames; } else { frame = (frame + 1) % indeterminate_frames; } } } }
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); /* 释放资源数据 */