参考:
Recovery模式下的文本显示
如何修改Recovery的字符串资源
Android recovery UI实现分析
Recovery模式下的文本显示
平台 | android版本 | 内核版本 |
---|---|---|
rtd1619 | 9.0 | 4.9.1 |
源码路径:android/bootable/recovery
需求 :
选择简体中文的情况下,但在ota升级界面文字显示为 繁体。需要调整回来
思路:
1.recovery 所匹配的文字并非是根据语言国家来更改res/xml下的文本文件,而是一个包含各种语言的文本图片 (bootable/recovery/res-hdpi/images/installing_text.png)
2.在制作该文本png图片时候,会记录每种语言每段的信息,(locale,high,width) locale即(语言-国家)的信息
3.在进行recovery 时候,会传入android 环境下的locale ,如果传入的locale和解析png图片的locale相匹配这将这段绘制到surface
- UI加载入口
recover 和bootcode一样是一个简单的rootfs.使用surface直接刷framebuffer 更改界面,先查看 recovery.cpp 的main入口
int main(int argc, char **argv) {
// We don\'t have logcat yet under recovery; so we\'ll print error on screen and
// log to stdout (which is redirected to recovery.log) as we used to do.
android::base::InitLogging(argv, &UiLogger);
...
...
...
while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS,
&option_index)) != -1) {
...
case \'l\':
locale = optarg; //从参数中获取local “语言+国家”的形式
}
}
locale就是我们本文的关键
Device* device = make_device();
if (android::base::GetBoolProperty("ro.boot.quiescent", false)) {
printf("Quiescent recovery mode.\\n");
ui = new StubRecoveryUI();
} else {
ui = device->GetUI();
if (!ui->Init(locale)) {
printf("Failed to initialize UI, use stub UI instead.\\n");
ui = new StubRecoveryUI();
}
...
// Set background string to "installing security update" for security update,
// otherwise set it to "installing system update".
ui->SetSystemUpdateText(security_update); //设置是否为安全更新
}
这里又将locale 传入UI对象
- UI对象查找png文件
源文件 screen_ui.cpp
bool ScreenRecoveryUI::Init(const std::string& locale) {
RecoveryUI::Init(locale);
...
LoadBitmap("icon_error", &error_icon);
LoadBitmap("progress_empty", &progressBarEmpty);
LoadBitmap("progress_fill", &progressBarFill);
LoadBitmap("stage_empty", &stageMarkerEmpty);
LoadBitmap("stage_fill", &stageMarkerFill);
installing_text = nullptr; //这个即我所需要的
LoadLocalizedBitmap("erasing_text", &erasing_text);
LoadLocalizedBitmap("no_command_text", &no_command_text);
LoadLocalizedBitmap("error_text", &error_text);
...
}
...
// Choose the right background string to display during update.
void ScreenRecoveryUI::SetSystemUpdateText(bool security_update) {
if (security_update) {
LoadLocalizedBitmap("installing_security_text", &installing_text);
} else {
LoadLocalizedBitmap("installing_text", &installing_text); //加载图片
}
Redraw();
}
...
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
int result = res_create_localized_alpha_surface(filename, locale_.c_str(), surface);
}
- 加载,分析png图片所需要的段
nt res_create_localized_alpha_surface(const char* name,
const char* locale,
GRSurface** pSurface) {
...
printf(" create surface by native locale area %s\\n", locale);
PngHandler png_handler(name); // 根据installing_text名字加载png
if (!png_handler) return png_handler.error_code();
if (png_handler.channels() != 1) {
return -7;
}
png_structp png_ptr = png_handler.png_ptr(); //获取png每段的信息
png_uint_32 width = png_handler.width();
png_uint_32 height = png_handler.height();
for (png_uint_32 y = 0; y < height; ++y) {
std::vector<unsigned char> row(width);
png_read_row(png_ptr, row.data(), nullptr);
int w = (row[1] << 8) | row[0];
int h = (row[3] << 8) | row[2];
__unused int len = row[4];
char* loc = reinterpret_cast<char*>(&row[5]); //在png格式中第五段是locale信息(语言_国家)
printf(" create surface name %20s\\n", name); //自己加的log信息
printf(" create surface locale %s\\n", locale);
printf(" create surface loc %s\\n", loc);
//matches_locale()即用来匹配传入的locale 信息
if (y + 1 + h >= height || matches_locale(loc, locale)) {
printf("res_create_localized_alpha_surface %20s: %s (%d x %d @ %d)\\n", name, loc, w, h, y);
GRSurface* surface = malloc_surface(w * h);
if (!surface) {
return -8;
}
//加载符合的数据到surface
surface->width = w;
surface->height = h;
surface->row_bytes = w;
surface->pixel_bytes = 1;
for (int i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row.data(), nullptr);
memcpy(surface->data + i * w, row.data(), w);
}
*pSurface = surface;
break;
}
for (int i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row.data(), nullptr);
}
}
return 0;
}
这里需要看自身的log信息看png的locale信息
比如这里我的设置中文简体情况为:
png locale: zh_CN
传入的 locale:zh-CN这里有个问题就是:在解析台湾字段时段为
png locale :zh //看备注所以直接匹配到了繁体
所以我们需要更改匹配规则
- 如何比较locale信息
index 52ab60b..b5cc62f 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -397,15 +397,22 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
// match the locale string without the {script} section.
// For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale
// == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN".
+ // prefix == "zh_CN" matches locale == "zh-Hans-CN".
if (android::base::StartsWith(locale, prefix)) {
return true;
}
- size_t separator = prefix.find(\'-\');
+ size_t separator = prefix.find(\'_\');
if (separator == std::string::npos) {
+
return false;
}
- std::regex loc_regex(prefix.substr(0, separator) + "-[A-Za-z]*" + prefix.substr(separator));
+ if( prefix.substr(separator+1).empty()){
+ return false;
+ }
+ std::regex loc_regex(prefix.substr(0, separator) + "-[A-Za-z]*" + prefix.substr(separator+1));
return std::regex_match(locale, loc_regex);
}
- 以上就是修改内容
备注
- 如何自己生成png图片
在android 下面已经有源码 直接生成apk,再有apk生成png
android/bootable/recovery/tools/recovery_l10n
具体操作可以看
- c++ 的std::regex 类需要学习
- png 数据分析 需要学习
PngHandler::PngHandler(const std::string& name) : error_code_(0), png_fp_(nullptr, fclose) {
std::string res_path = android::base::StringPrintf("/res/images/%s.png", name.c_str());
png_fp_.reset(fopen(res_path.c_str(), "rbe"));
if (!png_fp_) {
error_code_ = -1;
return;
}
unsigned char header[8];
size_t bytesRead = fread(header, 1, sizeof(header), png_fp_.get());
if (bytesRead != sizeof(header)) {
error_code_ = -2;
return;
}
if (png_sig_cmp(header, 0, sizeof(header))) {
error_code_ = -3;
return;
}
png_ptr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr_) {
error_code_ = -4;
return;
}
info_ptr_ = png_create_info_struct(png_ptr_);
if (!info_ptr_) {
error_code_ = -5;
return;
}
if (setjmp(png_jmpbuf(png_ptr_))) {
error_code_ = -6;
return;
}
png_init_io(png_ptr_, png_fp_.get());
png_set_sig_bytes(png_ptr_, sizeof(header));
png_read_info(png_ptr_, info_ptr_);
int color_type;
int bit_depth;
png_get_IHDR(png_ptr_, info_ptr_, &width_, &height_, &bit_depth, &color_type, nullptr, nullptr,
nullptr);
channels_ = png_get_channels(png_ptr_, info_ptr_);
if (bit_depth == 8 && channels_ == 3 && color_type == PNG_COLOR_TYPE_RGB) {
// 8-bit RGB images: great, nothing to do.
} else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
// 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
png_set_expand_gray_1_2_4_to_8(png_ptr_);
} else if (bit_depth <= 8 && channels_ == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
// paletted images: expand to 8-bit RGB. Note that we DON\'T
// currently expand the tRNS chunk (if any) to an alpha
// channel, because minui doesn\'t support alpha channels in
// general.
png_set_palette_to_rgb(png_ptr_);
channels_ = 3;
} else {
fprintf(stderr, "minui doesn\'t support PNG depth %d channels %d color_type %d\\n", bit_depth,
channels_, color_type);
error_code_ = -7;
}
}