Merge "Add a new option in recovery menu to test the background texts" am: 4c7608f3ca
am: 8874d3c309
Change-Id: I678eb4f5e3ebee72f519bd0a9b3fd76cbcf18d7c
This commit is contained in:
+23
-21
@@ -17,34 +17,36 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
static const char* MENU_ITEMS[] = {
|
static const char* MENU_ITEMS[] = {
|
||||||
"Reboot system now",
|
"Reboot system now",
|
||||||
"Reboot to bootloader",
|
"Reboot to bootloader",
|
||||||
"Apply update from ADB",
|
"Apply update from ADB",
|
||||||
"Apply update from SD card",
|
"Apply update from SD card",
|
||||||
"Wipe data/factory reset",
|
"Wipe data/factory reset",
|
||||||
#ifndef AB_OTA_UPDATER
|
#ifndef AB_OTA_UPDATER
|
||||||
"Wipe cache partition",
|
"Wipe cache partition",
|
||||||
#endif // !AB_OTA_UPDATER
|
#endif // !AB_OTA_UPDATER
|
||||||
"Mount /system",
|
"Mount /system",
|
||||||
"View recovery logs",
|
"View recovery logs",
|
||||||
"Run graphics test",
|
"Run graphics test",
|
||||||
"Power off",
|
"Run locale test",
|
||||||
NULL,
|
"Power off",
|
||||||
|
nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Device::BuiltinAction MENU_ACTIONS[] = {
|
static const Device::BuiltinAction MENU_ACTIONS[] = {
|
||||||
Device::REBOOT,
|
Device::REBOOT,
|
||||||
Device::REBOOT_BOOTLOADER,
|
Device::REBOOT_BOOTLOADER,
|
||||||
Device::APPLY_ADB_SIDELOAD,
|
Device::APPLY_ADB_SIDELOAD,
|
||||||
Device::APPLY_SDCARD,
|
Device::APPLY_SDCARD,
|
||||||
Device::WIPE_DATA,
|
Device::WIPE_DATA,
|
||||||
#ifndef AB_OTA_UPDATER
|
#ifndef AB_OTA_UPDATER
|
||||||
Device::WIPE_CACHE,
|
Device::WIPE_CACHE,
|
||||||
#endif // !AB_OTA_UPDATER
|
#endif // !AB_OTA_UPDATER
|
||||||
Device::MOUNT_SYSTEM,
|
Device::MOUNT_SYSTEM,
|
||||||
Device::VIEW_RECOVERY_LOGS,
|
Device::VIEW_RECOVERY_LOGS,
|
||||||
Device::RUN_GRAPHICS_TEST,
|
Device::RUN_GRAPHICS_TEST,
|
||||||
Device::SHUTDOWN,
|
Device::RUN_LOCALE_TEST,
|
||||||
|
Device::SHUTDOWN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
|
static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class Device {
|
|||||||
VIEW_RECOVERY_LOGS = 9,
|
VIEW_RECOVERY_LOGS = 9,
|
||||||
MOUNT_SYSTEM = 10,
|
MOUNT_SYSTEM = 10,
|
||||||
RUN_GRAPHICS_TEST = 11,
|
RUN_GRAPHICS_TEST = 11,
|
||||||
|
RUN_LOCALE_TEST = 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
|
// Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
//
|
//
|
||||||
// Graphics.
|
// Graphics.
|
||||||
@@ -129,6 +130,9 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface);
|
|||||||
int res_create_localized_alpha_surface(const char* name, const char* locale,
|
int res_create_localized_alpha_surface(const char* name, const char* locale,
|
||||||
GRSurface** pSurface);
|
GRSurface** pSurface);
|
||||||
|
|
||||||
|
// Return a list of locale strings embedded in |png_name|. Return a empty list in case of failure.
|
||||||
|
std::vector<std::string> get_locales_in_png(const std::string& png_name);
|
||||||
|
|
||||||
// Free a surface allocated by any of the res_create_*_surface()
|
// Free a surface allocated by any of the res_create_*_surface()
|
||||||
// functions.
|
// functions.
|
||||||
void res_free_surface(GRSurface* surface);
|
void res_free_surface(GRSurface* surface);
|
||||||
|
|||||||
@@ -396,6 +396,41 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
|
|||||||
return std::regex_match(locale, loc_regex);
|
return std::regex_match(locale, loc_regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> get_locales_in_png(const std::string& png_name) {
|
||||||
|
png_structp png_ptr = nullptr;
|
||||||
|
png_infop info_ptr = nullptr;
|
||||||
|
png_uint_32 width, height;
|
||||||
|
png_byte channels;
|
||||||
|
|
||||||
|
int status = open_png(png_name.c_str(), &png_ptr, &info_ptr, &width, &height, &channels);
|
||||||
|
if (status < 0) {
|
||||||
|
printf("Failed to open %s\n", png_name.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (channels != 1) {
|
||||||
|
printf("Expect input png to have 1 data channel, this file has %d\n", channels);
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::vector<unsigned char> row(width);
|
||||||
|
for (png_uint_32 y = 0; y < height; ++y) {
|
||||||
|
png_read_row(png_ptr, row.data(), nullptr);
|
||||||
|
int h = (row[3] << 8) | row[2];
|
||||||
|
std::string loc(reinterpret_cast<char*>(&row[5]));
|
||||||
|
if (!loc.empty()) {
|
||||||
|
result.push_back(loc);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < h; ++i, ++y) {
|
||||||
|
png_read_row(png_ptr, row.data(), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int res_create_localized_alpha_surface(const char* name,
|
int res_create_localized_alpha_surface(const char* name,
|
||||||
const char* locale,
|
const char* locale,
|
||||||
GRSurface** pSurface) {
|
GRSurface** pSurface) {
|
||||||
|
|||||||
@@ -1191,6 +1191,11 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
|||||||
run_graphics_test();
|
run_graphics_test();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Device::RUN_LOCALE_TEST: {
|
||||||
|
ScreenRecoveryUI* screen_ui = static_cast<ScreenRecoveryUI*>(ui);
|
||||||
|
screen_ui->CheckBackgroundTextImages(locale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Device::MOUNT_SYSTEM:
|
case Device::MOUNT_SYSTEM:
|
||||||
// For a system image built with the root directory (i.e. system_root_image == "true"), we
|
// For a system image built with the root directory (i.e. system_root_image == "true"), we
|
||||||
// mount it to /system_root, and symlink /system to /system_root/system to make adb shell
|
// mount it to /system_root, and symlink /system to /system_root/system to make adb shell
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
@@ -258,6 +260,81 @@ void ScreenRecoveryUI::SetColor(UIElement e) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenRecoveryUI::SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries,
|
||||||
|
size_t sel) {
|
||||||
|
SetLocale(locales_entries[sel]);
|
||||||
|
std::vector<std::string> text_name = { "erasing_text", "error_text", "installing_text",
|
||||||
|
"installing_security_text", "no_command_text" };
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<GRSurface, decltype(&free)>> surfaces;
|
||||||
|
for (const auto& name : text_name) {
|
||||||
|
GRSurface* text_image = nullptr;
|
||||||
|
LoadLocalizedBitmap(name.c_str(), &text_image);
|
||||||
|
if (!text_image) {
|
||||||
|
Print("Failed to load %s\n", name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
surfaces.emplace(name, std::unique_ptr<GRSurface, decltype(&free)>(text_image, &free));
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&updateMutex);
|
||||||
|
gr_color(0, 0, 0, 255);
|
||||||
|
gr_clear();
|
||||||
|
|
||||||
|
int text_y = kMarginHeight;
|
||||||
|
int text_x = kMarginWidth;
|
||||||
|
int line_spacing = gr_sys_font()->char_height; // Put some extra space between images.
|
||||||
|
// Write the header and descriptive texts.
|
||||||
|
SetColor(INFO);
|
||||||
|
std::string header = "Show background text image";
|
||||||
|
text_y += DrawTextLine(text_x, text_y, header.c_str(), true);
|
||||||
|
std::string locale_selection = android::base::StringPrintf(
|
||||||
|
"Current locale: %s, %zu/%zu", locales_entries[sel].c_str(), sel, locales_entries.size());
|
||||||
|
const char* instruction[] = { locale_selection.c_str(),
|
||||||
|
"Use volume up/down to switch locales and power to exit.",
|
||||||
|
nullptr };
|
||||||
|
text_y += DrawWrappedTextLines(text_x, text_y, instruction);
|
||||||
|
|
||||||
|
// Iterate through the text images and display them in order for the current locale.
|
||||||
|
for (const auto& p : surfaces) {
|
||||||
|
text_y += line_spacing;
|
||||||
|
SetColor(LOG);
|
||||||
|
text_y += DrawTextLine(text_x, text_y, p.first.c_str(), false);
|
||||||
|
gr_color(255, 255, 255, 255);
|
||||||
|
gr_texticon(text_x, text_y, p.second.get());
|
||||||
|
text_y += gr_get_height(p.second.get());
|
||||||
|
}
|
||||||
|
// Update the whole screen.
|
||||||
|
gr_flip();
|
||||||
|
pthread_mutex_unlock(&updateMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenRecoveryUI::CheckBackgroundTextImages(const std::string& saved_locale) {
|
||||||
|
// Load a list of locales embedded in one of the resource files.
|
||||||
|
std::vector<std::string> locales_entries = get_locales_in_png("installing_text");
|
||||||
|
if (locales_entries.empty()) {
|
||||||
|
Print("Failed to load locales from the resource files\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t selected = 0;
|
||||||
|
SelectAndShowBackgroundText(locales_entries, selected);
|
||||||
|
|
||||||
|
FlushKeys();
|
||||||
|
while (true) {
|
||||||
|
int key = WaitKey();
|
||||||
|
if (key == KEY_POWER || key == KEY_ENTER) {
|
||||||
|
break;
|
||||||
|
} else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
||||||
|
selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
|
||||||
|
SelectAndShowBackgroundText(locales_entries, selected);
|
||||||
|
} else if (key == KEY_DOWN || key == KEY_VOLUMEDOWN) {
|
||||||
|
selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
|
||||||
|
SelectAndShowBackgroundText(locales_entries, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetLocale(saved_locale);
|
||||||
|
}
|
||||||
|
|
||||||
int ScreenRecoveryUI::DrawHorizontalRule(int y) const {
|
int ScreenRecoveryUI::DrawHorizontalRule(int y) const {
|
||||||
gr_fill(0, y + 4, gr_fb_width(), y + 6);
|
gr_fill(0, y + 4, gr_fb_width(), y + 6);
|
||||||
return 8;
|
return 8;
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
|
|
||||||
void SetColor(UIElement e) const;
|
void SetColor(UIElement e) const;
|
||||||
|
|
||||||
|
// Check the background text image. Use volume up/down button to cycle through the locales
|
||||||
|
// embedded in the png file, and power button to go back to recovery main menu.
|
||||||
|
void CheckBackgroundTextImages(const std::string& saved_locale);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The margin that we don't want to use for showing texts (e.g. round screen, or screen with
|
// The margin that we don't want to use for showing texts (e.g. round screen, or screen with
|
||||||
// rounded corners).
|
// rounded corners).
|
||||||
@@ -199,6 +203,10 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void SetLocale(const std::string&);
|
void SetLocale(const std::string&);
|
||||||
|
|
||||||
|
// Display the background texts for "erasing", "error", "no_command" and "installing" for the
|
||||||
|
// selected locale.
|
||||||
|
void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RECOVERY_UI_H
|
#endif // RECOVERY_UI_H
|
||||||
|
|||||||
Reference in New Issue
Block a user