diff options
Diffstat (limited to 'recovery.c')
-rw-r--r-- | recovery.c | 246 |
1 files changed, 152 insertions, 94 deletions
diff --git a/recovery.c b/recovery.c index 0ff5d94d0..438530710 100644 --- a/recovery.c +++ b/recovery.c @@ -36,12 +36,14 @@ #include "minui/minui.h" #include "minzip/DirUtil.h" #include "roots.h" +#include "recovery_ui.h" static const struct option OPTIONS[] = { { "send_intent", required_argument, NULL, 's' }, { "update_package", required_argument, NULL, 'u' }, { "wipe_data", no_argument, NULL, 'w' }, { "wipe_cache", no_argument, NULL, 'c' }, + { NULL, 0, NULL, 0 }, }; static const char *COMMAND_FILE = "CACHE:recovery/command"; @@ -206,6 +208,15 @@ get_args(int *argc, char ***argv) { set_bootloader_message(&boot); } +static void +set_sdcard_update_bootloader_message() +{ + struct bootloader_message boot; + memset(&boot, 0, sizeof(boot)); + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); + set_bootloader_message(&boot); +} // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and @@ -269,116 +280,159 @@ erase_root(const char *root) return format_root_device(root); } -static void -prompt_and_wait() -{ - char* headers[] = { "Android system recovery <" +static char** +prepend_title(char** headers) { + char* title[] = { "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>", - "", - "Use trackball to highlight;", - "click to select.", - "", - NULL }; - - // these constants correspond to elements of the items[] list. -#define ITEM_REBOOT 0 -#define ITEM_APPLY_SDCARD 1 -#define ITEM_WIPE_DATA 2 -#define ITEM_WIPE_CACHE 3 - char* items[] = { "reboot system now [Home+Back]", - "apply sdcard:update.zip [Alt+S]", - "wipe data/factory reset [Alt+W]", - "wipe cache partition", + "", NULL }; + // count the number of lines in our title, plus the + // caller-provided headers. + int count = 0; + char** p; + for (p = title; *p; ++p, ++count); + for (p = headers; *p; ++p, ++count); + + char** new_headers = malloc((count+1) * sizeof(char*)); + char** h = new_headers; + for (p = title; *p; ++p, ++h) *h = *p; + for (p = headers; *p; ++p, ++h) *h = *p; + *h = NULL; + + return new_headers; +} + +static int +get_menu_selection(char** headers, char** items, int menu_only) { + // throw away keys pressed previously, so user doesn't + // accidentally trigger menu items. + ui_clear_key_queue(); + ui_start_menu(headers, items); int selected = 0; int chosen_item = -1; - finish_recovery(NULL); - ui_reset_progress(); - for (;;) { + while (chosen_item < 0) { int key = ui_wait_key(); - int alt = ui_key_pressed(KEY_LEFTALT) || ui_key_pressed(KEY_RIGHTALT); int visible = ui_text_visible(); - if (key == KEY_DREAM_BACK && ui_key_pressed(KEY_DREAM_HOME)) { - // Wait for the keys to be released, to avoid triggering - // special boot modes (like coming back into recovery!). - while (ui_key_pressed(KEY_DREAM_BACK) || - ui_key_pressed(KEY_DREAM_HOME)) { - usleep(1000); - } - chosen_item = ITEM_REBOOT; - } else if (alt && key == KEY_W) { - chosen_item = ITEM_WIPE_DATA; - } else if (alt && key == KEY_S) { - chosen_item = ITEM_APPLY_SDCARD; - } else if ((key == KEY_DOWN || key == KEY_VOLUMEDOWN) && visible) { - ++selected; - selected = ui_menu_select(selected); - } else if ((key == KEY_UP || key == KEY_VOLUMEUP) && visible) { - --selected; - selected = ui_menu_select(selected); - } else if (key == BTN_MOUSE && visible) { - chosen_item = selected; - } + int action = device_handle_key(key, visible); - if (chosen_item >= 0) { - // turn off the menu, letting ui_print() to scroll output - // on the screen. - ui_end_menu(); - - switch (chosen_item) { - case ITEM_REBOOT: - return; - - case ITEM_WIPE_DATA: - ui_print("\n-- Wiping data...\n"); - erase_root("DATA:"); - erase_root("CACHE:"); - ui_print("Data wipe complete.\n"); - if (!ui_text_visible()) return; + if (action < 0) { + switch (action) { + case HIGHLIGHT_UP: + --selected; + selected = ui_menu_select(selected); break; - - case ITEM_WIPE_CACHE: - ui_print("\n-- Wiping cache...\n"); - erase_root("CACHE:"); - ui_print("Cache wipe complete.\n"); - if (!ui_text_visible()) return; + case HIGHLIGHT_DOWN: + ++selected; + selected = ui_menu_select(selected); break; - - case ITEM_APPLY_SDCARD: - ui_print("\n-- Install from sdcard...\n"); - int status = install_package(SDCARD_PACKAGE_FILE); - if (status != INSTALL_SUCCESS) { - ui_set_background(BACKGROUND_ICON_ERROR); - ui_print("Installation aborted.\n"); - } else if (!ui_text_visible()) { - return; // reboot if logs aren't visible - } else { - if (firmware_update_pending()) { - ui_print("\nReboot via home+back or menu\n" - "to complete installation.\n"); - } else { - ui_print("\nInstall from sdcard complete.\n"); - } - } + case SELECT_ITEM: + chosen_item = selected; + break; + case NO_ACTION: break; } + } else if (!menu_only) { + chosen_item = action; + } + } + + ui_end_menu(); + return chosen_item; +} + +static void +wipe_data(int confirm) { + if (confirm) { + static char** title_headers = NULL; + + if (title_headers == NULL) { + char* headers[] = { "Confirm wipe of all user data?", + " THIS CAN NOT BE UNDONE.", + "", + NULL }; + title_headers = prepend_title(headers); + } + + char* items[] = { " No", + " No", + " No", + " No", + " No", + " No", + " No", + " Yes -- delete all user data", // [7] + " No", + " No", + " No", + NULL }; + + int chosen_item = get_menu_selection(title_headers, items, 1); + if (chosen_item != 7) { + return; + } + } - // if we didn't return from this function to reboot, show - // the menu again. - ui_start_menu(headers, items); - selected = 0; - chosen_item = -1; + ui_print("\n-- Wiping data...\n"); + device_wipe_data(); + erase_root("DATA:"); + erase_root("CACHE:"); + ui_print("Data wipe complete.\n"); +} - finish_recovery(NULL); - ui_reset_progress(); +static void +prompt_and_wait() +{ + char** headers = prepend_title(MENU_HEADERS); - // throw away keys pressed while the command was running, - // so user doesn't accidentally trigger menu items. - ui_clear_key_queue(); + for (;;) { + finish_recovery(NULL); + ui_reset_progress(); + + int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0); + + // device-specific code may take some action here. It may + // return one of the core actions handled in the switch + // statement below. + chosen_item = device_perform_action(chosen_item); + + switch (chosen_item) { + case ITEM_REBOOT: + return; + + case ITEM_WIPE_DATA: + wipe_data(ui_text_visible()); + if (!ui_text_visible()) return; + break; + + case ITEM_WIPE_CACHE: + ui_print("\n-- Wiping cache...\n"); + erase_root("CACHE:"); + ui_print("Cache wipe complete.\n"); + if (!ui_text_visible()) return; + break; + + case ITEM_APPLY_SDCARD: + ui_print("\n-- Install from sdcard...\n"); + set_sdcard_update_bootloader_message(); + int status = install_package(SDCARD_PACKAGE_FILE); + if (status != INSTALL_SUCCESS) { + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Installation aborted.\n"); + } else if (!ui_text_visible()) { + return; // reboot if logs aren't visible + } else { + if (firmware_update_pending()) { + ui_print("\nReboot via menu to complete\n" + "installation.\n"); + } else { + ui_print("\nInstall from sdcard complete.\n"); + } + } + break; } } } @@ -435,10 +489,14 @@ main(int argc, char **argv) if (update_package != NULL) { status = install_package(update_package); if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); - } else if (wipe_data || wipe_cache) { - if (wipe_data && erase_root("DATA:")) status = INSTALL_ERROR; + } else if (wipe_data) { + if (device_wipe_data()) status = INSTALL_ERROR; + if (erase_root("DATA:")) status = INSTALL_ERROR; if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); + } else if (wipe_cache) { + if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR; + if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); } else { status = INSTALL_ERROR; // No command specified } |