aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--device.cpp160
-rw-r--r--device.h45
-rw-r--r--minui/graphics.cpp11
-rw-r--r--minui/include/minui/minui.h1
-rw-r--r--recovery.cpp157
-rw-r--r--res-hdpi/images/ic_back.pngbin0 -> 217 bytes
-rw-r--r--res-hdpi/images/ic_back_sel.pngbin0 -> 226 bytes
-rw-r--r--res-hdpi/images/ic_factory_reset.pngbin0 -> 352 bytes
-rw-r--r--res-hdpi/images/ic_factory_reset_sel.pngbin0 -> 365 bytes
-rw-r--r--res-hdpi/images/ic_options_advanced.pngbin0 -> 356 bytes
-rw-r--r--res-hdpi/images/ic_options_advanced_sel.pngbin0 -> 360 bytes
-rw-r--r--res-hdpi/images/ic_reboot.pngbin0 -> 352 bytes
-rw-r--r--res-hdpi/images/ic_reboot_sel.pngbin0 -> 360 bytes
-rw-r--r--res-hdpi/images/ic_system_update.pngbin0 -> 272 bytes
-rw-r--r--res-hdpi/images/ic_system_update_sel.pngbin0 -> 278 bytes
-rw-r--r--res-hdpi/images/logo_image.pngbin0 -> 15773 bytes
-rw-r--r--res-mdpi/images/ic_back.pngbin0 -> 190 bytes
-rw-r--r--res-mdpi/images/ic_back_sel.pngbin0 -> 174 bytes
-rw-r--r--res-mdpi/images/ic_factory_reset.pngbin0 -> 270 bytes
-rw-r--r--res-mdpi/images/ic_factory_reset_sel.pngbin0 -> 279 bytes
-rw-r--r--res-mdpi/images/ic_options_advanced.pngbin0 -> 286 bytes
-rw-r--r--res-mdpi/images/ic_options_advanced_sel.pngbin0 -> 291 bytes
-rw-r--r--res-mdpi/images/ic_reboot.pngbin0 -> 266 bytes
-rw-r--r--res-mdpi/images/ic_reboot_sel.pngbin0 -> 277 bytes
-rw-r--r--res-mdpi/images/ic_system_update.pngbin0 -> 217 bytes
-rw-r--r--res-mdpi/images/ic_system_update_sel.pngbin0 -> 220 bytes
-rw-r--r--res-mdpi/images/logo_image.pngbin0 -> 8653 bytes
-rw-r--r--res-xhdpi/images/ic_back.pngbin0 -> 276 bytes
-rw-r--r--res-xhdpi/images/ic_back_sel.pngbin0 -> 286 bytes
-rw-r--r--res-xhdpi/images/ic_factory_reset.pngbin0 -> 488 bytes
-rw-r--r--res-xhdpi/images/ic_factory_reset_sel.pngbin0 -> 500 bytes
-rw-r--r--res-xhdpi/images/ic_options_advanced.pngbin0 -> 509 bytes
-rw-r--r--res-xhdpi/images/ic_options_advanced_sel.pngbin0 -> 507 bytes
-rw-r--r--res-xhdpi/images/ic_reboot.pngbin0 -> 470 bytes
-rw-r--r--res-xhdpi/images/ic_reboot_sel.pngbin0 -> 482 bytes
-rw-r--r--res-xhdpi/images/ic_system_update.pngbin0 -> 350 bytes
-rw-r--r--res-xhdpi/images/ic_system_update_sel.pngbin0 -> 355 bytes
-rw-r--r--res-xhdpi/images/logo_image.pngbin0 -> 10117 bytes
-rw-r--r--res-xxhdpi/images/font_menu.pngbin0 -> 65852 bytes
-rw-r--r--res-xxhdpi/images/ic_back.pngbin0 -> 364 bytes
-rw-r--r--res-xxhdpi/images/ic_back_sel.pngbin0 -> 373 bytes
-rw-r--r--res-xxhdpi/images/ic_factory_reset.pngbin0 -> 693 bytes
-rw-r--r--res-xxhdpi/images/ic_factory_reset_sel.pngbin0 -> 704 bytes
-rw-r--r--res-xxhdpi/images/ic_options_advanced.pngbin0 -> 738 bytes
-rw-r--r--res-xxhdpi/images/ic_options_advanced_sel.pngbin0 -> 717 bytes
-rw-r--r--res-xxhdpi/images/ic_reboot.pngbin0 -> 698 bytes
-rw-r--r--res-xxhdpi/images/ic_reboot_sel.pngbin0 -> 708 bytes
-rw-r--r--res-xxhdpi/images/ic_system_update.pngbin0 -> 501 bytes
-rw-r--r--res-xxhdpi/images/ic_system_update_sel.pngbin0 -> 509 bytes
-rw-r--r--res-xxhdpi/images/logo_image.pngbin0 -> 40521 bytes
-rw-r--r--res-xxxhdpi/images/ic_back.pngbin0 -> 452 bytes
-rw-r--r--res-xxxhdpi/images/ic_back_sel.pngbin0 -> 463 bytes
-rw-r--r--res-xxxhdpi/images/ic_factory_reset.pngbin0 -> 883 bytes
-rw-r--r--res-xxxhdpi/images/ic_factory_reset_sel.pngbin0 -> 898 bytes
-rw-r--r--res-xxxhdpi/images/ic_options_advanced.pngbin0 -> 868 bytes
-rw-r--r--res-xxxhdpi/images/ic_options_advanced_sel.pngbin0 -> 853 bytes
-rw-r--r--res-xxxhdpi/images/ic_reboot.pngbin0 -> 946 bytes
-rw-r--r--res-xxxhdpi/images/ic_reboot_sel.pngbin0 -> 941 bytes
-rw-r--r--res-xxxhdpi/images/ic_system_update.pngbin0 -> 653 bytes
-rw-r--r--res-xxxhdpi/images/ic_system_update_sel.pngbin0 -> 660 bytes
-rw-r--r--res-xxxhdpi/images/logo_image.pngbin0 -> 75801 bytes
-rw-r--r--screen_ui.cpp496
-rw-r--r--screen_ui.h63
-rw-r--r--stub_ui.h15
-rw-r--r--ui.cpp234
-rw-r--r--ui.h105
-rw-r--r--wear_ui.cpp58
-rw-r--r--wear_ui.h10
68 files changed, 1017 insertions, 338 deletions
diff --git a/device.cpp b/device.cpp
index d43fd754..2d57047d 100644
--- a/device.cpp
+++ b/device.cpp
@@ -16,58 +16,140 @@
#include "device.h"
-static const char* MENU_ITEMS[] = {
- "Reboot system now",
-#ifdef DOWNLOAD_MODE
- "Reboot to download mode",
-#else
- "Reboot to bootloader",
-#endif
- "Apply update",
+#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
+
+// *** Main menu ***
+static const menu_type_t MAIN_MENU_TYPE = MT_GRID;
+static const MenuItem MAIN_MENU_ITEMS[] = {
+ MenuItem("Reboot", "ic_reboot", "ic_reboot_sel"),
+ MenuItem("Apply update", "ic_system_update", "ic_system_update_sel"),
+ MenuItem("Factory reset", "ic_factory_reset", "ic_factory_reset_sel"),
+ MenuItem("Advanced", "ic_options_advanced", "ic_options_advanced_sel"),
+};
+static const MenuItemVector main_menu_items_ =
+ MenuItemVector(MAIN_MENU_ITEMS,
+ MAIN_MENU_ITEMS + ARRAY_SIZE(MAIN_MENU_ITEMS));
+static const Device::BuiltinAction MAIN_MENU_ACTIONS[] = {
+ Device::REBOOT,
+ Device::APPLY_UPDATE,
+ Device::WIPE_MENU,
+ Device::ADVANCED_MENU,
+};
+static const Device::MenuActionVector main_menu_actions_ =
+ Device::MenuActionVector(MAIN_MENU_ACTIONS,
+ MAIN_MENU_ACTIONS + ARRAY_SIZE(MAIN_MENU_ACTIONS));
+static_assert(ARRAY_SIZE(MAIN_MENU_ITEMS) ==
+ ARRAY_SIZE(MAIN_MENU_ACTIONS),
+ "MAIN_MENU_ITEMS and MAIN_MENU_ACTIONS should have the same length.");
+
+
+// *** Wipe menu ***
+static const menu_type_t WIPE_MENU_TYPE = MT_LIST;
+static const MenuItem WIPE_MENU_ITEMS[] = {
#ifndef RELEASE_BUILD
- "Wipe data (keep media)",
+ MenuItem("Wipe data (keep media)"),
#endif
- "Full factory reset",
+ MenuItem("Full factory reset"),
#ifndef AB_OTA_UPDATER
- "Wipe cache partition",
-#endif // !AB_OTA_UPDATER
- "Wipe system partition",
- "Mount /system",
- "View recovery logs",
- "Run graphics test",
- "Power off",
- NULL,
+ MenuItem("Wipe cache"),
+#endif
+ MenuItem("Wipe system"),
};
-
-static const Device::BuiltinAction MENU_ACTIONS[] = {
- Device::REBOOT,
- Device::REBOOT_BOOTLOADER,
- Device::APPLY_UPDATE,
+static const MenuItemVector wipe_menu_items_ =
+ MenuItemVector(WIPE_MENU_ITEMS,
+ WIPE_MENU_ITEMS + ARRAY_SIZE(WIPE_MENU_ITEMS));
+static const Device::BuiltinAction WIPE_MENU_ACTIONS[] = {
#ifndef RELEASE_BUILD
- Device::WIPE_DATA,
+ Device::WIPE_DATA,
#endif
- Device::WIPE_FULL,
+ Device::WIPE_FULL,
#ifndef AB_OTA_UPDATER
- Device::WIPE_CACHE,
-#endif // !AB_OTA_UPDATER
- Device::WIPE_SYSTEM,
- Device::MOUNT_SYSTEM,
- Device::VIEW_RECOVERY_LOGS,
- Device::RUN_GRAPHICS_TEST,
- Device::SHUTDOWN,
+ Device::WIPE_CACHE,
+#endif
+ Device::WIPE_SYSTEM,
};
+static const Device::MenuActionVector wipe_menu_actions_ =
+ Device::MenuActionVector(WIPE_MENU_ACTIONS,
+ WIPE_MENU_ACTIONS + ARRAY_SIZE(WIPE_MENU_ACTIONS));
+static_assert(ARRAY_SIZE(WIPE_MENU_ITEMS) ==
+ ARRAY_SIZE(WIPE_MENU_ACTIONS),
+ "WIPE_MENU_ITEMS and WIPE_MENU_ACTIONS should have the same length.");
+
-static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
- sizeof(MENU_ACTIONS) / sizeof(MENU_ACTIONS[0]) + 1,
- "MENU_ITEMS and MENU_ACTIONS should have the same length, "
- "except for the extra NULL entry in MENU_ITEMS.");
+// *** Advanced menu
+static const menu_type_t ADVANCED_MENU_TYPE = MT_LIST;
-const char* const* Device::GetMenuItems() {
- return MENU_ITEMS;
+static const MenuItem ADVANCED_MENU_ITEMS[] = {
+#ifdef DOWNLOAD_MODE
+ MenuItem("Reboot to download mode"),
+#else
+ MenuItem("Reboot to bootloader"),
+#endif
+ MenuItem("Mount system"),
+ MenuItem("View logs"),
+ MenuItem("Run graphics test"),
+ MenuItem("Power off"),
+};
+static const MenuItemVector advanced_menu_items_ =
+ MenuItemVector(ADVANCED_MENU_ITEMS,
+ ADVANCED_MENU_ITEMS + ARRAY_SIZE(ADVANCED_MENU_ITEMS));
+
+static const Device::BuiltinAction ADVANCED_MENU_ACTIONS[] = {
+ Device::REBOOT_BOOTLOADER,
+ Device::MOUNT_SYSTEM,
+ Device::VIEW_RECOVERY_LOGS,
+ Device::RUN_GRAPHICS_TEST,
+ Device::SHUTDOWN,
+};
+static const Device::MenuActionVector advanced_menu_actions_ =
+ Device::MenuActionVector(ADVANCED_MENU_ACTIONS,
+ ADVANCED_MENU_ACTIONS + ARRAY_SIZE(ADVANCED_MENU_ACTIONS));
+
+static_assert(ARRAY_SIZE(ADVANCED_MENU_ITEMS) ==
+ ARRAY_SIZE(ADVANCED_MENU_ACTIONS),
+ "ADVANCED_MENU_ITEMS and ADVANCED_MENU_ACTIONS should have the same length.");
+
+
+Device::Device(RecoveryUI* ui) :
+ ui_(ui)
+{
+ GoHome();
}
Device::BuiltinAction Device::InvokeMenuItem(int menu_position) {
- return menu_position < 0 ? NO_ACTION : MENU_ACTIONS[menu_position];
+ if (menu_position < 0) {
+ if (menu_position == Device::kGoBack ||
+ menu_position == Device::kGoHome) {
+ // Assume only two menu levels, so back is equivalent to home.
+ GoHome();
+ }
+ return NO_ACTION;
+ }
+ BuiltinAction action = menu_actions_.at(menu_position);
+ switch (action) {
+ case WIPE_MENU:
+ menu_is_main_ = false;
+ menu_type_ = WIPE_MENU_TYPE;
+ menu_items_ = wipe_menu_items_;
+ menu_actions_ = wipe_menu_actions_;
+ break;
+ case ADVANCED_MENU:
+ menu_is_main_ = false;
+ menu_type_ = ADVANCED_MENU_TYPE;
+ menu_items_ = advanced_menu_items_;
+ menu_actions_ = advanced_menu_actions_;
+ break;
+ default:
+ break; // Fall through
+ }
+ return action;
+}
+
+void Device::GoHome() {
+ menu_is_main_ = true;
+ menu_type_ = MAIN_MENU_TYPE;
+ menu_items_ = main_menu_items_;
+ menu_actions_ = main_menu_actions_;
}
int Device::HandleMenuKey(int key, bool visible) {
diff --git a/device.h b/device.h
index afdac96b..a5fc16f0 100644
--- a/device.h
+++ b/device.h
@@ -21,7 +21,7 @@
class Device : public VoldWatcher {
public:
- explicit Device(RecoveryUI* ui) : ui_(ui) {}
+ explicit Device(RecoveryUI* ui);
virtual ~Device() {}
// Called to obtain the UI object that should be used to display the recovery user interface for
@@ -55,24 +55,32 @@ class Device : public VoldWatcher {
enum BuiltinAction {
NO_ACTION = 0,
+ // Main menu
REBOOT = 1,
APPLY_UPDATE = 2,
- // APPLY_CACHE was 3.
- // APPLY_ADB_SIDELOAD was 4.
- WIPE_DATA = 5,
- WIPE_FULL = 6,
- WIPE_CACHE = 7,
- WIPE_SYSTEM = 8,
- REBOOT_BOOTLOADER = 9,
- SHUTDOWN = 10,
- VIEW_RECOVERY_LOGS = 11,
- MOUNT_SYSTEM = 12,
- RUN_GRAPHICS_TEST = 13,
+ WIPE_MENU = 3,
+ ADVANCED_MENU = 4,
+ // Wipe menu
+ WIPE_DATA = 10,
+ WIPE_FULL = 11,
+ WIPE_CACHE = 12,
+ WIPE_SYSTEM = 13,
+ // Advanced menu
+ REBOOT_BOOTLOADER = 20,
+ MOUNT_SYSTEM = 21,
+ VIEW_RECOVERY_LOGS = 22,
+ RUN_GRAPHICS_TEST = 23,
+ SHUTDOWN = 24,
};
- // Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
- // to InvokeMenuItem will correspond to the indexes into this array.
- virtual const char* const* GetMenuItems();
+ typedef std::vector<MenuItem> MenuItemVector;
+ typedef std::vector<BuiltinAction> MenuActionVector;
+
+ // Return the menu properties. The menu_position passed to InvokeMenuItem
+ // will correspond to the indexes in the associated vectors.
+ virtual bool IsMainMenu() const { return menu_is_main_; }
+ virtual menu_type_t GetMenuType() const { return menu_type_; }
+ virtual const MenuItemVector& GetMenuItems() const { return menu_items_; }
// Perform a recovery action selected from the menu. 'menu_position' will be the item number of
// the selected menu item, or a non-negative number returned from HandleMenuKey(). The menu will
@@ -82,6 +90,8 @@ class Device : public VoldWatcher {
// here and return NO_ACTION.
virtual BuiltinAction InvokeMenuItem(int menu_position);
+ virtual void GoHome();
+
static const int kNoAction = -1;
static const int kHighlightUp = -2;
static const int kHighlightDown = -3;
@@ -115,6 +125,11 @@ class Device : public VoldWatcher {
private:
RecoveryUI* ui_;
+
+ bool menu_is_main_;
+ menu_type_t menu_type_;
+ MenuItemVector menu_items_;
+ MenuActionVector menu_actions_;
};
// The device-specific library must define this function (or the default one will be used, if there
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index 3bfce11d..e9c2699d 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -29,6 +29,7 @@
#include "minui/minui.h"
static GRFont* gr_font = NULL;
+static GRFont* gr_font_menu = NULL;
static MinuiBackend* gr_backend = nullptr;
static int overscan_percent = OVERSCAN_PERCENT;
@@ -52,6 +53,11 @@ const GRFont* gr_sys_font()
return gr_font;
}
+const GRFont* gr_menu_font()
+{
+ return gr_font_menu;
+}
+
int gr_measure(const GRFont* font, const char *s)
{
return font->char_width * strlen(s);
@@ -284,6 +290,11 @@ static void gr_init_font(void)
{
int res = gr_init_font("font", &gr_font);
if (res == 0) {
+ res = gr_init_font("font_menu", &gr_font_menu);
+ if (res != 0) {
+ printf("failed to read menu font\n");
+ gr_font_menu = gr_font;
+ }
return;
}
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 4daccab2..9bcc394c 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -56,6 +56,7 @@ void gr_fill(int x1, int y1, int x2, int y2);
void gr_texticon(int x, int y, GRSurface* icon);
const GRFont* gr_sys_font();
+const GRFont* gr_menu_font();
int gr_init_font(const char* name, GRFont** dest);
void gr_text(const GRFont* font, int x, int y, const char *s, bool bold);
int gr_measure(const GRFont* font, const char *s);
diff --git a/recovery.cpp b/recovery.cpp
index abc1fe7c..9e42266e 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -666,18 +666,22 @@ static bool erase_volume(const char* volume, bool force = false) {
// return a positive number beyond the given range. Caller sets 'menu_only' to true to ensure only
// a menu item gets selected. 'initial_selection' controls the initial cursor location. Returns the
// (non-negative) chosen item number, or -1 if timed out waiting for input.
-int get_menu_selection(const char* const* headers, const char* const* items, bool menu_only,
+int get_menu_selection(bool menu_is_main,
+ menu_type_t menu_type,
+ const char* const* headers,
+ const MenuItemVector& menu_items,
+ bool menu_only,
int initial_selection, Device* device) {
// Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
ui->FlushKeys();
- ui->StartMenu(headers, items, initial_selection);
+ ui->StartMenu(menu_is_main, menu_type, headers, menu_items, initial_selection);
int selected = initial_selection;
int chosen_item = -1;
while (chosen_item < 0) {
- int key = ui->WaitKey();
- if (key == -1) { // WaitKey() timed out.
+ RecoveryUI::InputEvent evt = ui->WaitInputEvent();
+ if (evt.type() == RecoveryUI::EVENT_TYPE_NONE) { // WaitKey() timed out.
if (ui->WasTextEverVisible()) {
continue;
} else {
@@ -687,8 +691,21 @@ int get_menu_selection(const char* const* headers, const char* const* items, boo
}
}
- bool visible = ui->IsTextVisible();
- int action = device->HandleMenuKey(key, visible);
+ int action = Device::kNoAction;
+ if (evt.type() == RecoveryUI::EVENT_TYPE_TOUCH) {
+ int touch_sel = ui->SelectMenu(evt.pos());
+ if (touch_sel < 0) {
+ action = touch_sel;
+ }
+ else {
+ action = Device::kInvokeItem;
+ selected = touch_sel;
+ }
+ }
+ else {
+ bool visible = ui->IsTextVisible();
+ action = device->HandleMenuKey(evt.key(), visible);
+ }
if (action < 0) {
switch (action) {
@@ -724,6 +741,9 @@ int get_menu_selection(const char* const* headers, const char* const* items, boo
}
ui->EndMenu();
+ if (chosen_item == Device::kGoHome) {
+ device->GoHome();
+ }
return chosen_item;
}
@@ -757,17 +777,17 @@ static std::string browse_directory(const std::string& path, Device* device) {
// Append dirs to the zips list.
zips.insert(zips.end(), dirs.begin(), dirs.end());
- const char* entries[zips.size() + 1];
- entries[zips.size()] = nullptr;
+ MenuItemVector items;
for (size_t i = 0; i < zips.size(); i++) {
- entries[i] = zips[i].c_str();
+ items.push_back(MenuItem(zips[i]));
}
const char* headers[] = { "Choose a package to install:", path.c_str(), nullptr };
int chosen_item = 0;
while (true) {
- chosen_item = get_menu_selection(headers, entries, true, chosen_item, device);
+ chosen_item = get_menu_selection(false, MT_LIST, headers, items,
+ true, chosen_item, device);
if (chosen_item == Device::kGoHome) {
return "@";
}
@@ -798,9 +818,13 @@ static std::string browse_directory(const std::string& path, Device* device) {
static bool yes_no(Device* device, const char* question1, const char* question2) {
const char* headers[] = { question1, question2, NULL };
- const char* items[] = { " No", " Yes", NULL };
+ const MenuItemVector items = {
+ MenuItem(" No"),
+ MenuItem(" Yes"),
+ };
- int chosen_item = get_menu_selection(headers, items, true, 0, device);
+ int chosen_item = get_menu_selection(false, MT_LIST, headers, items,
+ true, 0, device);
return (chosen_item == 1);
}
@@ -831,13 +855,14 @@ static bool prompt_and_wipe_data(Device* device) {
"stored on this device.",
nullptr
};
- const char* const items[] = {
- "Try again",
- "Factory data reset",
- NULL
+ const MenuItemVector items = {
+ MenuItem("Try again"),
+ MenuItem("Factory data reset"),
};
+
for (;;) {
- int chosen_item = get_menu_selection(headers, items, true, 0, device);
+ int chosen_item = get_menu_selection(false, MT_LIST, headers, items,
+ true, 0, device);
if (chosen_item != 1) {
return true; // Just reboot, no wipe; not a failure, user asked for it
}
@@ -1021,8 +1046,11 @@ static bool wipe_ab_device(size_t wipe_package_size) {
return true;
}
-static void choose_recovery_file(Device* device) {
+static int choose_recovery_file(Device* device) {
std::vector<std::string> entries;
+ if (access(TEMPORARY_LOG_FILE, R_OK) != -1) {
+ entries.push_back(TEMPORARY_LOG_FILE);
+ }
if (has_cache) {
for (int i = 0; i < KEEP_LOG_COUNT; i++) {
auto add_to_entries = [&](const char* filename) {
@@ -1042,34 +1070,34 @@ static void choose_recovery_file(Device* device) {
// Add LAST_KMSG_FILE + LAST_KMSG_FILE.x
add_to_entries(LAST_KMSG_FILE);
}
- } else {
- // If cache partition is not found, view /tmp/recovery.log instead.
- if (access(TEMPORARY_LOG_FILE, R_OK) == -1) {
- return;
- } else {
- entries.push_back(TEMPORARY_LOG_FILE);
- }
+ }
+ if (entries.empty()) {
+ // Should never happen
+ return Device::kNoAction;
}
- entries.push_back("Back");
-
- std::vector<const char*> menu_entries(entries.size());
- std::transform(entries.cbegin(), entries.cend(), menu_entries.begin(),
- [](const std::string& entry) { return entry.c_str(); });
- menu_entries.push_back(nullptr);
+ MenuItemVector items(entries.size());
+ std::transform(entries.cbegin(), entries.cend(), items.begin(),
+ [](const std::string& entry) { return MenuItem(entry.c_str()); });
const char* headers[] = { "Select file to view", nullptr };
int chosen_item = 0;
while (true) {
- chosen_item = get_menu_selection(headers, menu_entries.data(), true, chosen_item, device);
+ chosen_item = get_menu_selection(false, MT_LIST, headers, items,
+ true, chosen_item, device);
if (chosen_item == Device::kGoHome ||
chosen_item == Device::kGoBack || chosen_item == 0) {
break;
}
- ui->ShowFile(entries[chosen_item].c_str());
+ int key = ui->ShowFile(entries[chosen_item].c_str());
+ if (key == KEY_HOME || key == KEY_HOMEPAGE) {
+ chosen_item = Device::kGoHome;
+ break;
+ }
}
+ return chosen_item;
}
static void run_graphics_test() {
@@ -1156,43 +1184,35 @@ static int apply_from_storage(Device* device, const std::string& id, bool* wipe_
static int
show_apply_update_menu(Device* device, bool* wipe_cache) {
+ MenuItemVector items;
static const char* headers[] = { "Apply update", nullptr };
- char* menu_items[MAX_NUM_MANAGED_VOLUMES + 1 + 1];
std::vector<VolumeInfo> volumes = vdc->getVolumes();
- const int item_sideload = 0;
- int n, i;
- std::vector<VolumeInfo>::iterator vitr;
-
refresh:
- menu_items[item_sideload] = strdup("Apply from ADB");
+ items.push_back(MenuItem("Apply from ADB")); // Index 0
- n = item_sideload + 1;
- for (vitr = volumes.begin(); vitr != volumes.end(); ++vitr) {
- menu_items[n] = (char*)malloc(256);
- sprintf(menu_items[n], "Choose from %s", vitr->mLabel.c_str());
- ++n;
+ for (auto& vol : volumes) {
+ items.push_back(MenuItem("Choose from " + vol.mLabel));
}
- menu_items[n] = nullptr;
int status = INSTALL_ERROR;
- int chosen = get_menu_selection(headers, menu_items, 0, 0, device);
- for (i = 0; i < n; ++i) {
- free(menu_items[i]);
- }
+ int chosen = get_menu_selection(false, MT_LIST, headers, items,
+ false, 0, device);
if (chosen == Device::kRefresh) {
goto refresh;
}
- if (chosen == Device::kGoBack) {
+ if (chosen == Device::kGoBack ||
+ chosen == Device::kGoHome) {
return INSTALL_NONE;
}
- if (chosen == item_sideload) {
- static const char* headers[] = { "ADB Sideload", nullptr };
- static const char* list[] = { "Cancel sideload", nullptr };
+ if (chosen == 0) {
+ static const char* s_headers[] = { "ADB Sideload", nullptr };
+ static const MenuItemVector s_items = { MenuItem("Cancel sideload") };
start_sideload(ui, wipe_cache, TEMPORARY_INSTALL_FILE);
- int item = get_menu_selection(headers, list, 0, 0, device);
+ int item = get_menu_selection(false, MT_LIST, s_headers, s_items,
+ false, 0, device);
if (item != Device::kNoAction) {
stop_sideload();
}
@@ -1224,11 +1244,17 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
}
ui->SetProgressType(RecoveryUI::EMPTY);
- int chosen_item = get_menu_selection(nullptr, device->GetMenuItems(), false, 0, device);
- // We are already in the main menu
+ int chosen_item = get_menu_selection(device->IsMainMenu(),
+ device->GetMenuType(),
+ nullptr,
+ device->GetMenuItems(),
+ false, 0, device);
if (chosen_item == Device::kGoBack ||
- chosen_item == Device::kGoHome ||
- chosen_item == Device::kRefresh) {
+ chosen_item == Device::kGoHome) {
+ device->GoHome();
+ continue;
+ }
+ if (chosen_item == Device::kRefresh) {
continue;
}
@@ -1240,6 +1266,8 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
bool should_wipe_cache = false;
switch (chosen_action) {
case Device::NO_ACTION:
+ case Device::WIPE_MENU:
+ case Device::ADVANCED_MENU:
break;
case Device::REBOOT:
@@ -1289,13 +1317,13 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
{
status = show_apply_update_menu(device, &should_wipe_cache);
- if (status == INSTALL_SUCCESS && should_wipe_cache) {
- if (!wipe_cache(false, device)) {
- status = INSTALL_ERROR;
+ if (status != INSTALL_NONE) {
+ if (status == INSTALL_SUCCESS && should_wipe_cache) {
+ if (!wipe_cache(false, device)) {
+ status = INSTALL_ERROR;
+ }
}
- }
- if (status > 0 && status != INSTALL_NONE) {
if (status != INSTALL_SUCCESS) {
ui->SetBackground(RecoveryUI::ERROR);
ui->Print("Installation aborted.\n");
@@ -1311,6 +1339,9 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
case Device::VIEW_RECOVERY_LOGS:
choose_recovery_file(device);
+ if (chosen_item == Device::kGoHome) {
+ device->GoHome();
+ }
break;
case Device::RUN_GRAPHICS_TEST:
diff --git a/res-hdpi/images/ic_back.png b/res-hdpi/images/ic_back.png
new file mode 100644
index 00000000..ec1ea23e
--- /dev/null
+++ b/res-hdpi/images/ic_back.png
Binary files differ
diff --git a/res-hdpi/images/ic_back_sel.png b/res-hdpi/images/ic_back_sel.png
new file mode 100644
index 00000000..2b154d13
--- /dev/null
+++ b/res-hdpi/images/ic_back_sel.png
Binary files differ
diff --git a/res-hdpi/images/ic_factory_reset.png b/res-hdpi/images/ic_factory_reset.png
new file mode 100644
index 00000000..f7b85671
--- /dev/null
+++ b/res-hdpi/images/ic_factory_reset.png
Binary files differ
diff --git a/res-hdpi/images/ic_factory_reset_sel.png b/res-hdpi/images/ic_factory_reset_sel.png
new file mode 100644
index 00000000..94222d0b
--- /dev/null
+++ b/res-hdpi/images/ic_factory_reset_sel.png
Binary files differ
diff --git a/res-hdpi/images/ic_options_advanced.png b/res-hdpi/images/ic_options_advanced.png
new file mode 100644
index 00000000..940709ca
--- /dev/null
+++ b/res-hdpi/images/ic_options_advanced.png
Binary files differ
diff --git a/res-hdpi/images/ic_options_advanced_sel.png b/res-hdpi/images/ic_options_advanced_sel.png
new file mode 100644
index 00000000..510731a4
--- /dev/null
+++ b/res-hdpi/images/ic_options_advanced_sel.png
Binary files differ
diff --git a/res-hdpi/images/ic_reboot.png b/res-hdpi/images/ic_reboot.png
new file mode 100644
index 00000000..f46f8342
--- /dev/null
+++ b/res-hdpi/images/ic_reboot.png
Binary files differ
diff --git a/res-hdpi/images/ic_reboot_sel.png b/res-hdpi/images/ic_reboot_sel.png
new file mode 100644
index 00000000..cbeeeff8
--- /dev/null
+++ b/res-hdpi/images/ic_reboot_sel.png
Binary files differ
diff --git a/res-hdpi/images/ic_system_update.png b/res-hdpi/images/ic_system_update.png
new file mode 100644
index 00000000..0f592577
--- /dev/null
+++ b/res-hdpi/images/ic_system_update.png
Binary files differ
diff --git a/res-hdpi/images/ic_system_update_sel.png b/res-hdpi/images/ic_system_update_sel.png
new file mode 100644
index 00000000..49c854e7
--- /dev/null
+++ b/res-hdpi/images/ic_system_update_sel.png
Binary files differ
diff --git a/res-hdpi/images/logo_image.png b/res-hdpi/images/logo_image.png
new file mode 100644
index 00000000..8bab73c1
--- /dev/null
+++ b/res-hdpi/images/logo_image.png
Binary files differ
diff --git a/res-mdpi/images/ic_back.png b/res-mdpi/images/ic_back.png
new file mode 100644
index 00000000..4af9ce63
--- /dev/null
+++ b/res-mdpi/images/ic_back.png
Binary files differ
diff --git a/res-mdpi/images/ic_back_sel.png b/res-mdpi/images/ic_back_sel.png
new file mode 100644
index 00000000..4e8152c7
--- /dev/null
+++ b/res-mdpi/images/ic_back_sel.png
Binary files differ
diff --git a/res-mdpi/images/ic_factory_reset.png b/res-mdpi/images/ic_factory_reset.png
new file mode 100644
index 00000000..114b1f96
--- /dev/null
+++ b/res-mdpi/images/ic_factory_reset.png
Binary files differ
diff --git a/res-mdpi/images/ic_factory_reset_sel.png b/res-mdpi/images/ic_factory_reset_sel.png
new file mode 100644
index 00000000..60471b30
--- /dev/null
+++ b/res-mdpi/images/ic_factory_reset_sel.png
Binary files differ
diff --git a/res-mdpi/images/ic_options_advanced.png b/res-mdpi/images/ic_options_advanced.png
new file mode 100644
index 00000000..1d509cab
--- /dev/null
+++ b/res-mdpi/images/ic_options_advanced.png
Binary files differ
diff --git a/res-mdpi/images/ic_options_advanced_sel.png b/res-mdpi/images/ic_options_advanced_sel.png
new file mode 100644
index 00000000..6b6ba9c6
--- /dev/null
+++ b/res-mdpi/images/ic_options_advanced_sel.png
Binary files differ
diff --git a/res-mdpi/images/ic_reboot.png b/res-mdpi/images/ic_reboot.png
new file mode 100644
index 00000000..f6b73941
--- /dev/null
+++ b/res-mdpi/images/ic_reboot.png
Binary files differ
diff --git a/res-mdpi/images/ic_reboot_sel.png b/res-mdpi/images/ic_reboot_sel.png
new file mode 100644
index 00000000..007f5828
--- /dev/null
+++ b/res-mdpi/images/ic_reboot_sel.png
Binary files differ
diff --git a/res-mdpi/images/ic_system_update.png b/res-mdpi/images/ic_system_update.png
new file mode 100644
index 00000000..0395db24
--- /dev/null
+++ b/res-mdpi/images/ic_system_update.png
Binary files differ
diff --git a/res-mdpi/images/ic_system_update_sel.png b/res-mdpi/images/ic_system_update_sel.png
new file mode 100644
index 00000000..cd15c9e4
--- /dev/null
+++ b/res-mdpi/images/ic_system_update_sel.png
Binary files differ
diff --git a/res-mdpi/images/logo_image.png b/res-mdpi/images/logo_image.png
new file mode 100644
index 00000000..ebdb0e68
--- /dev/null
+++ b/res-mdpi/images/logo_image.png
Binary files differ
diff --git a/res-xhdpi/images/ic_back.png b/res-xhdpi/images/ic_back.png
new file mode 100644
index 00000000..6dbb7066
--- /dev/null
+++ b/res-xhdpi/images/ic_back.png
Binary files differ
diff --git a/res-xhdpi/images/ic_back_sel.png b/res-xhdpi/images/ic_back_sel.png
new file mode 100644
index 00000000..20e5451d
--- /dev/null
+++ b/res-xhdpi/images/ic_back_sel.png
Binary files differ
diff --git a/res-xhdpi/images/ic_factory_reset.png b/res-xhdpi/images/ic_factory_reset.png
new file mode 100644
index 00000000..695fb54d
--- /dev/null
+++ b/res-xhdpi/images/ic_factory_reset.png
Binary files differ
diff --git a/res-xhdpi/images/ic_factory_reset_sel.png b/res-xhdpi/images/ic_factory_reset_sel.png
new file mode 100644
index 00000000..31b2ca16
--- /dev/null
+++ b/res-xhdpi/images/ic_factory_reset_sel.png
Binary files differ
diff --git a/res-xhdpi/images/ic_options_advanced.png b/res-xhdpi/images/ic_options_advanced.png
new file mode 100644
index 00000000..8067ee31
--- /dev/null
+++ b/res-xhdpi/images/ic_options_advanced.png
Binary files differ
diff --git a/res-xhdpi/images/ic_options_advanced_sel.png b/res-xhdpi/images/ic_options_advanced_sel.png
new file mode 100644
index 00000000..a87325e6
--- /dev/null
+++ b/res-xhdpi/images/ic_options_advanced_sel.png
Binary files differ
diff --git a/res-xhdpi/images/ic_reboot.png b/res-xhdpi/images/ic_reboot.png
new file mode 100644
index 00000000..6f933d98
--- /dev/null
+++ b/res-xhdpi/images/ic_reboot.png
Binary files differ
diff --git a/res-xhdpi/images/ic_reboot_sel.png b/res-xhdpi/images/ic_reboot_sel.png
new file mode 100644
index 00000000..04f797d4
--- /dev/null
+++ b/res-xhdpi/images/ic_reboot_sel.png
Binary files differ
diff --git a/res-xhdpi/images/ic_system_update.png b/res-xhdpi/images/ic_system_update.png
new file mode 100644
index 00000000..22aca1eb
--- /dev/null
+++ b/res-xhdpi/images/ic_system_update.png
Binary files differ
diff --git a/res-xhdpi/images/ic_system_update_sel.png b/res-xhdpi/images/ic_system_update_sel.png
new file mode 100644
index 00000000..11e6d7b9
--- /dev/null
+++ b/res-xhdpi/images/ic_system_update_sel.png
Binary files differ
diff --git a/res-xhdpi/images/logo_image.png b/res-xhdpi/images/logo_image.png
new file mode 100644
index 00000000..9c37f8f0
--- /dev/null
+++ b/res-xhdpi/images/logo_image.png
Binary files differ
diff --git a/res-xxhdpi/images/font_menu.png b/res-xxhdpi/images/font_menu.png
new file mode 100644
index 00000000..f3b54b38
--- /dev/null
+++ b/res-xxhdpi/images/font_menu.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_back.png b/res-xxhdpi/images/ic_back.png
new file mode 100644
index 00000000..fef22710
--- /dev/null
+++ b/res-xxhdpi/images/ic_back.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_back_sel.png b/res-xxhdpi/images/ic_back_sel.png
new file mode 100644
index 00000000..50dc5577
--- /dev/null
+++ b/res-xxhdpi/images/ic_back_sel.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_factory_reset.png b/res-xxhdpi/images/ic_factory_reset.png
new file mode 100644
index 00000000..5792af95
--- /dev/null
+++ b/res-xxhdpi/images/ic_factory_reset.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_factory_reset_sel.png b/res-xxhdpi/images/ic_factory_reset_sel.png
new file mode 100644
index 00000000..9a0b7608
--- /dev/null
+++ b/res-xxhdpi/images/ic_factory_reset_sel.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_options_advanced.png b/res-xxhdpi/images/ic_options_advanced.png
new file mode 100644
index 00000000..6e56fc85
--- /dev/null
+++ b/res-xxhdpi/images/ic_options_advanced.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_options_advanced_sel.png b/res-xxhdpi/images/ic_options_advanced_sel.png
new file mode 100644
index 00000000..30d38e26
--- /dev/null
+++ b/res-xxhdpi/images/ic_options_advanced_sel.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_reboot.png b/res-xxhdpi/images/ic_reboot.png
new file mode 100644
index 00000000..1d3a5642
--- /dev/null
+++ b/res-xxhdpi/images/ic_reboot.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_reboot_sel.png b/res-xxhdpi/images/ic_reboot_sel.png
new file mode 100644
index 00000000..6dfde37d
--- /dev/null
+++ b/res-xxhdpi/images/ic_reboot_sel.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_system_update.png b/res-xxhdpi/images/ic_system_update.png
new file mode 100644
index 00000000..78702005
--- /dev/null
+++ b/res-xxhdpi/images/ic_system_update.png
Binary files differ
diff --git a/res-xxhdpi/images/ic_system_update_sel.png b/res-xxhdpi/images/ic_system_update_sel.png
new file mode 100644
index 00000000..27297e08
--- /dev/null
+++ b/res-xxhdpi/images/ic_system_update_sel.png
Binary files differ
diff --git a/res-xxhdpi/images/logo_image.png b/res-xxhdpi/images/logo_image.png
new file mode 100644
index 00000000..258ae890
--- /dev/null
+++ b/res-xxhdpi/images/logo_image.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_back.png b/res-xxxhdpi/images/ic_back.png
new file mode 100644
index 00000000..b41f5572
--- /dev/null
+++ b/res-xxxhdpi/images/ic_back.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_back_sel.png b/res-xxxhdpi/images/ic_back_sel.png
new file mode 100644
index 00000000..b7f604cf
--- /dev/null
+++ b/res-xxxhdpi/images/ic_back_sel.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_factory_reset.png b/res-xxxhdpi/images/ic_factory_reset.png
new file mode 100644
index 00000000..c14607c9
--- /dev/null
+++ b/res-xxxhdpi/images/ic_factory_reset.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_factory_reset_sel.png b/res-xxxhdpi/images/ic_factory_reset_sel.png
new file mode 100644
index 00000000..dd61b862
--- /dev/null
+++ b/res-xxxhdpi/images/ic_factory_reset_sel.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_options_advanced.png b/res-xxxhdpi/images/ic_options_advanced.png
new file mode 100644
index 00000000..322a7b59
--- /dev/null
+++ b/res-xxxhdpi/images/ic_options_advanced.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_options_advanced_sel.png b/res-xxxhdpi/images/ic_options_advanced_sel.png
new file mode 100644
index 00000000..64f631d6
--- /dev/null
+++ b/res-xxxhdpi/images/ic_options_advanced_sel.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_reboot.png b/res-xxxhdpi/images/ic_reboot.png
new file mode 100644
index 00000000..5d431632
--- /dev/null
+++ b/res-xxxhdpi/images/ic_reboot.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_reboot_sel.png b/res-xxxhdpi/images/ic_reboot_sel.png
new file mode 100644
index 00000000..0ccd6da7
--- /dev/null
+++ b/res-xxxhdpi/images/ic_reboot_sel.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_system_update.png b/res-xxxhdpi/images/ic_system_update.png
new file mode 100644
index 00000000..687c2823
--- /dev/null
+++ b/res-xxxhdpi/images/ic_system_update.png
Binary files differ
diff --git a/res-xxxhdpi/images/ic_system_update_sel.png b/res-xxxhdpi/images/ic_system_update_sel.png
new file mode 100644
index 00000000..929b6ac2
--- /dev/null
+++ b/res-xxxhdpi/images/ic_system_update_sel.png
Binary files differ
diff --git a/res-xxxhdpi/images/logo_image.png b/res-xxxhdpi/images/logo_image.png
new file mode 100644
index 00000000..0fa93e10
--- /dev/null
+++ b/res-xxxhdpi/images/logo_image.png
Binary files differ
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 2f8b07b9..41d0594a 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -37,6 +37,8 @@
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <healthd/BatteryMonitor.h>
+
#include "common.h"
#include "device.h"
#include "minui/minui.h"
@@ -50,6 +52,69 @@ static double now() {
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
+static void get_battery_status(bool& charged, int& capacity) {
+ struct healthd_config healthd_config = {
+ .batteryStatusPath = android::String8(android::String8::kEmptyString),
+ .batteryHealthPath = android::String8(android::String8::kEmptyString),
+ .batteryPresentPath = android::String8(android::String8::kEmptyString),
+ .batteryCapacityPath = android::String8(android::String8::kEmptyString),
+ .batteryVoltagePath = android::String8(android::String8::kEmptyString),
+ .batteryTemperaturePath = android::String8(android::String8::kEmptyString),
+ .batteryTechnologyPath = android::String8(android::String8::kEmptyString),
+ .batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
+ .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
+ .batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
+ .batteryFullChargePath = android::String8(android::String8::kEmptyString),
+ .batteryCycleCountPath = android::String8(android::String8::kEmptyString),
+ .energyCounter = NULL,
+ .boot_min_cap = 0,
+ .screen_on = NULL
+ };
+ healthd_board_init(&healthd_config);
+
+ android::BatteryMonitor monitor;
+ monitor.init(&healthd_config);
+
+ int charge_status = monitor.getChargeStatus();
+ // Treat unknown status as charged.
+ charged = (charge_status != android::BATTERY_STATUS_DISCHARGING &&
+ charge_status != android::BATTERY_STATUS_NOT_CHARGING);
+ android::BatteryProperty prop;
+ android::status_t status = monitor.getProperty(android::BATTERY_PROP_CAPACITY, &prop);
+ // If we can't read battery percentage, it may be a device without battery. In this
+ // situation, use 100 as a fake battery percentage.
+ if (status != 0) {
+ prop.valueInt64 = 100;
+ }
+ capacity = (int)prop.valueInt64;
+}
+
+ScreenMenuItem::~ScreenMenuItem() {
+ if (icon_) {
+ res_free_surface(icon_);
+ }
+ if (icon_sel_) {
+ res_free_surface(icon_sel_);
+ }
+}
+
+GRSurface* ScreenMenuItem::icon() {
+ if (!icon_) {
+ res_create_display_surface(icon_name_.c_str(), &icon_);
+ }
+ return icon_;
+}
+
+GRSurface* ScreenMenuItem::icon_sel() {
+ if (icon_name_sel_.empty()) {
+ return icon();
+ }
+ if (!icon_sel_) {
+ res_create_display_surface(icon_name_sel_.c_str(), &icon_sel_);
+ }
+ return icon_sel_;
+}
+
ScreenRecoveryUI::ScreenRecoveryUI()
: kMarginWidth(RECOVERY_UI_MARGIN_WIDTH),
kMarginHeight(RECOVERY_UI_MARGIN_HEIGHT),
@@ -69,9 +134,13 @@ ScreenRecoveryUI::ScreenRecoveryUI()
text_top_(0),
show_text(false),
show_text_ever(false),
- menu_(nullptr),
+ menu_is_main_(true),
+ menu_type_(MT_NONE),
+ menu_headers_(nullptr),
+ menu_start_y_(0),
show_menu(false),
- menu_items(0),
+ menu_show_start(0),
+ menu_show_count(0),
menu_sel(0),
file_viewer_text_(nullptr),
intro_frames(0),
@@ -180,7 +249,7 @@ void ScreenRecoveryUI::draw_background_locked() {
// Draws the animation and progress bar (if any) on the screen. Does not flip pages. Should only be
// called with updateMutex locked.
void ScreenRecoveryUI::draw_foreground_locked() {
- if (currentIcon != NONE) {
+ if (currentIcon != NONE && currentIcon != NO_COMMAND) {
gr_color(0, 0, 0, 255);
gr_clear();
GRSurface* frame = GetCurrentFrame();
@@ -228,8 +297,12 @@ void ScreenRecoveryUI::draw_foreground_locked() {
}
}
+/* Lineage teal: #167c80 */
void ScreenRecoveryUI::SetColor(UIElement e) const {
switch (e) {
+ case STATUSBAR:
+ gr_color(255, 255, 255, 255);
+ break;
case INFO:
gr_color(249, 194, 0, 255);
break;
@@ -238,13 +311,13 @@ void ScreenRecoveryUI::SetColor(UIElement e) const {
break;
case MENU:
case MENU_SEL_BG:
- gr_color(106, 103, 102, 255);
+ gr_color(0xd8, 0xd8, 0xd8, 255);
break;
case MENU_SEL_BG_ACTIVE:
gr_color(138, 135, 134, 255);
break;
case MENU_SEL_FG:
- gr_color(0, 177, 229, 255);
+ gr_color(0x16, 0x7c, 0x80, 255);
break;
case LOG:
gr_color(196, 196, 196, 255);
@@ -302,7 +375,8 @@ int ScreenRecoveryUI::DrawWrappedTextLines(int x, int y, const char* const* line
next_start += last_space + 1;
}
}
- offset += DrawTextLine(x, y + offset, sub.c_str(), false);
+ gr_text(gr_menu_font(), x, y + offset, sub.c_str(), false);
+ offset += menu_char_height_ + 4;
}
}
return offset;
@@ -319,6 +393,215 @@ static const char* LONG_PRESS_HELP[] = {
NULL
};
+void ScreenRecoveryUI::draw_statusbar_locked() {
+ int y = kMarginHeight;
+ int x;
+
+ int h_unit = gr_fb_width() / 9;
+ int v_unit = gr_fb_height() / 16;
+
+ GRSurface* icon;
+ int icon_x, icon_y, icon_h, icon_w;
+
+ // Local time
+ char localtm_str[] = "--:--";
+ time_t now;
+ struct tm localtm;
+ time(&now);
+ if (now > TV_MIN) {
+ localtime_r(&now, &localtm);
+ snprintf(localtm_str, sizeof(localtm_str), "%02d:%02d",
+ localtm.tm_hour, localtm.tm_min);
+ }
+
+ // Battery status
+ bool batt_charged;
+ int batt_capacity;
+ get_battery_status(batt_charged, batt_capacity);
+ char batt_capacity_str[3+1+1];
+ snprintf(batt_capacity_str, sizeof(batt_capacity_str), "%d%%", batt_capacity);
+
+ // Draw status bar from right to left
+
+ // Time
+ SetColor(STATUSBAR);
+ x = gr_fb_width();
+ x -= 5 * char_width_;
+ gr_text(gr_sys_font(), x, y, localtm_str, false);
+
+ x -= char_width_; // Separator
+
+ // Battery icon
+ x -= 1 * char_width_;
+ SetColor((batt_capacity < 20) ? HEADER : STATUSBAR);
+
+ // Top
+ icon_x = x + char_width_ / 3;
+ icon_y = y;
+ icon_w = char_width_ / 3;
+ icon_h = char_height_ / 12;
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h);
+
+ // Main rect
+ icon_x = x;
+ icon_y = y + icon_h;
+ icon_w = char_width_;
+ icon_h = char_height_ - (char_height_ / 12);
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h);
+
+ // Capacity
+ icon_x = x + char_width_ / 6;
+ icon_y = y + char_height_ / 12;
+ icon_w = char_width_ - (2 * char_width_ / 6);
+ icon_h = char_height_ - (3 * char_height_ / 12);
+ int cap_h = icon_h * batt_capacity / 100;
+ gr_fill(icon_x, icon_y + icon_h - cap_h, icon_x + icon_w, icon_y + icon_h);
+ gr_color(0, 0, 0, 255);
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h - cap_h);
+ SetColor(STATUSBAR);
+
+ x -= char_width_; // Separator
+
+ // Battery text
+ x -= strlen(batt_capacity_str) * char_width_;
+ gr_text(gr_sys_font(), x, y, batt_capacity_str, false);
+}
+
+/*
+ * Header layout:
+ * * 1/32: Status bar
+ * * Header image
+ * * 1/32: Margin
+ */
+void ScreenRecoveryUI::draw_header_locked(int& y) {
+ int h_unit = gr_fb_width() / 9;
+ int v_unit = gr_fb_height() / 16;
+
+ GRSurface* icon;
+ int icon_x, icon_y, icon_h, icon_w;
+
+ y += v_unit / 2; // Margin
+
+ // Draw back icon if not in main menu
+ if (!menu_is_main_) {
+ icon = (menu_sel == Device::kGoBack ? ic_back_sel : ic_back);
+ icon_w = gr_get_width(icon);
+ icon_h = gr_get_height(icon);
+ icon_x = (h_unit / 2) + ((h_unit * 1) - icon_w) / 2;
+ icon_y = y + ((v_unit * 1) - icon_h) / 2;
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
+ }
+ y += v_unit;
+
+ // Draw logo
+ icon = logo_image;
+ icon_w = gr_get_width(icon);
+ icon_h = gr_get_height(icon);
+ icon_x = (gr_fb_width() - icon_w) / 2;
+ icon_y = y + ((v_unit * 4) - icon_h) / 2;
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
+ y += v_unit * 4;
+
+ y += v_unit * 1; // Margin
+}
+
+void ScreenRecoveryUI::draw_text_menu_locked(int& y) {
+ static constexpr int kMenuIndent = 4;
+ int x = kMarginWidth + kMenuIndent;
+
+ draw_statusbar_locked();
+ draw_header_locked(y);
+
+ if (menu_headers_) {
+ SetColor(HEADER);
+ // Ignore kMenuIndent, which is not taken into account by text_cols_.
+ y += DrawWrappedTextLines(kMarginWidth, y, menu_headers_);
+
+ SetColor(MENU);
+ y += DrawHorizontalRule(y) + 4;
+ }
+
+ menu_start_y_ = y;
+ int i;
+ for (i = menu_show_start; i < (int)menu_items_.size() && y < gr_fb_height(); ++i) {
+ const ScreenMenuItem& item = menu_items_.at(i);
+ if (i == menu_sel) {
+ SetColor(MENU_SEL_FG);
+ y += menu_char_height_;
+ gr_text(gr_menu_font(), x, y, item.text().c_str(), true);
+ y += menu_char_height_;
+ y += menu_char_height_;
+ } else {
+ SetColor(MENU);
+ y += menu_char_height_;
+ gr_text(gr_menu_font(), x, y, item.text().c_str(), false);
+ y += menu_char_height_;
+ y += menu_char_height_;
+ }
+ }
+ menu_show_count = i - menu_show_start;
+}
+
+/*
+ * Grid layout.
+ *
+ * Grid item:
+ * Horizontal:
+ * * 3/9 of screen per item.
+ * * 1/9 of screen margin around/between items.
+ * Vertical:
+ * * 3/16 of screen per item.
+ * * No margin between items.
+ *
+ * Within a grid item:
+ * Asher's icons 1/5 of grid both dimensions.
+ * Current icons 2/5 of grid both dimensions.
+ * Horizontal:
+ * * All items centered.
+ * Vertical:
+ * * Icon lower aligned in top 2/3.
+ * * Text upper aligned in low 1/3 plus half line margin.
+ */
+void ScreenRecoveryUI::draw_grid_menu_locked(int& y) {
+ int h_unit = gr_fb_width() / 9;
+ int v_unit = gr_fb_height() / 16;
+
+ int grid_w = h_unit * 3;
+ int grid_h = v_unit * 3;
+
+ draw_statusbar_locked();
+ draw_header_locked(y);
+
+ menu_start_y_ = y;
+ int i;
+ for (i = menu_show_start; i < (int)menu_items_.size() && y + grid_h < gr_fb_height(); ++i) {
+ ScreenMenuItem& item = menu_items_.at(i);
+ int grid_x = (i % 2) ? h_unit * 5 : h_unit * 1;
+ int grid_y = y;
+ if (item.icon()) {
+ GRSurface* icon = (i == menu_sel) ? item.icon_sel() : item.icon();
+ int icon_w = gr_get_width(icon);
+ int icon_h = gr_get_height(icon);
+ int icon_x = grid_x + (grid_w - icon_w) / 2;
+ int icon_y = grid_y + ((grid_h * 2 / 3) - icon_h) / 2;
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
+ }
+ if (!item.text().empty()) {
+ int text_w = item.text().size() * char_width_;
+ int text_h = char_height_;
+ int text_x = grid_x + (grid_w - text_w) / 2;
+ int text_y = grid_y + (grid_h * 2 / 3) + (char_height_ / 2);
+ SetColor(i == menu_sel ? MENU_SEL_FG : MENU);
+ gr_text(gr_sys_font(), text_x, text_y, item.text().c_str(), false);
+ }
+ if (i % 2) {
+ y += grid_h;
+ grid_y = y;
+ }
+ }
+ menu_show_count = i - menu_show_start;
+}
+
// Redraws everything on the screen. Does not flip pages. Should only be called with updateMutex
// locked.
void ScreenRecoveryUI::draw_screen_locked() {
@@ -333,50 +616,40 @@ void ScreenRecoveryUI::draw_screen_locked() {
int y = kMarginHeight;
if (show_menu) {
- static constexpr int kMenuIndent = 4;
- int x = kMarginWidth + kMenuIndent;
-
- SetColor(INFO);
- y += DrawTextLine(x, y, "Android Recovery", true);
- std::string recovery_fingerprint =
- android::base::GetProperty("ro.bootimage.build.fingerprint", "");
- for (const auto& chunk : android::base::Split(recovery_fingerprint, ":")) {
- y += DrawTextLine(x, y, chunk.c_str(), false);
+ switch (menu_type_) {
+ case MT_LIST:
+ draw_text_menu_locked(y);
+ break;
+ case MT_GRID:
+ draw_grid_menu_locked(y);
+ break;
+ default:
+ break;
}
- y += DrawTextLines(x, y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
-
- SetColor(HEADER);
- // Ignore kMenuIndent, which is not taken into account by text_cols_.
- y += DrawWrappedTextLines(kMarginWidth, y, menu_headers_);
- SetColor(MENU);
- y += DrawHorizontalRule(y) + 4;
- for (int i = 0; i < menu_items; ++i) {
- if (i == menu_sel) {
- // Draw the highlight bar.
- SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG);
- DrawHighlightBar(0, y - 2, gr_fb_width(), char_height_ + 4);
- // Bold white text for the selected item.
- SetColor(MENU_SEL_FG);
- y += DrawTextLine(x, y, menu_[i], true);
- SetColor(MENU);
- } else {
- y += DrawTextLine(x, y, menu_[i], false);
- }
+ // Draw version info
+ if (menu_is_main_) {
+ int text_x, text_y;
+ text_x = (gr_fb_width() - (android_version_.size() * char_width_)) / 2;
+ text_y = gr_fb_height() - 2 * (char_height_ + 4);
+ DrawTextLine(text_x, text_y, android_version_.c_str(), false);
+ text_x = (gr_fb_width() - (lineage_version_.size() * char_width_)) / 2;
+ text_y = gr_fb_height() - 1 * (char_height_ + 4);
+ DrawTextLine(text_x, text_y, lineage_version_.c_str(), false);
}
- y += DrawHorizontalRule(y);
}
-
- // Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
- // we've displayed the entire text buffer.
- SetColor(LOG);
- int row = (text_top_ + text_rows_ - 1) % text_rows_;
- size_t count = 0;
- for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
- ty -= char_height_, ++count) {
- DrawTextLine(kMarginWidth, ty, text_[row], false);
- --row;
- if (row < 0) row = text_rows_ - 1;
+ else {
+ // Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
+ // we've displayed the entire text buffer.
+ SetColor(LOG);
+ int row = (text_top_ + text_rows_ - 1) % text_rows_;
+ size_t count = 0;
+ for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
+ ty -= char_height_, ++count) {
+ DrawTextLine(kMarginWidth, ty, text_[row], false);
+ --row;
+ if (row < 0) row = text_rows_ - 1;
+ }
}
}
@@ -459,6 +732,10 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
}
}
+void ScreenRecoveryUI::FreeBitmap(GRSurface* surface) {
+ res_free_surface(surface);
+}
+
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
int result = res_create_localized_alpha_surface(filename, locale_.c_str(), surface);
if (result < 0) {
@@ -491,6 +768,7 @@ bool ScreenRecoveryUI::InitTextParams() {
}
gr_font_size(gr_sys_font(), &char_width_, &char_height_);
+ gr_font_size(gr_menu_font(), &menu_char_width_, &menu_char_height_);
text_rows_ = (gr_fb_height() - kMarginHeight * 2) / char_height_;
text_cols_ = (gr_fb_width() - kMarginWidth * 2) / char_width_;
return true;
@@ -509,11 +787,14 @@ bool ScreenRecoveryUI::Init(const std::string& locale) {
text_ = Alloc2d(text_rows_, text_cols_ + 1);
file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
- menu_ = Alloc2d(text_rows_, text_cols_ + 1);
text_col_ = text_row_ = 0;
text_top_ = 1;
+ LoadBitmap("logo_image", &logo_image);
+ LoadBitmap("ic_back", &ic_back);
+ LoadBitmap("ic_back_sel", &ic_back_sel);
+
LoadBitmap("icon_error", &error_icon);
LoadBitmap("progress_empty", &progressBarEmpty);
@@ -580,8 +861,10 @@ void ScreenRecoveryUI::LoadAnimation() {
void ScreenRecoveryUI::SetBackground(Icon icon) {
pthread_mutex_lock(&updateMutex);
- currentIcon = icon;
- update_screen_locked();
+ if (icon != currentIcon) {
+ currentIcon = icon;
+ update_screen_locked();
+ }
pthread_mutex_unlock(&updateMutex);
}
@@ -698,7 +981,7 @@ void ScreenRecoveryUI::ClearText() {
pthread_mutex_unlock(&updateMutex);
}
-void ScreenRecoveryUI::ShowFile(FILE* fp) {
+int ScreenRecoveryUI::ShowFile(FILE* fp) {
std::vector<off_t> offsets;
offsets.push_back(ftello(fp));
ClearText();
@@ -715,10 +998,16 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
Redraw();
while (show_prompt) {
show_prompt = false;
- int key = WaitKey();
- if (key == KEY_POWER || key == KEY_ENTER) {
- return;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ RecoveryUI::InputEvent evt = WaitInputEvent();
+ if (evt.type() != RecoveryUI::EVENT_TYPE_KEY) {
+ show_prompt = true;
+ continue;
+ }
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER ||
+ evt.key() == KEY_BACKSPACE || evt.key() == KEY_BACK ||
+ evt.key() == KEY_HOME || evt.key() == KEY_HOMEPAGE) {
+ return evt.key();
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP) {
if (offsets.size() <= 1) {
show_prompt = true;
} else {
@@ -727,7 +1016,7 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
}
} else {
if (feof(fp)) {
- return;
+ return -1;
}
offsets.push_back(ftello(fp));
}
@@ -746,13 +1035,14 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
}
}
}
+ return -1;
}
-void ScreenRecoveryUI::ShowFile(const char* filename) {
+int ScreenRecoveryUI::ShowFile(const char* filename) {
FILE* fp = fopen_path(filename, "re");
if (fp == nullptr) {
Print(" Unable to open %s: %s\n", filename, strerror(errno));
- return;
+ return -1;
}
char** old_text = text_;
@@ -764,30 +1054,38 @@ void ScreenRecoveryUI::ShowFile(const char* filename) {
text_ = file_viewer_text_;
ClearText();
- ShowFile(fp);
+ int key = ShowFile(fp);
fclose(fp);
text_ = old_text;
text_col_ = old_text_col;
text_row_ = old_text_row;
text_top_ = old_text_top;
+ return key;
}
-void ScreenRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
+void ScreenRecoveryUI::StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) {
pthread_mutex_lock(&updateMutex);
- if (text_rows_ > 0 && text_cols_ > 0) {
- menu_headers_ = headers;
- size_t i = 0;
- for (; i < text_rows_ && items[i] != nullptr; ++i) {
- strncpy(menu_[i], items[i], text_cols_ - 1);
- menu_[i][text_cols_ - 1] = '\0';
- }
- menu_items = i;
- show_menu = true;
- menu_sel = initial_selection;
- update_screen_locked();
+ menu_is_main_ = is_main;
+ menu_type_ = type;
+ menu_headers_ = headers;
+ for (auto& item : items) {
+ menu_items_.push_back(ScreenMenuItem(item));
+ }
+ show_menu = true;
+ menu_sel = initial_selection;
+ draw_screen_locked();
+ if (menu_sel < menu_show_start) {
+ menu_show_start = menu_sel;
+ }
+ if (menu_sel >= menu_show_start + menu_show_count) {
+ menu_show_start = menu_sel - (menu_show_count - 1);
}
+ update_screen_locked();
pthread_mutex_unlock(&updateMutex);
}
@@ -798,8 +1096,16 @@ int ScreenRecoveryUI::SelectMenu(int sel) {
menu_sel = sel;
// Wrap at top and bottom.
- if (menu_sel < 0) menu_sel = menu_items - 1;
- if (menu_sel >= menu_items) menu_sel = 0;
+ if (menu_sel < 0) menu_sel = (int)menu_items_.size() - 1;
+ if (menu_sel >= (int)menu_items_.size()) menu_sel = 0;
+
+ // Scroll
+ if (menu_sel < menu_show_start) {
+ menu_show_start = menu_sel;
+ }
+ if (menu_sel >= menu_show_start + menu_show_count) {
+ menu_show_start = menu_sel - (menu_show_count - 1);
+ }
sel = menu_sel;
if (menu_sel != old_sel) update_screen_locked();
@@ -808,11 +1114,57 @@ int ScreenRecoveryUI::SelectMenu(int sel) {
return sel;
}
+int ScreenRecoveryUI::SelectMenu(const Point& point) {
+ int sel = Device::kNoAction;
+ int h_unit = gr_fb_width() / 9;
+ int v_unit = gr_fb_height() / 16;
+ pthread_mutex_lock(&updateMutex);
+ if (show_menu) {
+ if (point.y() < menu_start_y_) {
+ if (!menu_is_main_ &&
+ point.x() >= h_unit / 2 && point.x() < h_unit * 3 / 2 &&
+ point.y() >= v_unit * 1 / 2 && point.y() < v_unit * 3 / 2) {
+ sel = Device::kGoBack;
+ }
+ }
+ else {
+ int row = -1, col = -1;
+ switch (menu_type_) {
+ case MT_LIST:
+ sel = (point.y() - menu_start_y_) / (menu_char_height_ * 3);
+ break;
+ case MT_GRID:
+ row = (point.y() - menu_start_y_) / (gr_fb_height() * 3 / 16);
+ col = (point.x()) / (gr_fb_width() / 9);
+ if ((col % 4) != 0) {
+ sel = row * 2 + ((col - 1) / 4);
+ }
+ break;
+ default:
+ break;
+ }
+ if (sel >= (int)menu_items_.size()) {
+ sel = Device::kNoAction;
+ }
+ }
+ if (sel != -1 && sel != menu_sel) {
+ menu_sel = sel;
+ update_screen_locked();
+ usleep(100*1000);
+ }
+ }
+ pthread_mutex_unlock(&updateMutex);
+ return sel;
+}
+
void ScreenRecoveryUI::EndMenu() {
pthread_mutex_lock(&updateMutex);
if (show_menu && text_rows_ > 0 && text_cols_ > 0) {
show_menu = false;
}
+ menu_type_ = MT_NONE;
+ menu_headers_ = nullptr;
+ menu_items_.clear();
pthread_mutex_unlock(&updateMutex);
}
diff --git a/screen_ui.h b/screen_ui.h
index 726a9957..389d8c42 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -24,9 +24,35 @@
#include "ui.h"
+#define MAX_MENU_ITEMS 32
+
// From minui/minui.h.
struct GRSurface;
+class ScreenMenuItem {
+ public:
+ ScreenMenuItem() : icon_(nullptr), icon_sel_(nullptr) {}
+ explicit ScreenMenuItem(const MenuItem& mi) :
+ text_(mi.text()),
+ icon_name_(mi.icon_name()),
+ icon_(nullptr),
+ icon_name_sel_(mi.icon_name_sel()),
+ icon_sel_(nullptr) {}
+ ~ScreenMenuItem();
+
+ const std::string& text() const { return text_; }
+ GRSurface* icon();
+ GRSurface* icon_sel();
+
+ private:
+ std::string text_;
+ std::string icon_name_;
+ GRSurface* icon_;
+ std::string icon_name_sel_;
+ GRSurface* icon_sel_;
+};
+typedef std::vector<ScreenMenuItem> ScreenMenuItemVector;
+
// Implementation of RecoveryUI appropriate for devices with a screen
// (shows an icon + a progress bar, text logging, menu, etc.)
class ScreenRecoveryUI : public RecoveryUI {
@@ -55,19 +81,29 @@ class ScreenRecoveryUI : public RecoveryUI {
// printing messages
void Print(const char* fmt, ...) override __printflike(2, 3);
void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
- void ShowFile(const char* filename) override;
+ int ShowFile(const char* filename) override;
// menu display
- void StartMenu(const char* const* headers, const char* const* items,
+ void StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) override;
int SelectMenu(int sel) override;
+ int SelectMenu(const Point& point) override;
void EndMenu() override;
+ bool MenuShowing() const { return show_menu; }
+ bool MenuScrollable() const { return (menu_type_ == MT_LIST); }
+ int MenuItemStart() const { return menu_start_y_; }
+ int MenuItemHeight() const { return (3 * menu_char_height_); }
+
void KeyLongPress(int) override;
void Redraw();
enum UIElement {
+ STATUSBAR,
HEADER,
MENU,
MENU_SEL_BG,
@@ -96,6 +132,10 @@ class ScreenRecoveryUI : public RecoveryUI {
// The layout to use.
int layout_;
+ GRSurface* logo_image;
+ GRSurface* ic_back;
+ GRSurface* ic_back_sel;
+
GRSurface* error_icon;
GRSurface* erasing_text;
@@ -128,10 +168,15 @@ class ScreenRecoveryUI : public RecoveryUI {
bool show_text;
bool show_text_ever; // has show_text ever been true?
- char** menu_;
+ bool menu_is_main_;
+ menu_type_t menu_type_;
const char* const* menu_headers_;
+ ScreenMenuItemVector menu_items_;
+ int menu_start_y_;
bool show_menu;
- int menu_items, menu_sel;
+ int menu_show_start;
+ int menu_show_count;
+ int menu_sel;
// An alternate text screen, swapped with 'text_' when we're viewing a log file.
char** file_viewer_text_;
@@ -150,12 +195,19 @@ class ScreenRecoveryUI : public RecoveryUI {
int char_width_;
int char_height_;
+ int menu_char_width_;
+ int menu_char_height_;
+
pthread_mutex_t updateMutex;
virtual bool InitTextParams();
virtual void draw_background_locked();
virtual void draw_foreground_locked();
+ virtual void draw_statusbar_locked();
+ virtual void draw_header_locked(int& y);
+ virtual void draw_text_menu_locked(int& y);
+ virtual void draw_grid_menu_locked(int& y);
virtual void draw_screen_locked();
virtual void update_screen_locked();
virtual void update_progress_locked();
@@ -166,13 +218,14 @@ class ScreenRecoveryUI : public RecoveryUI {
static void* ProgressThreadStartRoutine(void* data);
void ProgressThreadLoop();
- virtual void ShowFile(FILE*);
+ virtual int ShowFile(FILE*);
virtual void PrintV(const char*, bool, va_list);
void PutChar(char);
void ClearText();
void LoadAnimation();
void LoadBitmap(const char* filename, GRSurface** surface);
+ void FreeBitmap(GRSurface* surface);
void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
int PixelsFromDp(int dp) const;
diff --git a/stub_ui.h b/stub_ui.h
index 85dbcfd8..806c10a7 100644
--- a/stub_ui.h
+++ b/stub_ui.h
@@ -51,15 +51,26 @@ class StubRecoveryUI : public RecoveryUI {
va_end(ap);
}
void PrintOnScreenOnly(const char* fmt, ...) override {}
- void ShowFile(const char* filename) override {}
+ int ShowFile(const char* filename) override { return -1; }
// menu display
- void StartMenu(const char* const* headers, const char* const* items,
+ void StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) override {}
int SelectMenu(int sel) override {
return sel;
}
+ int SelectMenu(const Point& point) override {
+ return 0;
+ }
void EndMenu() override {}
+
+ bool MenuShowing() const { return true; }
+ bool MenuScrollable() const { return true; }
+ int MenuItemStart() const { return 0; }
+ int MenuItemHeight() const { return 1; }
};
#endif // RECOVERY_STUB_UI_H
diff --git a/ui.cpp b/ui.cpp
index dc50c5d6..95d422df 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -39,6 +39,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
+#include <cutils/properties.h>
#include <minui/minui.h>
#include "common.h"
@@ -58,7 +59,7 @@ RecoveryUI::RecoveryUI()
volumes_changed_(false),
kTouchLowThreshold(RECOVERY_UI_TOUCH_LOW_THRESHOLD),
kTouchHighThreshold(RECOVERY_UI_TOUCH_HIGH_THRESHOLD),
- key_queue_len(0),
+ event_queue_len(0),
key_last_down(-1),
key_long_press(false),
key_down_count(0),
@@ -70,10 +71,20 @@ RecoveryUI::RecoveryUI()
has_down_key(false),
has_touch_screen(false),
touch_slot_(0),
+ touch_finger_down_(false),
+ touch_saw_x_(false),
+ touch_saw_y_(false),
+ touch_reported_(false),
is_bootreason_recovery_ui_(false),
screensaver_state_(ScreensaverState::DISABLED) {
- pthread_mutex_init(&key_queue_mutex, nullptr);
- pthread_cond_init(&key_queue_cond, nullptr);
+ char propval[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", propval, "(unknown)");
+ android_version_ = std::string("Android ") + propval;
+ property_get("ro.lineage.version", propval, "(unknown)");
+ lineage_version_ = std::string("LineageOS ") + propval;
+
+ pthread_mutex_init(&event_queue_mutex, nullptr);
+ pthread_cond_init(&event_queue_cond, nullptr);
memset(key_pressed, 0, sizeof(key_pressed));
}
@@ -216,59 +227,59 @@ void RecoveryUI::Stop() {
!android::base::WriteStringToFile("0", BRIGHTNESS_FILE);
}
-void RecoveryUI::OnTouchEvent() {
- Point delta = touch_pos_ - touch_start_;
- enum SwipeDirection { UP, DOWN, RIGHT, LEFT } direction;
+void RecoveryUI::OnTouchPress() {
+ touch_start_ = touch_track_ = touch_pos_;
+}
- // We only consider a valid swipe if:
- // - the delta along one axis is below kTouchLowThreshold;
- // - and the delta along the other axis is beyond kTouchHighThreshold.
- if (abs(delta.y()) < kTouchLowThreshold && abs(delta.x()) > kTouchHighThreshold) {
- direction = delta.x() < 0 ? SwipeDirection::LEFT : SwipeDirection::RIGHT;
- } else if (abs(delta.x()) < kTouchLowThreshold && abs(delta.y()) > kTouchHighThreshold) {
- direction = delta.y() < 0 ? SwipeDirection::UP : SwipeDirection::DOWN;
- } else {
- for (const auto& vk : virtual_keys_) {
- if (touch_start_.x() >= vk.min_.x() && touch_start_.x() < vk.max_.x() &&
- touch_start_.y() >= vk.min_.y() && touch_start_.y() < vk.max_.y()) {
- ProcessKey(vk.keycode, 1); // press key
- ProcessKey(vk.keycode, 0); // and release it
- return;
+void RecoveryUI::OnTouchTrack() {
+ if (touch_pos_.y() <= gr_fb_height()) {
+ if (MenuShowing() && MenuScrollable()) {
+ while (abs(touch_pos_.y() - touch_track_.y()) >= MenuItemHeight()) {
+ int dy = touch_pos_.y() - touch_track_.y();
+ int key = (dy < 0) ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
+ ProcessKey(key, 1); // press key
+ ProcessKey(key, 0); // and release it
+ int sgn = (dy > 0) - (dy < 0);
+ touch_track_.y(touch_track_.y() + sgn * MenuItemHeight());
}
}
- LOG(DEBUG) << "Ignored " << delta.x() << " " << delta.y()
- << " (low: " << kTouchLowThreshold
- << ", high: " << kTouchHighThreshold << ")";
- return;
}
+}
+void RecoveryUI::OnTouchRelease() {
// Allow turning on text mode with any swipe, if bootloader has set a bootreason of recovery_ui.
if (is_bootreason_recovery_ui_ && !IsTextVisible()) {
ShowText(true);
return;
}
- LOG(DEBUG) << "Swipe direction=" << direction;
- switch (direction) {
- case SwipeDirection::UP:
- ProcessKey(KEY_UP, 1); // press up key
- ProcessKey(KEY_UP, 0); // and release it
- break;
+ // Check vkeys. Only report if touch both starts and ends in the vkey.
+ if (touch_start_.y() > gr_fb_height() && touch_pos_.y() > gr_fb_height()) {
+ for (const auto& vk : virtual_keys_) {
+ if (vk.inside(touch_start_) && vk.inside(touch_pos_)) {
+ ProcessKey(vk.keycode, 1); // press key
+ ProcessKey(vk.keycode, 0); // and release it
+ }
+ }
+ return;
+ }
- case SwipeDirection::DOWN:
- ProcessKey(KEY_DOWN, 1); // press down key
- ProcessKey(KEY_DOWN, 0); // and release it
- break;
+ // If we tracked a vertical swipe, ignore the release
+ if (touch_track_ != touch_start_) {
+ return;
+ }
- case SwipeDirection::LEFT:
- ProcessKey(KEY_BACK, 1); // press power key
- ProcessKey(KEY_BACK, 0); // and release it
- break;
- case SwipeDirection::RIGHT:
- ProcessKey(KEY_POWER, 1); // press power key
- ProcessKey(KEY_POWER, 0); // and release it
- break;
- };
+ // Check for horizontal swipe
+ Point delta = touch_pos_ - touch_start_;
+ if (abs(delta.y()) < kTouchLowThreshold && abs(delta.x()) > kTouchHighThreshold) {
+ int key = (delta.x() < 0) ? KEY_BACK : KEY_POWER;
+ ProcessKey(key, 1); // press key
+ ProcessKey(key, 0); // and release it
+ return;
+ }
+
+ // Simple touch
+ EnqueueTouch(touch_pos_);
}
int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
@@ -279,10 +290,6 @@ int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
// Touch inputs handling.
//
- // We handle the touch inputs by tracking the position changes between initial contacting and
- // upon lifting. touch_start_X/Y record the initial positions, with touch_finger_down set. Upon
- // detecting the lift, we unset touch_finger_down and detect a swipe based on position changes.
- //
// Per the doc Multi-touch Protocol at below, there are two protocols.
// https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
//
@@ -299,14 +306,17 @@ int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
if (ev.type == EV_SYN) {
if (touch_screen_allowed_ && ev.code == SYN_REPORT) {
- // There might be multiple SYN_REPORT events. We should only detect a swipe after lifting the
- // contact.
- if (touch_finger_down_ && !touch_swiping_) {
- touch_start_ = touch_pos_;
- touch_swiping_ = true;
- } else if (!touch_finger_down_ && touch_swiping_) {
- touch_swiping_ = false;
- OnTouchEvent();
+ // There might be multiple SYN_REPORT events. Only report press/release once.
+ if (!touch_reported_ && touch_finger_down_) {
+ if (touch_saw_x_ && touch_saw_y_) {
+ OnTouchPress();
+ touch_reported_ = true;
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
+ } else if (touch_reported_ && !touch_finger_down_) {
+ OnTouchRelease();
+ touch_reported_ = false;
+ touch_saw_x_ = touch_saw_y_ = false;
}
}
return 0;
@@ -342,13 +352,23 @@ int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
switch (ev.code) {
case ABS_MT_POSITION_X:
- touch_pos_.x(ev.value);
touch_finger_down_ = true;
+ touch_saw_x_ = true;
+ touch_pos_.x(ev.value);
+ if (touch_reported_ && touch_saw_y_) {
+ OnTouchTrack();
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
break;
case ABS_MT_POSITION_Y:
- touch_pos_.y(ev.value);
touch_finger_down_ = true;
+ touch_saw_y_ = true;
+ touch_pos_.y(ev.value);
+ if (touch_reported_ && touch_saw_x_) {
+ OnTouchTrack();
+ touch_saw_x_ = touch_saw_y_ = false;
+ }
break;
case ABS_MT_TRACKING_ID:
@@ -398,7 +418,7 @@ void RecoveryUI::ProcessKey(int key_code, int updown) {
bool long_press = false;
bool reboot_enabled;
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
key_pressed[key_code] = updown;
if (updown) {
++key_down_count;
@@ -419,7 +439,7 @@ void RecoveryUI::ProcessKey(int key_code, int updown) {
key_last_down = -1;
}
reboot_enabled = enable_reboot;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
if (register_key) {
switch (CheckKey(key_code, long_press)) {
@@ -459,27 +479,38 @@ void* RecoveryUI::time_key_helper(void* cookie) {
void RecoveryUI::time_key(int key_code, int count) {
usleep(750000); // 750 ms == "long"
bool long_press = false;
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
if (key_last_down == key_code && key_down_count == count) {
long_press = key_long_press = true;
}
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
if (long_press) KeyLongPress(key_code);
}
void RecoveryUI::EnqueueKey(int key_code) {
- pthread_mutex_lock(&key_queue_mutex);
- const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
- if (key_queue_len < queue_max) {
- key_queue[key_queue_len++] = key_code;
- pthread_cond_signal(&key_queue_cond);
+ pthread_mutex_lock(&event_queue_mutex);
+ const int queue_max = sizeof(event_queue) / sizeof(event_queue[0]);
+ if (event_queue_len < queue_max) {
+ InputEvent event(key_code);
+ event_queue[event_queue_len++] = event;
+ pthread_cond_signal(&event_queue_cond);
+ }
+ pthread_mutex_unlock(&event_queue_mutex);
+}
+
+void RecoveryUI::EnqueueTouch(const Point& pos) {
+ pthread_mutex_lock(&event_queue_mutex);
+ const int queue_max = sizeof(event_queue) / sizeof(event_queue[0]);
+ if (event_queue_len < queue_max) {
+ InputEvent event(pos);
+ event_queue[event_queue_len++] = event;
+ pthread_cond_signal(&event_queue_cond);
}
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
}
-int RecoveryUI::WaitKey() {
- pthread_mutex_lock(&key_queue_mutex);
- int timeouts = UI_WAIT_KEY_TIMEOUT_SEC;
+RecoveryUI::InputEvent RecoveryUI::WaitInputEvent() {
+ pthread_mutex_lock(&event_queue_mutex);
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
// plugged in.
@@ -492,16 +523,18 @@ int RecoveryUI::WaitKey() {
timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC;
int rc = 0;
- while (key_queue_len == 0 && rc != ETIMEDOUT) {
+ while (event_queue_len == 0 && rc != ETIMEDOUT) {
+ Print(""); // Force screen update
struct timespec key_timeout;
gettimeofday(&now, nullptr);
key_timeout.tv_sec = now.tv_sec + 1;
key_timeout.tv_nsec = now.tv_usec * 1000;
- rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &key_timeout);
+ rc = pthread_cond_timedwait(&event_queue_cond, &event_queue_mutex, &key_timeout);
if (rc == ETIMEDOUT) {
if (VolumesChanged()) {
- pthread_mutex_unlock(&key_queue_mutex);
- return KEY_REFRESH;
+ pthread_mutex_unlock(&event_queue_mutex);
+ InputEvent event(KEY_REFRESH);
+ return event;
}
if (key_timeout.tv_sec <= timeout.tv_sec) {
rc = 0;
@@ -528,8 +561,8 @@ int RecoveryUI::WaitKey() {
} else if (screensaver_state_ != ScreensaverState::NORMAL) {
// Drop the first key if it's changing from OFF to NORMAL.
if (screensaver_state_ == ScreensaverState::OFF) {
- if (key_queue_len > 0) {
- memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
+ if (event_queue_len > 0) {
+ memcpy(&event_queue[0], &event_queue[1], sizeof(int) * --event_queue_len);
}
}
@@ -542,23 +575,24 @@ int RecoveryUI::WaitKey() {
}
}
}
- } while (IsUsbConnected() && key_queue_len == 0);
+ } while (IsUsbConnected() && event_queue_len == 0);
- int key = -1;
- if (key_queue_len > 0) {
- key = key_queue[0];
- memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
+ InputEvent event;
+ if (event_queue_len > 0) {
+ event = event_queue[0];
+ memcpy(&event_queue[0], &event_queue[1], sizeof(event_queue[0]) * --event_queue_len);
}
- pthread_mutex_unlock(&key_queue_mutex);
- return key;
+ pthread_mutex_unlock(&event_queue_mutex);
+ return event;
}
void RecoveryUI::CancelWaitKey()
{
- pthread_mutex_lock(&key_queue_mutex);
- key_queue[key_queue_len++] = KEY_REFRESH;
- pthread_cond_signal(&key_queue_cond);
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
+ InputEvent event(KEY_REFRESH);
+ event_queue[event_queue_len++] = event;
+ pthread_cond_signal(&event_queue_cond);
+ pthread_mutex_unlock(&event_queue_mutex);
}
bool RecoveryUI::IsUsbConnected() {
@@ -578,16 +612,16 @@ bool RecoveryUI::IsUsbConnected() {
}
bool RecoveryUI::IsKeyPressed(int key) {
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
int pressed = key_pressed[key];
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
return pressed;
}
bool RecoveryUI::IsLongPress() {
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
bool result = key_long_press;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
return result;
}
@@ -604,15 +638,15 @@ bool RecoveryUI::HasTouchScreen() const {
}
void RecoveryUI::FlushKeys() {
- pthread_mutex_lock(&key_queue_mutex);
- key_queue_len = 0;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
+ event_queue_len = 0;
+ pthread_mutex_unlock(&event_queue_mutex);
}
RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) {
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
key_long_press = false;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
// If we have power and volume up keys, that chord is the signal to toggle the text display.
if (HasThreeButtons() || (HasPowerKey() && HasTouchScreen() && touch_screen_allowed_)) {
@@ -635,9 +669,9 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key, bool is_long_press) {
// Press power seven times in a row to reboot.
if (key == KEY_POWER) {
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
bool reboot_enabled = enable_reboot;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
if (reboot_enabled) {
++consecutive_power_keys;
@@ -657,9 +691,9 @@ void RecoveryUI::KeyLongPress(int) {
}
void RecoveryUI::SetEnableReboot(bool enabled) {
- pthread_mutex_lock(&key_queue_mutex);
+ pthread_mutex_lock(&event_queue_mutex);
enable_reboot = enabled;
- pthread_mutex_unlock(&key_queue_mutex);
+ pthread_mutex_unlock(&event_queue_mutex);
}
void RecoveryUI::SetLocale(const std::string& new_locale) {
diff --git a/ui.h b/ui.h
index c2339acb..824ce942 100644
--- a/ui.h
+++ b/ui.h
@@ -22,9 +22,33 @@
#include <time.h>
#include <string>
+#include <vector>
#include "voldclient.h"
+enum menu_type_t { MT_NONE, MT_LIST, MT_GRID };
+
+class MenuItem {
+ public:
+ MenuItem() {}
+ explicit MenuItem(const std::string& text,
+ const std::string& icon_name = "",
+ const std::string& icon_name_sel = "") :
+ text_(text),
+ icon_name_(icon_name),
+ icon_name_sel_(icon_name_sel) {}
+
+ const std::string& text() const { return text_; }
+ const std::string& icon_name() const { return icon_name_; }
+ const std::string& icon_name_sel() const { return icon_name_sel_; }
+
+ private:
+ std::string text_;
+ std::string icon_name_;
+ std::string icon_name_sel_;
+};
+typedef std::vector<MenuItem> MenuItemVector;
+
/*
* Simple representation of a (x,y) coordinate with convenience operators
*/
@@ -109,12 +133,37 @@ class RecoveryUI {
virtual void Print(const char* fmt, ...) __printflike(2, 3) = 0;
virtual void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3) = 0;
- virtual void ShowFile(const char* filename) = 0;
-
- // --- key handling ---
+ virtual int ShowFile(const char* filename) = 0;
+
+ // --- event handling ---
+
+ enum event_type_t { EVENT_TYPE_NONE, EVENT_TYPE_KEY, EVENT_TYPE_TOUCH };
+ class InputEvent {
+ public:
+ InputEvent() :
+ type_(EVENT_TYPE_NONE),
+ evt_({0}) {}
+ explicit InputEvent(int key) :
+ type_(EVENT_TYPE_KEY),
+ evt_({key}) {}
+ explicit InputEvent(const Point& pos) :
+ type_(EVENT_TYPE_TOUCH),
+ evt_({0}) { evt_.pos = pos; }
+
+ event_type_t type() const { return type_; }
+ int key() const { return evt_.key; }
+ const Point& pos() const { return evt_.pos; }
+
+ private:
+ event_type_t type_;
+ union {
+ int key;
+ Point pos;
+ } evt_;
+ };
// Waits for a key and return it. May return -1 after timeout.
- virtual int WaitKey();
+ virtual InputEvent WaitInputEvent();
// Cancel a WaitKey()
virtual void CancelWaitKey();
@@ -156,12 +205,16 @@ class RecoveryUI {
// Display some header text followed by a menu of items, which appears at the top of the screen
// (in place of any scrolling ui_print() output, if necessary).
- virtual void StartMenu(const char* const* headers, const char* const* items,
+ virtual void StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) = 0;
// Sets the menu highlight to the given index, wrapping if necessary. Returns the actual item
// selected.
virtual int SelectMenu(int sel) = 0;
+ virtual int SelectMenu(const Point& point) = 0;
// Ends menu mode, resetting the text overlay so that ui_print() statements will be displayed.
virtual void EndMenu() = 0;
@@ -169,8 +222,17 @@ class RecoveryUI {
// Notify of volume state change
void onVolumeChanged() { volumes_changed_ = 1; }
+ virtual bool MenuShowing() const = 0;
+ virtual bool MenuScrollable() const = 0;
+ virtual int MenuItemStart() const = 0;
+ virtual int MenuItemHeight() const = 0;
+
protected:
void EnqueueKey(int key_code);
+ void EnqueueTouch(const Point& pos);
+
+ std::string android_version_;
+ std::string lineage_version_;
// The locale that's used to show the rendered texts.
std::string locale_;
@@ -192,14 +254,15 @@ class RecoveryUI {
const int kTouchHighThreshold;
// Key event input queue
- pthread_mutex_t key_queue_mutex;
- pthread_cond_t key_queue_cond;
- int key_queue[256], key_queue_len;
- char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
- int key_last_down; // under key_queue_mutex
- bool key_long_press; // under key_queue_mutex
- int key_down_count; // under key_queue_mutex
- bool enable_reboot; // under key_queue_mutex
+ pthread_mutex_t event_queue_mutex;
+ pthread_cond_t event_queue_cond;
+ InputEvent event_queue[256];
+ int event_queue_len;
+ char key_pressed[KEY_MAX + 1]; // under event_queue_mutex
+ int key_last_down; // under event_queue_mutex
+ bool key_long_press; // under event_queue_mutex
+ int key_down_count; // under event_queue_mutex
+ bool enable_reboot; // under event_queue_mutex
int rel_sum;
int consecutive_power_keys;
@@ -211,6 +274,11 @@ class RecoveryUI {
bool has_touch_screen;
struct vkey_t {
+ bool inside (const Point& p) const {
+ return (p.x() >= min_.x() && p.x() < max_.x() &&
+ p.y() >= min_.y() && p.y() < max_.y());
+ }
+
int keycode;
Point min_;
Point max_;
@@ -218,10 +286,13 @@ class RecoveryUI {
// Touch event related variables. See the comments in RecoveryUI::OnInputEvent().
int touch_slot_;
+ bool touch_finger_down_;
+ bool touch_saw_x_;
+ bool touch_saw_y_;
+ bool touch_reported_;
Point touch_pos_;
Point touch_start_;
- bool touch_finger_down_;
- bool touch_swiping_;
+ Point touch_track_;
std::vector<vkey_t> virtual_keys_;
bool is_bootreason_recovery_ui_;
@@ -235,7 +306,9 @@ class RecoveryUI {
void OnTouchDeviceDetected(int fd);
void OnKeyDetected(int key_code);
- void OnTouchEvent();
+ void OnTouchPress();
+ void OnTouchTrack();
+ void OnTouchRelease();
int OnInputEvent(int fd, uint32_t epevents);
void ProcessKey(int key_code, int updown);
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 169ef20e..bd2ad44f 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -137,8 +137,8 @@ void WearRecoveryUI::draw_screen_locked() {
// Show the current menu item number in relation to total number if
// items don't fit on the screen.
- if (menu_items > menu_end - menu_start) {
- sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items);
+ if ((int)menu_items_.size() > menu_end - menu_start) {
+ sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, (int)menu_items_.size());
gr_text(gr_sys_font(), x + 4, y, cur_selection_str, 1);
y += char_height_ + 4;
}
@@ -147,18 +147,19 @@ void WearRecoveryUI::draw_screen_locked() {
SetColor(MENU);
for (int i = menu_start; i < menu_end; ++i) {
+ const ScreenMenuItem& item = menu_items_.at(i);
if (i == menu_sel) {
// draw the highlight bar
SetColor(MENU_SEL_BG);
gr_fill(x, y - 2, gr_fb_width() - x, y + char_height_ + 2);
// white text of selected item
SetColor(MENU_SEL_FG);
- if (menu_[i][0]) {
- gr_text(gr_sys_font(), x + 4, y, menu_[i], 1);
+ if (!item.text().empty()) {
+ gr_text(gr_sys_font(), x + 4, y, item.text().c_str(), 1);
}
SetColor(MENU);
- } else if (menu_[i][0]) {
- gr_text(gr_sys_font(), x + 4, y, menu_[i], 0);
+ } else if (!item.text().empty()) {
+ gr_text(gr_sys_font(), x + 4, y, item.text().c_str(), 0);
}
y += char_height_ + 4;
}
@@ -250,7 +251,10 @@ void WearRecoveryUI::Print(const char* fmt, ...) {
pthread_mutex_unlock(&updateMutex);
}
-void WearRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
+void WearRecoveryUI::StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) {
pthread_mutex_lock(&updateMutex);
if (text_rows_ > 0 && text_cols_ > 0) {
@@ -261,16 +265,14 @@ void WearRecoveryUI::StartMenu(const char* const* headers, const char* const* it
// Because WearRecoveryUI supports scrollable menu, it's fine to have
// more entries than text_rows_. The menu may be truncated otherwise.
// Bug: 23752519
- for (; items[i] != nullptr; i++) {
- strncpy(menu_[i], items[i], text_cols_ - 1);
- menu_[i][text_cols_ - 1] = '\0';
+ for (auto& item : items) {
+ menu_items_.push_back(ScreenMenuItem(item));
}
- menu_items = i;
show_menu = true;
menu_sel = initial_selection;
menu_start = 0;
menu_end = visible_text_rows - 1 - kMenuUnusableRows;
- if (menu_items <= menu_end) menu_end = menu_items;
+ if ((int)menu_items_.size() <= menu_end) menu_end = (int)menu_items_.size();
update_screen_locked();
}
pthread_mutex_unlock(&updateMutex);
@@ -283,11 +285,11 @@ int WearRecoveryUI::SelectMenu(int sel) {
old_sel = menu_sel;
menu_sel = sel;
if (menu_sel < 0) menu_sel = 0;
- if (menu_sel >= menu_items) menu_sel = menu_items - 1;
+ if (menu_sel >= (int)menu_items_.size()) menu_sel = (int)menu_items_.size() - 1;
if (menu_sel < menu_start) {
menu_start--;
menu_end--;
- } else if (menu_sel >= menu_end && menu_sel < menu_items) {
+ } else if (menu_sel >= menu_end && menu_sel < (int)menu_items_.size()) {
menu_end++;
menu_start++;
}
@@ -298,7 +300,11 @@ int WearRecoveryUI::SelectMenu(int sel) {
return sel;
}
-void WearRecoveryUI::ShowFile(FILE* fp) {
+int WearRecoveryUI::SelectMenu(const Point& point) {
+ return -1;
+}
+
+int WearRecoveryUI::ShowFile(FILE* fp) {
std::vector<off_t> offsets;
offsets.push_back(ftello(fp));
ClearText();
@@ -315,10 +321,14 @@ void WearRecoveryUI::ShowFile(FILE* fp) {
Redraw();
while (show_prompt) {
show_prompt = false;
- int key = WaitKey();
- if (key == KEY_POWER || key == KEY_ENTER) {
- return;
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ RecoveryUI::InputEvent evt = WaitInputEvent();
+ if (evt.type() != RecoveryUI::EVENT_TYPE_KEY) {
+ show_prompt = true;
+ continue;
+ }
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER) {
+ return evt.key();
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP) {
if (offsets.size() <= 1) {
show_prompt = true;
} else {
@@ -327,7 +337,7 @@ void WearRecoveryUI::ShowFile(FILE* fp) {
}
} else {
if (feof(fp)) {
- return;
+ return -1;
}
offsets.push_back(ftello(fp));
}
@@ -347,6 +357,7 @@ void WearRecoveryUI::ShowFile(FILE* fp) {
}
}
}
+ return -1;
}
void WearRecoveryUI::PutChar(char ch) {
@@ -359,14 +370,15 @@ void WearRecoveryUI::PutChar(char ch) {
pthread_mutex_unlock(&updateMutex);
}
-void WearRecoveryUI::ShowFile(const char* filename) {
+int WearRecoveryUI::ShowFile(const char* filename) {
FILE* fp = fopen_path(filename, "re");
if (fp == nullptr) {
Print(" Unable to open %s: %s\n", filename, strerror(errno));
- return;
+ return -1;
}
- ShowFile(fp);
+ int key = ShowFile(fp);
fclose(fp);
+ return key;
}
void WearRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) {
diff --git a/wear_ui.h b/wear_ui.h
index 3bd90b69..1a412b8f 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -32,13 +32,17 @@ class WearRecoveryUI : public ScreenRecoveryUI {
// printing messages
void Print(const char* fmt, ...) override;
void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
- void ShowFile(const char* filename) override;
- void ShowFile(FILE* fp) override;
+ int ShowFile(const char* filename) override;
+ int ShowFile(FILE* fp) override;
// menu display
- void StartMenu(const char* const* headers, const char* const* items,
+ void StartMenu(bool is_main,
+ menu_type_t type,
+ const char* const* headers,
+ const MenuItemVector& items,
int initial_selection) override;
int SelectMenu(int sel) override;
+ int SelectMenu(const Point& point) override;
protected:
// progress bar vertical position, it's centered horizontally