Android Recovery Ui 分析

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);       /* 释放资源数据 */

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-06 17:49:11

Android Recovery Ui 分析的相关文章

Android recovery UI实现分析

Android recovery模式为何物? 关于这个问题, baidu上已经有无数的答案.不理解的朋友先补习一下. 从纯技术角度来讲, recovery和android本质上是两个独立的rootfs,  仅仅是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分. recovery作为一个简单的rootfs, 提供了很有限的几个功能,仅仅包括了几个简单的库,UI的显示採用的是直接刷framebuffer的形式,作为andro

Android 5.x OTA Update官方文档(八、图说Recovery UI)

写在前面: 若能直译,不会意译,意译不成,为了选择不误导他人也会漏译无伤大雅的部分,英语是硬伤,如果有误译,请路过的朋友帮忙指正,以免误导更多的朋友. RecoveryUI除了之前提到的标题.选项菜单.提示性文字还有另外的一个重要的成员图片.在正常的更新过程中,用户看到的仅仅是图片(这里指的标准的OTA升级流程,如开机进入recovery模式.安装更新时进度条发生变化,最后再开机进入正常模式),而且在这个过程,用户是没有机会与RecoveryUI进行交互的.但是一旦在更新过程中出现了异常,用户所

Android 5..x OTA Update官方文档(六、定制Recovery UI)

recovery界面 为了支持不同的硬件设备(物理按键.显示.LEDs等),我们可以定制recovery界面进行可视化显示,并进行相关的操作.那么我们可以通过继承bootable/recovery/defalust_device.cpp,并重写相关的函数来为我们的设备进行可视化定制.因此本篇博文旨在为大家介绍如何构建一个能够实现recovery界面定制的静态库.首先来了解西面这段头文件: device/yoyodyne/tardis/recovery/recovery_ui.cpp #inclu

CM android的CMUpdater分析(二)

至于为何要在这里讲解android系统源码中的系统更新,我已经在上一篇< CM android的CMUpdater分析(一)>中介绍了.在上一篇中,主要讲解了在eclipse中如何搭建系统应用的开发环境,现在我们就使用eclipse来分析CMUpdater源码.该系统更新是CM修改原生android的基础上实现的.通过分析android系统的应用源码,可以学到一些很好的思想和编程方法学.好了,废话少说,现在就开始我们的学习之旅. 首先,在开始介绍之前,我先把之前根据CMUpdater源码分析来

Cordova Android源码分析系列一(项目总览和CordovaActivity分析)

PhoneGap/Cordova是一个专业的移动应用开发框架,是一个全面的WEB APP开发的框架,提供了以WEB形式来访问终端设备的API的功能.这对于采用WEB APP进行开发者来说是个福音,这可以避免了原生开发的某些功能.Cordova 只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用. Cordova Android项目是Cordova Android原生部分的Java代码实现,提供了Android原生代码和上层We

Android init源代码分析(2)init.rc解析

本文描述init.rc脚本解析以及执行过程,读完本章后,读者应能 (1) 了解init.rc解析过程 (2) 定制init.rc init.rc介绍 init.rc是一个文本文件,可认为它是Android系统启动脚本.init.rc文件中定义了环境变量配置.系统进程启动,分区挂载,属性配置等诸多内容.init.rc具有特殊的语法.init源码目录下的readme.txt中详细的描述了init启动脚本的语法规则,是试图定制init.rc的开发者的必读资料. Android启动脚本包括一组文件,包括

android原生browser分析(二)--界面篇

我们先看一张浏览器的主界面,上面标示浏览器界面各部分对应的类,这里是以平板上的界面为例.给张图是为了给大家一个直观的感觉. BrowserActivity是整个应用的主界面,在onCreate中创建了Controller对象,Controller对象是整个应用最重要的管理类,这个后面再说. @Override public void onCreate(Bundle icicle) { mController = createController(); } Controller的创建中新建了UI类

Android 之UI自适应解决方案

1.概况 作为Android开发人员,最头疼的莫过于让自己开发的程序在不同终端上面的显示效果看起来尽量一致(当然,如果要充分利用大屏幕的优势另当别论).在全球范围内来讲,android有着数以亿计的设备,其中就不乏设备分辨率多种多样,以及设备屏幕物理尺寸的多样化. 总得来说我们需要做的有三点,其一让APP的每个UI中的每个View宽和高更加灵活以适应不同分辨率.其二对于大屏幕设备(PAD)需要有不同的设计,竟可能多的展示内容,获取你整个APP的所有UI都可以做到一个布局中来.其三图标资源需提供不

Android更新Ui进阶精解(二)

<代码里的世界> 用文字札记描绘自己 android学习之路 转载请保留出处 by Qiao http://blog.csdn.net/qiaoidea/article/details/45115047 Android更新Ui进阶精解(一) android ui线程检查机制 Android更新Ui进阶精解(二) android 线程更新UI机制 1.回顾 第一篇讲了对Ui线程更新的方法和见解,然后接着讲了线程检查机制,这里来详细分析下更新Ui的核心--Android中消息系统模型.当然,这里要