最近在作一个在recovery中显示文字的工作,所以对这块研究较多,现在把研究的一点新的结果分享出来,如果有什么错误也欢迎大家在下面评论。
Android的Recovery中,利用 boottable/recovery下的minui库作为基础,采用的是直接存取framebuffer的方式,来完成recovery中所需的各种UI的绘制。
在recovery的源码中,跟ui显示相关的代码的大致结构为:
1 boottable/recovery下的 ui.h , ui.cpp, screen_ui.h,screen_ui.cpp,以及 mi_screen_ui.h,**_screen_ui.cpp,
这部分的主要作用是:
1.1 定义并实现几个类,如ScreenRecoveryUI,ScreenRecoveryUI、RecoveryUI,这几个类由抽象到具体一层层继承下来,在recovery.cpp的main中实例化并被使用
1.2 将minui库里resources.cpp,graphics.cpp提供的基本api封装到几个方法中,这几个方法在类中基本被按功能划分,单独负责一个ui单元的显示,如draw_background_locked、draw_battery_locked、draw_logo_locked、draw_progress_locked、draw_progressbar_locked、draw_state_locked等
1.3 之后再将这些方法进一步按照设计需求组合,实现了一些完成更多功能的方法,如SetBackground,ShowProgress
2 boottable/recovery/minui下的resources.cpp,graphics.cpp
其中resources.cpp提供的api主要用于图片资源的读取和加载,graphics.cpp负责具体完成各类ui的绘制
3 recovery下面根据分辨率不同保存的图片资源,如boottable/recovery/res-xxhdpi等
下面我们以android6.0的原生代码为例,对在进入recovery的过程中,各类ui被加载并显示的过程来具体分析
由于之前所述,recovery的UI已经把大部分实现细节放在了screen_ui.cpp等文件中,因此在recovery的main中,要完成ui显示,所需要的操作主要可分为如下几步:
Device* device = make_device();
ui = device->GetUI();
ui->SetLocale(locale);
ui->Init();
ui->SetBackground(RecoveryUI::NONE);
首先在reocvery.cpp的main中,全局变量ui通过Device类的GetUI()返回,由于RecoveryUI为虚基类,因此依次实际执行的是ScreenRecoveryUI中的SetLocale()标识所属区域,保存在全局变量locale中,这个值在原声recovery中显示国际化里的不同地域的文字时起到了重要作用。
SetLocale负责读取系统之前保存的地区信息,并复制给recovery中的全局变量locale。具体过程是先从/cahe/recpvery/command文件中读取, command文件中会设置locale的命令如"-- locale =zh_CN“,如果没有传入locale, 初始化过程中会尝试从/cache/recovery/last_locale中读取locale, 如果该文件也没有,则locale不会被赋值,就默认用English。
然后在ScreenRecoveryUI的Init()中,调用gr_init() 初始化图形设备,加载之后所需要的各种图片资源,将其保存到各类GRSurface结构体中,具体为调用LoadBitmap,将每个png图片存放在一个数组GRsurface数组中,调用LoadLocalizedBitmap,将区域文字所在的图片中的text信息根据当前的locale提取出来,生成对应的surface。在最后,调用pthread_create(&progress_t, NULL, progress_thread, NULL) 创建一个线程,该线程的任务是一个死循环,在该循环中不停检测currentIcon以及progressBarType,以此来决定是否更新进度条
调用ScreenRecoveryUI类的SetBackground()设置初始显示背景,其中重点是update_screen_locked,这个函数的主要作用是刷新屏幕背景。在Recovery中负责显示的部分将会一直调用update_screen_locked或者 update_progress_locked,其中update_progress_locked用来更新进度条。
void ScreenRecoveryUI::update_screen_locked()
{
draw_screen_locked();
gr_flip();
}
主要包含两个操作,一是更新screen, 二是切换前后buffer。
在draw_screen_locked中,将整个渲染buffer填充为黑色,然后计算背景surface的长宽,文字surface的长宽,在调用minui库,计算出整个framebuffer的长宽,结合framebuffer的长宽计算出背景surface以及文字surface显示的坐标,
计算出这些数据后,就可以调用png库进行渲染。
同理,draw_progress_locked函数的原理与 update_screen_locked函数类似, 最终是将进度条的surface输出到渲染buffer。
总体而言,recovery中上层通过调用minui库实现了图形的描绘以及固定大小的文字显示,minui库调用了png库来实现最后的渲染。
下一篇里我打算介绍google在recovery中根据地区信息的不同,来显示国际化文字的一个机制。