zoukankan      html  css  js  c++  java
  • 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 = '';
                    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);       /* 释放资源数据 */  
    

  • 相关阅读:
    jQuery事件
    jQuery选择器
    jQuery对象和语法
    jQuery简介
    残差的正态性检验——概率图和QQ-plot图
    https://oldpan.me/深度学习博客
    深度学习的内存消耗在哪里?
    图片缩放
    随机梯度下降批尺寸的影响
    利用PIL.ImageOps.invert实现二值图像黑白反转
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5371988.html
Copyright © 2011-2022 走看看