From da584a2e6df7045c080aceca9d3a8a3fee0081db Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Tue, 8 Dec 2015 16:24:35 -0800 Subject: recovery: Menu rewrites and cleanups * Introduce a menu stack for navigating sub-menus. The menu data structure format is a bit messy, but necessary in order to provide a string list for the ui. * Create "advanced" sub-menu for rarely used and dangerous commands. * Create "factory reset" sub-menu for various reset and wipe commands. * Separate "wipe data" and "factory reset" items. Change-Id: Ib9bc6967b98d022880cfe7fa8e324cd64b07d248 --- device.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++++++----------- device.h | 31 ++++++++------- recovery.cpp | 18 +++++---- 3 files changed, 126 insertions(+), 43 deletions(-) diff --git a/device.cpp b/device.cpp index 0ac6b3f..4f19f0e 100644 --- a/device.cpp +++ b/device.cpp @@ -16,42 +16,119 @@ #include "device.h" -static const char* MENU_ITEMS[] = { - "Reboot system now", +enum menu_action_type { + ACTION_NONE, + ACTION_SUBMENU, + ACTION_INVOKE +}; + +struct menu_entry; +struct menu { + const char** names; + const menu_entry* entries; +}; + +union menu_action { + const menu* submenu; + Device::BuiltinAction action; +}; + +struct menu_entry { + menu_action_type action_type; + const menu_action action; +}; + +static const char* WIPE_MENU_NAMES[] = { + "System reset (keep media)", + "Full factory reset", + "Wipe cache partition", + nullptr +}; +static const menu_entry WIPE_MENU_ENTRIES[] = { + { ACTION_INVOKE, { .action = Device::WIPE_DATA } }, + { ACTION_INVOKE, { .action = Device::WIPE_FULL } }, + { ACTION_INVOKE, { .action = Device::WIPE_CACHE } }, + { ACTION_NONE, { .action = Device::NO_ACTION } } +}; +static const menu WIPE_MENU = { + WIPE_MENU_NAMES, + WIPE_MENU_ENTRIES +}; + +static const char* ADVANCED_MENU_NAMES[] = { + "Reboot recovery", #ifdef DOWNLOAD_MODE "Reboot to download mode", #else "Reboot to bootloader", #endif - "Apply update", - "Wipe data/factory reset", - "Wipe cache partition", - "Wipe media", "Mount /system", "View recovery logs", "Power off", - NULL + nullptr +}; +static const menu_entry ADVANCED_MENU_ENTRIES[] = { + { ACTION_INVOKE, { .action = Device::REBOOT_RECOVERY } }, +#ifdef DOWNLOAD_MODE + { ACTION_INVOKE, { .action = Device::REBOOT_BOOTLOADER } }, +#else + { ACTION_INVOKE, { .action = Device::REBOOT_BOOTLOADER } }, +#endif + { ACTION_INVOKE, { .action = Device::MOUNT_SYSTEM } }, + { ACTION_INVOKE, { .action = Device::VIEW_RECOVERY_LOGS } }, + { ACTION_INVOKE, { .action = Device::SHUTDOWN } }, + { ACTION_NONE, { .action = Device::NO_ACTION } } +}; +static const menu ADVANCED_MENU = { + ADVANCED_MENU_NAMES, + ADVANCED_MENU_ENTRIES +}; + +static const char* MAIN_MENU_NAMES[] = { + "Reboot system now", + "Apply update", + "Factory reset", + "Advanced", + nullptr +}; +static const menu_entry MAIN_MENU_ENTRIES[] = { + { ACTION_INVOKE, { .action = Device::REBOOT } }, + { ACTION_INVOKE, { .action = Device::APPLY_UPDATE } }, + { ACTION_SUBMENU, { .submenu = &WIPE_MENU } }, + { ACTION_SUBMENU, { .submenu = &ADVANCED_MENU } }, + { ACTION_NONE, { .action = Device::NO_ACTION } } +}; +static const menu MAIN_MENU = { + MAIN_MENU_NAMES, + MAIN_MENU_ENTRIES }; -extern int ui_root_menu; +Device::Device(RecoveryUI* ui) : + ui_(ui) { + menu_stack.push(&MAIN_MENU); +} const char* const* Device::GetMenuItems() { - return MENU_ITEMS; + const menu* m = menu_stack.top(); + return m->names; } Device::BuiltinAction Device::InvokeMenuItem(int menu_position) { - switch (menu_position) { - case 0: return REBOOT; - case 1: return REBOOT_BOOTLOADER; - case 2: return APPLY_UPDATE; - case 3: return WIPE_DATA; - case 4: return WIPE_CACHE; - case 5: return WIPE_MEDIA; - case 6: return MOUNT_SYSTEM; - case 7: return VIEW_RECOVERY_LOGS; - case 8: return SHUTDOWN; - default: return NO_ACTION; + if (menu_position < 0) { + if (menu_position == Device::kGoBack) { + if (menu_stack.size() > 1) { + menu_stack.pop(); + } + } + return NO_ACTION; + } + const menu* m = menu_stack.top(); + const menu_entry* entry = m->entries + menu_position; + if (entry->action_type == ACTION_SUBMENU) { + menu_stack.push(entry->action.submenu); + return NO_ACTION; } + return entry->action.action; } int Device::HandleMenuKey(int key, int visible) { @@ -86,8 +163,7 @@ int Device::HandleMenuKey(int key, int visible) { case KEY_BACKSPACE: case KEY_BACK: - if (!ui_root_menu) - return kGoBack; + return kGoBack; default: // If you have all of the above buttons, any other buttons diff --git a/device.h b/device.h index 1241982..dba4ac1 100644 --- a/device.h +++ b/device.h @@ -19,11 +19,15 @@ #include "ui.h" +#include + #define KEY_FLAG_ABS 0x8000 +struct menu; + class Device : public VoldWatcher { public: - Device(RecoveryUI* ui) : ui_(ui) { } + explicit Device(RecoveryUI* ui); virtual ~Device() { } // Called to obtain the UI object that should be used to display @@ -59,18 +63,17 @@ class Device : public VoldWatcher { virtual int HandleMenuKey(int key, int visible); enum BuiltinAction { - NO_ACTION = 0, - REBOOT = 1, - APPLY_UPDATE = 2, - // APPLY_CACHE was 3. - // APPLY_ADB_SIDELOAD was 4. - WIPE_DATA = 5, - WIPE_CACHE = 6, - WIPE_MEDIA = 7, - REBOOT_BOOTLOADER = 8, - SHUTDOWN = 9, - VIEW_RECOVERY_LOGS = 10, - MOUNT_SYSTEM = 11, + NO_ACTION, + REBOOT, + APPLY_UPDATE, + WIPE_DATA, + WIPE_FULL, + WIPE_CACHE, + REBOOT_RECOVERY, + REBOOT_BOOTLOADER, + SHUTDOWN, + VIEW_RECOVERY_LOGS, + MOUNT_SYSTEM, }; // Return the list of menu items (an array of strings, @@ -117,6 +120,8 @@ class Device : public VoldWatcher { private: RecoveryUI* ui_; + + std::stack menu_stack; }; // The device-specific library must define this function (or the diff --git a/recovery.cpp b/recovery.cpp index 5c9f43f..3ecd5db 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1025,8 +1025,6 @@ refresh: return status; } -int ui_root_menu = 0; - // Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION // means to take the default, which is to reboot or shutdown depending // on if the --shutdown_after flag was passed to recovery. @@ -1034,7 +1032,6 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) { for (;;) { finish_recovery(NULL); - ui_root_menu = 1; switch (status) { case INSTALL_SUCCESS: case INSTALL_NONE: @@ -1049,7 +1046,6 @@ prompt_and_wait(Device* device, int status) { ui->SetProgressType(RecoveryUI::EMPTY); int chosen_item = get_menu_selection(nullptr, device->GetMenuItems(), 0, 0, device); - ui_root_menu = 0; // device-specific code may take some action here. It may // return one of the core actions handled in the switch @@ -1064,6 +1060,7 @@ prompt_and_wait(Device* device, int status) { case Device::REBOOT: case Device::SHUTDOWN: + case Device::REBOOT_RECOVERY: case Device::REBOOT_BOOTLOADER: return chosen_action; @@ -1072,13 +1069,13 @@ prompt_and_wait(Device* device, int status) { if (!ui->IsTextVisible()) return Device::NO_ACTION; break; - case Device::WIPE_CACHE: - wipe_cache(ui->IsTextVisible(), device); + case Device::WIPE_FULL: + wipe_data(ui->IsTextVisible(), device, true); if (!ui->IsTextVisible()) return Device::NO_ACTION; break; - case Device::WIPE_MEDIA: - wipe_media(ui->IsTextVisible(), device); + case Device::WIPE_CACHE: + wipe_cache(ui->IsTextVisible(), device); if (!ui->IsTextVisible()) return Device::NO_ACTION; break; @@ -1516,6 +1513,11 @@ main(int argc, char **argv) { property_set(ANDROID_RB_PROPERTY, "shutdown,"); break; + case Device::REBOOT_RECOVERY: + ui->Print("Rebooting recovery...\n"); + property_set(ANDROID_RB_PROPERTY, "reboot,recovery"); + break; + case Device::REBOOT_BOOTLOADER: #ifdef DOWNLOAD_MODE ui->Print("Rebooting to download mode...\n"); -- cgit v1.1