diff options
author | Yu-Ping Wu <yupingso@chromium.org> | 2020-05-13 12:36:43 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-01 07:52:30 +0000 |
commit | 251c0f23f57f54dcc3bb91b4ef78598e971afa1f (patch) | |
tree | a4b62bf68430c7f2c2a09ec5d027f17ad1242b65 | |
parent | 402d191efef56e88d30d270a5ce0c9f11b2f75e0 (diff) | |
download | vboot-251c0f23f57f54dcc3bb91b4ef78598e971afa1f.tar.gz |
vboot/ui: implement language selection screen
Implement language selection screen, and add language item to all the
other screens. Add a default screen init function default_screen_init()
to initialize the default selection to the second item if the first item
is the language selection.
BRANCH=none
BUG=b:146399181, b:144968920
TEST=make runtests
TEST=USE="menu_ui" emerge-nami depthcharge
Cq-Depend: chromium:2193151, chromium:2192508
Change-Id: I3251b0095ec29ec26cc27745b1089e60894c892c
Signed-off-by: Yu-Ping Wu <yupingso@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2196095
Reviewed-by: Joel Kitching <kitching@chromium.org>
-rw-r--r-- | firmware/2lib/2ui.c | 49 | ||||
-rw-r--r-- | firmware/2lib/2ui_screens.c | 145 | ||||
-rw-r--r-- | firmware/2lib/include/2ui.h | 41 | ||||
-rw-r--r-- | firmware/2lib/include/2ui_private.h | 2 | ||||
-rw-r--r-- | tests/vb2_ui_action_tests.c | 27 | ||||
-rw-r--r-- | tests/vb2_ui_tests.c | 69 | ||||
-rw-r--r-- | tests/vb2_ui_utility_tests.c | 66 |
7 files changed, 328 insertions, 71 deletions
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c index eaa2bc4f..ee0da1f1 100644 --- a/firmware/2lib/2ui.c +++ b/firmware/2lib/2ui.c @@ -73,6 +73,21 @@ vb2_error_t check_shutdown_request(struct vb2_ui_context *ui) /*****************************************************************************/ /* Menu navigation functions */ +const struct vb2_menu *get_menu(struct vb2_ui_context *ui) +{ + const struct vb2_menu *menu; + static const struct vb2_menu empty_menu = { + .num_items = 0, + .items = NULL, + }; + if (ui->state.screen->get_menu) { + menu = ui->state.screen->get_menu(ui); + return menu ? menu : &empty_menu; + } else { + return &ui->state.screen->menu; + } +} + vb2_error_t menu_navigation_action(struct vb2_ui_context *ui) { uint32_t key = ui->key; @@ -126,16 +141,18 @@ vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui) vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui) { int item; + const struct vb2_menu *menu; if (!DETACHABLE && ui->key == VB_BUTTON_VOL_DOWN_SHORT_PRESS) return VB2_REQUEST_UI_CONTINUE; + menu = get_menu(ui); item = ui->state.selected_item + 1; - while (item < ui->state.screen->num_items && + while (item < menu->num_items && ((1 << item) & ui->state.disabled_item_mask)) item++; /* Only update if item is valid */ - if (item < ui->state.screen->num_items) + if (item < menu->num_items) ui->state.selected_item = item; return VB2_REQUEST_UI_CONTINUE; @@ -143,15 +160,17 @@ vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui) vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui) { + const struct vb2_menu *menu; const struct vb2_menu_item *menu_item; if (!DETACHABLE && ui->key == VB_BUTTON_POWER_SHORT_PRESS) return VB2_REQUEST_UI_CONTINUE; - if (ui->state.screen->num_items == 0) + menu = get_menu(ui); + if (menu->num_items == 0) return VB2_REQUEST_UI_CONTINUE; - menu_item = &ui->state.screen->items[ui->state.selected_item]; + menu_item = &menu->items[ui->state.selected_item]; if (menu_item->action) { VB2_DEBUG("Menu item <%s> run action\n", menu_item->text); @@ -175,6 +194,15 @@ vb2_error_t vb2_ui_change_root(struct vb2_ui_context *ui) return vb2_ui_change_screen(ui, ui->root_screen->id); } +static vb2_error_t default_screen_init(struct vb2_ui_context *ui) +{ + const struct vb2_menu *menu = get_menu(ui); + ui->state.selected_item = 0; + if (menu->num_items > 1 && menu->items[0].is_language_select) + ui->state.selected_item = 1; + return VB2_REQUEST_UI_CONTINUE; +} + vb2_error_t vb2_ui_change_screen(struct vb2_ui_context *ui, enum vb2_screen id) { const struct vb2_screen_info *new_screen_info; @@ -195,8 +223,8 @@ vb2_error_t vb2_ui_change_screen(struct vb2_ui_context *ui, enum vb2_screen id) if (ui->state.screen->init) return ui->state.screen->init(ui); - - return VB2_REQUEST_UI_CONTINUE; + else + return default_screen_init(ui); } /*****************************************************************************/ @@ -207,6 +235,7 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, { struct vb2_ui_context ui; struct vb2_screen_state prev_state; + const struct vb2_menu *menu; uint32_t key_flags; vb2_error_t rv; @@ -215,6 +244,7 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, ui.root_screen = vb2_get_screen_info(root_screen_id); if (ui.root_screen == NULL) VB2_DIE("Root screen not found.\n"); + ui.locale_id = vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX); rv = vb2_ui_change_screen(&ui, ui.root_screen->id); if (rv != VB2_REQUEST_UI_CONTINUE) return rv; @@ -225,11 +255,12 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, if (memcmp(&prev_state, &ui.state, sizeof(ui.state))) { memcpy(&prev_state, &ui.state, sizeof(ui.state)); + menu = get_menu(&ui); VB2_DEBUG("<%s> menu item <%s>\n", ui.state.screen->name, - ui.state.screen->num_items ? - ui.state.screen->items[ - ui.state.selected_item].text : "null"); + menu->num_items ? + menu->items[ui.state.selected_item].text : + "null"); vb2ex_display_ui(ui.state.screen->id, ui.locale_id, ui.state.selected_item, diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c index 50a61423..612a08c8 100644 --- a/firmware/2lib/2ui_screens.c +++ b/firmware/2lib/2ui_screens.c @@ -5,6 +5,7 @@ * Firmware screen definitions. */ +#include "2api.h" #include "2common.h" #include "2misc.h" #include "2nvstorage.h" @@ -13,9 +14,16 @@ #include "vboot_api.h" #include "vboot_kernel.h" -#define MENU_ITEMS(a) \ +#define MENU_ITEMS(a) ((struct vb2_menu){ \ .num_items = ARRAY_SIZE(a), \ - .items = a + .items = a, \ +}) + +#define LANGUAGE_SELECT_ITEM { \ + .text = "Language selection", \ + .target = VB2_SCREEN_LANGUAGE_SELECT, \ + .is_language_select = 1, \ +} #define ADVANCED_OPTIONS_ITEM { \ .text = "Advanced options", \ @@ -31,26 +39,105 @@ static const struct vb2_screen_info blank_screen = { }; /******************************************************************************/ +/* VB2_SCREEN_LANGUAGE_SELECT */ + +static vb2_error_t language_select_action(struct vb2_ui_context *ui) +{ + vb2_error_t rv; + ui->locale_id = ui->state.selected_item; + VB2_DEBUG("Locale changed to %u\n", ui->locale_id); + + /* Write locale id back to nvdata. */ + vb2_nv_set(ui->ctx, VB2_NV_LOCALIZATION_INDEX, ui->locale_id); + + /* Commit nvdata changes immediately, in case of three-finger salute + reboot. Ignore commit errors in recovery mode. */ + rv = vb2ex_commit_data(ui->ctx); + if (rv && !(ui->ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) + return rv; + + return vb2_ui_change_root(ui); +} + +const struct vb2_menu *get_language_menu(struct vb2_ui_context *ui) +{ + int i; + uint32_t num_locales; + struct vb2_menu_item *items; + + if (ui->language_menu.num_items > 0) + return &ui->language_menu; + + num_locales = vb2ex_get_locale_count(); + if (num_locales == 0) { + VB2_DEBUG("WARNING: No locales available; assuming 1 locale\n"); + num_locales = 1; + } + + items = malloc(num_locales * sizeof(struct vb2_menu_item)); + if (!items) { + VB2_DEBUG("ERROR: malloc failed for language items\n"); + return NULL; + } + + for (i = 0; i < num_locales; i++) { + items[i].text = "Some language"; + items[i].action = language_select_action; + } + + ui->language_menu.num_items = num_locales; + ui->language_menu.items = items; + return &ui->language_menu; +} + +static vb2_error_t language_select_init(struct vb2_ui_context *ui) +{ + const struct vb2_menu *menu = get_menu(ui); + if (menu->num_items == 0) { + VB2_DEBUG("ERROR: No menu items found; " + "rejecting entering language selection screen\n"); + return vb2_ui_change_root(ui); + } + if (ui->locale_id < menu->num_items) { + ui->state.selected_item = ui->locale_id; + } else { + VB2_DEBUG("WARNING: Current locale not found in menu items; " + "initializing selected_item to 0\n"); + ui->state.selected_item = 0; + } + return VB2_REQUEST_UI_CONTINUE; +} + +static const struct vb2_screen_info language_select_screen = { + .id = VB2_SCREEN_LANGUAGE_SELECT, + .name = "Language selection screen", + .init = language_select_init, + .get_menu = get_language_menu, +}; + +/******************************************************************************/ /* VB2_SCREEN_RECOVERY_BROKEN */ static const struct vb2_menu_item recovery_broken_items[] = { + LANGUAGE_SELECT_ITEM, ADVANCED_OPTIONS_ITEM, }; static const struct vb2_screen_info recovery_broken_screen = { .id = VB2_SCREEN_RECOVERY_BROKEN, .name = "Recover broken device", - MENU_ITEMS(recovery_broken_items), + .menu = MENU_ITEMS(recovery_broken_items), }; /******************************************************************************/ /* VB2_SCREEN_ADVANCED_OPTIONS */ -#define ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE 0 -#define ADVANCED_OPTIONS_ITEM_BACK 1 +#define ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE 1 +#define ADVANCED_OPTIONS_ITEM_BACK 2 vb2_error_t advanced_options_init(struct vb2_ui_context *ui) { + ui->state.selected_item = ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE; if (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) { ui->state.disabled_item_mask |= 1 << ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE; @@ -61,6 +148,7 @@ vb2_error_t advanced_options_init(struct vb2_ui_context *ui) } static const struct vb2_menu_item advanced_options_items[] = { + LANGUAGE_SELECT_ITEM, [ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE] = { .text = "Enable developer mode", .target = VB2_SCREEN_RECOVERY_TO_DEV, @@ -75,17 +163,18 @@ static const struct vb2_screen_info advanced_options_screen = { .id = VB2_SCREEN_ADVANCED_OPTIONS, .name = "Advanced options", .init = advanced_options_init, - MENU_ITEMS(advanced_options_items), + .menu = MENU_ITEMS(advanced_options_items), }; /******************************************************************************/ /* VB2_SCREEN_RECOVERY_SELECT */ -#define RECOVERY_SELECT_ITEM_PHONE 0 -#define RECOVERY_SELECT_ITEM_EXTERNAL_DISK 1 +#define RECOVERY_SELECT_ITEM_PHONE 1 +#define RECOVERY_SELECT_ITEM_EXTERNAL_DISK 2 vb2_error_t recovery_select_init(struct vb2_ui_context *ui) { + ui->state.selected_item = RECOVERY_SELECT_ITEM_PHONE; if (!vb2api_phone_recovery_enabled(ui->ctx)) { VB2_DEBUG("WARNING: Phone recovery not available\n"); ui->state.disabled_item_mask |= @@ -96,6 +185,7 @@ vb2_error_t recovery_select_init(struct vb2_ui_context *ui) } static const struct vb2_menu_item recovery_select_items[] = { + LANGUAGE_SELECT_ITEM, [RECOVERY_SELECT_ITEM_PHONE] = { .text = "Recovery using phone", .target = VB2_SCREEN_RECOVERY_PHONE_STEP1, @@ -111,22 +201,27 @@ static const struct vb2_screen_info recovery_select_screen = { .id = VB2_SCREEN_RECOVERY_SELECT, .name = "Recovery method selection", .init = recovery_select_init, - MENU_ITEMS(recovery_select_items), + .menu = MENU_ITEMS(recovery_select_items), }; /******************************************************************************/ /* VB2_SCREEN_RECOVERY_INVALID */ +static const struct vb2_menu_item recovery_invalid_items[] = { + LANGUAGE_SELECT_ITEM, +}; + static const struct vb2_screen_info recovery_invalid_screen = { .id = VB2_SCREEN_RECOVERY_INVALID, .name = "Invalid recovery inserted", + .menu = MENU_ITEMS(recovery_invalid_items), }; /******************************************************************************/ /* VB2_SCREEN_RECOVERY_TO_DEV */ -#define RECOVERY_TO_DEV_ITEM_CONFIRM 0 -#define RECOVERY_TO_DEV_ITEM_CANCEL 1 +#define RECOVERY_TO_DEV_ITEM_CONFIRM 1 +#define RECOVERY_TO_DEV_ITEM_CANCEL 2 vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui) { @@ -140,6 +235,8 @@ vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui) return vb2_ui_change_root(ui); } + ui->state.selected_item = RECOVERY_TO_DEV_ITEM_CONFIRM; + /* Disable "Confirm" button for other physical presence types. */ if (!PHYSICAL_PRESENCE_KEYBOARD) { ui->state.disabled_item_mask |= @@ -207,6 +304,7 @@ vb2_error_t recovery_to_dev_action(struct vb2_ui_context *ui) } static const struct vb2_menu_item recovery_to_dev_items[] = { + LANGUAGE_SELECT_ITEM, [RECOVERY_TO_DEV_ITEM_CONFIRM] = { .text = "Confirm", .action = recovery_to_dev_confirm_action, @@ -222,31 +320,41 @@ static const struct vb2_screen_info recovery_to_dev_screen = { .name = "Transition to developer mode", .init = recovery_to_dev_init, .action = recovery_to_dev_action, - MENU_ITEMS(recovery_to_dev_items), + .menu = MENU_ITEMS(recovery_to_dev_items), }; /******************************************************************************/ /* VB2_SCREEN_RECOVERY_PHONE_STEP1 */ +static const struct vb2_menu_item recovery_phone_step1_items[] = { + LANGUAGE_SELECT_ITEM, +}; + static const struct vb2_screen_info recovery_phone_step1_screen = { .id = VB2_SCREEN_RECOVERY_PHONE_STEP1, .name = "Phone recovery step 1", + .menu = MENU_ITEMS(recovery_phone_step1_items), }; /******************************************************************************/ /* VB2_SCREEN_RECOVERY_DISK_STEP1 */ +static const struct vb2_menu_item recovery_disk_step1_items[] = { + LANGUAGE_SELECT_ITEM, +}; + static const struct vb2_screen_info recovery_disk_step1_screen = { .id = VB2_SCREEN_RECOVERY_DISK_STEP1, .name = "Disk recovery step 1", + .menu = MENU_ITEMS(recovery_disk_step1_items), }; /******************************************************************************/ /* VB2_SCREEN_DEVELOPER_MODE */ -#define DEVELOPER_MODE_ITEM_RETURN_TO_SECURE 0 -#define DEVELOPER_MODE_ITEM_BOOT_INTERNAL 1 -#define DEVELOPER_MODE_ITEM_BOOT_EXTERNAL 2 +#define DEVELOPER_MODE_ITEM_RETURN_TO_SECURE 1 +#define DEVELOPER_MODE_ITEM_BOOT_INTERNAL 2 +#define DEVELOPER_MODE_ITEM_BOOT_EXTERNAL 3 vb2_error_t developer_mode_init(struct vb2_ui_context *ui) { @@ -353,6 +461,7 @@ vb2_error_t developer_mode_action(struct vb2_ui_context *ui) } static const struct vb2_menu_item developer_mode_items[] = { + LANGUAGE_SELECT_ITEM, [DEVELOPER_MODE_ITEM_RETURN_TO_SECURE] = { .text = "Return to secure mode", .target = VB2_SCREEN_DEVELOPER_TO_NORM, @@ -373,7 +482,7 @@ static const struct vb2_screen_info developer_mode_screen = { .name = "Developer mode", .init = developer_mode_init, .action = developer_mode_action, - MENU_ITEMS(developer_mode_items), + .menu = MENU_ITEMS(developer_mode_items), }; /******************************************************************************/ @@ -392,6 +501,7 @@ vb2_error_t developer_to_norm_action(struct vb2_ui_context *ui) } static const struct vb2_menu_item developer_to_norm_items[] = { + LANGUAGE_SELECT_ITEM, { .text = "Confirm", .action = developer_to_norm_action, @@ -405,7 +515,7 @@ static const struct vb2_menu_item developer_to_norm_items[] = { static const struct vb2_screen_info developer_to_norm_screen = { .id = VB2_SCREEN_DEVELOPER_TO_NORM, .name = "Transition to normal mode", - MENU_ITEMS(developer_to_norm_items), + .menu = MENU_ITEMS(developer_to_norm_items), }; /******************************************************************************/ @@ -418,6 +528,7 @@ static const struct vb2_screen_info developer_to_norm_screen = { */ static const struct vb2_screen_info *screens[] = { &blank_screen, + &language_select_screen, &recovery_broken_screen, &advanced_options_screen, &recovery_select_screen, diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h index eee1565f..49f51b32 100644 --- a/firmware/2lib/include/2ui.h +++ b/firmware/2lib/include/2ui.h @@ -16,6 +16,24 @@ struct vb2_ui_context; /* Forward declaration */ +struct vb2_menu_item { + /* Text description */ + const char *text; + /* Target screen */ + enum vb2_screen target; + /* Action function takes precedence over target screen if non-NULL. */ + vb2_error_t (*action)(struct vb2_ui_context *ui); + /* Whether the item is language selection */ + int is_language_select; +}; + +struct vb2_menu { + /* Number of menu items */ + uint16_t num_items; + /* List of menu items */ + const struct vb2_menu_item *items; +}; + struct vb2_screen_info { /* Screen id */ enum vb2_screen id; @@ -25,19 +43,13 @@ struct vb2_screen_info { vb2_error_t (*init)(struct vb2_ui_context *ui); /* Action function runs repeatedly while on the screen. */ vb2_error_t (*action)(struct vb2_ui_context *ui); - /* Number of menu items */ - uint16_t num_items; - /* List of menu items */ - const struct vb2_menu_item *items; -}; - -struct vb2_menu_item { - /* Text description */ - const char *text; - /* Target screen */ - enum vb2_screen target; - /* Action function takes precedence over target screen if non-NULL. */ - vb2_error_t (*action)(struct vb2_ui_context *ui); + /* Menu items. */ + struct vb2_menu menu; + /* + * Custom function for getting menu items. If non-null, field 'menu' + * will be ignored. + */ + const struct vb2_menu *(*get_menu)(struct vb2_ui_context *ui); }; struct vb2_screen_state { @@ -73,6 +85,9 @@ struct vb2_ui_context { /* For to_dev transition flow. */ int physical_presence_button_pressed; + + /* For language selection screen. */ + struct vb2_menu language_menu; }; vb2_error_t vb2_ui_developer_mode_boot_internal_action( diff --git a/firmware/2lib/include/2ui_private.h b/firmware/2lib/include/2ui_private.h index c1ecd8be..e1e47af3 100644 --- a/firmware/2lib/include/2ui_private.h +++ b/firmware/2lib/include/2ui_private.h @@ -12,6 +12,7 @@ /* From 2ui.c */ vb2_error_t check_shutdown_request(struct vb2_ui_context *ui); +const struct vb2_menu *get_menu(struct vb2_ui_context *ui); vb2_error_t menu_navigation_action(struct vb2_ui_context *ui); vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id, vb2_error_t (*global_action)(struct vb2_ui_context *ui)); @@ -19,6 +20,7 @@ vb2_error_t developer_action(struct vb2_ui_context *ui); vb2_error_t manual_recovery_action(struct vb2_ui_context *ui); /* From 2ui_screens.c */ +const struct vb2_menu *get_language_menu(struct vb2_ui_context *ui); vb2_error_t advanced_options_init(struct vb2_ui_context *ui); vb2_error_t recovery_select_init(struct vb2_ui_context *ui); vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui); diff --git a/tests/vb2_ui_action_tests.c b/tests/vb2_ui_action_tests.c index ddb9ee38..e778f6ee 100644 --- a/tests/vb2_ui_action_tests.c +++ b/tests/vb2_ui_action_tests.c @@ -105,18 +105,13 @@ static vb2_error_t mock_action_flag2(struct vb2_ui_context *ui) /* Mock screens */ struct vb2_screen_info mock_screen_temp; -const struct vb2_menu_item mock_empty_menu[] = {}; const struct vb2_screen_info mock_screen_blank = { .id = VB2_SCREEN_BLANK, .name = "mock_screen_blank", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_screen_info mock_screen_base = { .id = MOCK_SCREEN_BASE, .name = "mock_screen_base: menuless screen", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_menu_item mock_screen_menu_items[] = { { @@ -142,33 +137,27 @@ const struct vb2_menu_item mock_screen_menu_items[] = { const struct vb2_screen_info mock_screen_menu = { .id = MOCK_SCREEN_MENU, .name = "mock_screen_menu: screen with 5 items", - .num_items = ARRAY_SIZE(mock_screen_menu_items), - .items = mock_screen_menu_items, + .menu = { + .num_items = ARRAY_SIZE(mock_screen_menu_items), + .items = mock_screen_menu_items, + }, }; const struct vb2_screen_info mock_screen_target0 = { .id = MOCK_SCREEN_TARGET0, .name = "mock_screen_target0", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_screen_info mock_screen_target1 = { .id = MOCK_SCREEN_TARGET1, .name = "mock_screen_target1", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_screen_info mock_screen_target2 = { .id = MOCK_SCREEN_TARGET2, .name = "mock_screen_target2", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_screen_info mock_screen_action = { .id = MOCK_SCREEN_ACTION, .name = "mock_screen_action", .action = mock_action_countdown, - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; const struct vb2_menu_item mock_screen_all_action_items[] = { { @@ -180,8 +169,10 @@ const struct vb2_screen_info mock_screen_all_action = { .id = MOCK_SCREEN_ALL_ACTION, .name = "mock_screen_all_action", .action = mock_action_flag0, - .num_items = ARRAY_SIZE(mock_screen_all_action_items), - .items = mock_screen_all_action_items, + .menu = { + .num_items = ARRAY_SIZE(mock_screen_all_action_items), + .items = mock_screen_all_action_items, + }, }; static void screen_state_eq(const struct vb2_screen_state *state, @@ -293,8 +284,6 @@ static void reset_common_data(void) mock_screen_temp = (struct vb2_screen_info){ .id = MOCK_NO_SCREEN, .name = "mock_screen_temp", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; /* Mock ui_context based on mock screens */ diff --git a/tests/vb2_ui_tests.c b/tests/vb2_ui_tests.c index 4066e5b8..aef133eb 100644 --- a/tests/vb2_ui_tests.c +++ b/tests/vb2_ui_tests.c @@ -39,6 +39,8 @@ static struct display_call mock_displayed[64]; static int mock_displayed_count; static int mock_displayed_i; +static uint32_t mock_locale_count; + static int mock_calls_until_shutdown; /* Iteration counter starts from 0 @@ -194,6 +196,9 @@ static void reset_common_data(enum reset_type t) mock_displayed_count = 0; mock_displayed_i = 0; + /* For vb2ex_get_locale_count */ + mock_locale_count = 1; + /* For check_shutdown_request */ if (t == FOR_DEVELOPER) mock_calls_until_shutdown = 2000; /* Larger than 30s */ @@ -280,6 +285,11 @@ vb2_error_t vb2ex_display_ui(enum vb2_screen screen, return VB2_SUCCESS; } +uint32_t vb2ex_get_locale_count(void) +{ + return mock_locale_count; +} + uint32_t VbExIsShutdownRequested(void) { if (mock_calls_until_shutdown < 0) /* Never request shutdown */ @@ -502,7 +512,7 @@ static void manual_recovery_tests(void) TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN, "phone recovery"); displayed_eq("recovery select", VB2_SCREEN_RECOVERY_SELECT, - MOCK_IGNORE, 0, MOCK_IGNORE); + MOCK_IGNORE, 1, MOCK_IGNORE); displayed_eq("phone recovery", VB2_SCREEN_RECOVERY_PHONE_STEP1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); displayed_no_extra(); @@ -514,9 +524,9 @@ static void manual_recovery_tests(void) TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN, "external disk recovery"); displayed_eq("recovery select", VB2_SCREEN_RECOVERY_SELECT, - MOCK_IGNORE, 0, MOCK_IGNORE); - displayed_eq("recovery select", VB2_SCREEN_RECOVERY_SELECT, MOCK_IGNORE, 1, MOCK_IGNORE); + displayed_eq("recovery select", VB2_SCREEN_RECOVERY_SELECT, + MOCK_IGNORE, 2, MOCK_IGNORE); displayed_eq("disk recovery", VB2_SCREEN_RECOVERY_DISK_STEP1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); displayed_no_extra(); @@ -703,11 +713,64 @@ static void manual_recovery_tests(void) VB2_DEBUG("...done.\n"); } +static void language_selection_tests(void) +{ + VB2_DEBUG("Testing language selection...\n"); + + /* Enter language menu and change language */ + reset_common_data(FOR_MANUAL_RECOVERY); + mock_locale_count = 100; + vb2_nv_set(ctx, VB2_NV_LOCALIZATION_INDEX, 23); + add_mock_keypress(VB_KEY_UP); + add_mock_keypress(VB_KEY_ENTER); /* select language */ + add_mock_keypress(VB_KEY_DOWN); + add_mock_keypress(VB_KEY_ENTER); /* select locale 24 */ + add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE); + TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN, + "change language"); + displayed_eq("RECOVERY_SELECT default", VB2_SCREEN_RECOVERY_SELECT, + 23, MOCK_IGNORE, MOCK_IGNORE); + displayed_eq("RECOVERY_SELECT lang", VB2_SCREEN_RECOVERY_SELECT, + 23, 0, MOCK_IGNORE); + displayed_eq("LANGUAGE_SELECT 23", VB2_SCREEN_LANGUAGE_SELECT, + 23, 23, MOCK_IGNORE); + displayed_eq("LANGUAGE_SELECT 24", VB2_SCREEN_LANGUAGE_SELECT, + 23, 24, MOCK_IGNORE); + displayed_eq("RECOVERY_SELECT new locale", VB2_SCREEN_RECOVERY_SELECT, + 24, MOCK_IGNORE, MOCK_IGNORE); + displayed_no_extra(); + TEST_EQ(vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX), 24, + " locale 24 saved to nvdata"); + + /* Locale count = 0 */ + reset_common_data(FOR_MANUAL_RECOVERY); + mock_locale_count = 0; + vb2_nv_set(ctx, VB2_NV_LOCALIZATION_INDEX, 23); + add_mock_keypress(VB_KEY_UP); + add_mock_keypress(VB_KEY_ENTER); /* select language */ + add_mock_keypress(VB_KEY_ENTER); /* select locale 0 */ + add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE); + TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN, + "enter language menu"); + displayed_eq("RECOVERY_SELECT default", VB2_SCREEN_RECOVERY_SELECT, + 23, MOCK_IGNORE, MOCK_IGNORE); + displayed_eq("RECOVERY_SELECT lang", VB2_SCREEN_RECOVERY_SELECT, + 23, 0, MOCK_IGNORE); + displayed_eq("LANGUAGE_SELECT index 0", VB2_SCREEN_LANGUAGE_SELECT, + 23, 0, MOCK_IGNORE); + displayed_eq("RECOVERY_SELECT locale 0", VB2_SCREEN_RECOVERY_SELECT, + 0, MOCK_IGNORE, MOCK_IGNORE); + displayed_no_extra(); + + VB2_DEBUG("...done.\n"); +} + int main(void) { developer_tests(); broken_recovery_tests(); manual_recovery_tests(); + language_selection_tests(); return gTestSuccess ? 0 : 255; } diff --git a/tests/vb2_ui_utility_tests.c b/tests/vb2_ui_utility_tests.c index 257e69d9..533aa514 100644 --- a/tests/vb2_ui_utility_tests.c +++ b/tests/vb2_ui_utility_tests.c @@ -29,6 +29,7 @@ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] static struct vb2_context *ctx; static struct vb2_gbb_header gbb; +static uint32_t mock_locale_count; static int mock_shutdown_request; static struct vb2_ui_context mock_ui_context; @@ -43,22 +44,18 @@ static vb2_error_t mock_action_base(struct vb2_ui_context *ui) } /* Mock screens */ -const struct vb2_menu_item mock_empty_menu[] = {}; struct vb2_screen_info mock_screen_blank = { .id = VB2_SCREEN_BLANK, .name = "mock_screen_blank", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; struct vb2_screen_info mock_screen_base = { .id = MOCK_SCREEN_BASE, .name = "mock_screen_base: menuless screen", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; struct vb2_menu_item mock_screen_menu_items[] = { { - .text = "option 0", + .text = "option 0: language selection", + .is_language_select = 1, }, { .text = "option 1", @@ -76,14 +73,14 @@ struct vb2_menu_item mock_screen_menu_items[] = { const struct vb2_screen_info mock_screen_menu = { .id = MOCK_SCREEN_MENU, .name = "mock_screen_menu: screen with 5 options", - .num_items = ARRAY_SIZE(mock_screen_menu_items), - .items = mock_screen_menu_items, + .menu = { + .num_items = ARRAY_SIZE(mock_screen_menu_items), + .items = mock_screen_menu_items, + }, }; const struct vb2_screen_info mock_screen_root = { .id = MOCK_SCREEN_ROOT, .name = "mock_screen_root", - .num_items = ARRAY_SIZE(mock_empty_menu), - .items = mock_empty_menu, }; static void screen_state_eq(const struct vb2_screen_state *state, @@ -115,6 +112,9 @@ static void reset_common_data(void) vb2_nv_init(ctx); + /* For vb2ex_get_locale_count */ + mock_locale_count = 1; + /* For check_shutdown_request */ mock_shutdown_request = MOCK_IGNORE; @@ -133,6 +133,11 @@ struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) return &gbb; } +uint32_t vb2ex_get_locale_count(void) +{ + return mock_locale_count; +} + uint32_t VbExIsShutdownRequested(void) { if (mock_shutdown_request != MOCK_IGNORE) @@ -299,6 +304,46 @@ static void change_screen_tests(void) VB2_SUCCESS, "change to screen with init"); TEST_EQ(mock_action_called, 1, " action called once"); + /* Change to screen without init; using default init() */ + reset_common_data(); + mock_state->screen = &mock_screen_base; + TEST_EQ(vb2_ui_change_screen(&mock_ui_context, MOCK_SCREEN_MENU), + VB2_REQUEST_UI_CONTINUE, + "change to screen with language selection"); + screen_state_eq(mock_state, MOCK_SCREEN_MENU, + 1, /* Since index 0 is the language selection */ + 0); + + VB2_DEBUG("...done.\n"); +} + +static void get_language_menu_tests(void) +{ + const struct vb2_menu *menu; + const struct vb2_menu_item *items; + VB2_DEBUG("Testing get_language_menu...\n"); + + /* Only allocate menu items once */ + reset_common_data(); + mock_locale_count = 7; + menu = get_language_menu(&mock_ui_context); + TEST_PTR_NEQ(menu, NULL, "get language menu"); + TEST_EQ(menu->num_items, 7, " correct locale count"); + TEST_PTR_NEQ(menu->items, NULL, " items not null"); + items = menu->items; + + menu = get_language_menu(&mock_ui_context); + TEST_PTR_NEQ(menu, NULL, "get language menu again"); + TEST_EQ(menu->num_items, 7, " correct locale count again"); + TEST_PTR_EQ(menu->items, items, " same pointer of items"); + + /* Locale count = 0 */ + reset_common_data(); + mock_locale_count = 0; + menu = get_language_menu(&mock_ui_context); + TEST_PTR_NEQ(menu, NULL, "menu not null"); + TEST_EQ(menu->num_items, 1, " locale count 1"); + VB2_DEBUG("...done.\n"); } @@ -307,6 +352,7 @@ int main(void) check_shutdown_request_tests(); vb2_ui_change_root_tests(); change_screen_tests(); + get_language_menu_tests(); return gTestSuccess ? 0 : 255; } |