diff options
author | Tom Marshall <tdm@cyngn.com> | 2016-02-15 15:36:06 -0800 |
---|---|---|
committer | Tom Marshall <tdm@cyngn.com> | 2016-03-07 15:16:25 -0800 |
commit | 6c20b00105e405823aa3ec12479e52cc30c0df9c (patch) | |
tree | 607a9223c74ea58e8d62bce4874ebc281846c134 | |
parent | d66f66eb72fc72c17d1a292cfbeaf2ec08721327 (diff) | |
download | bootable_recovery-6c20b00105e405823aa3ec12479e52cc30c0df9c.zip bootable_recovery-6c20b00105e405823aa3ec12479e52cc30c0df9c.tar.gz bootable_recovery-6c20b00105e405823aa3ec12479e52cc30c0df9c.tar.bz2 |
recovery: Implement sysbar
Add a system bar (navigation bar) similar to the main Android system
with back and home buttons. This makes it easier for users to figure
out how to go back on devices that lack hardware buttons, and also
provides a quick way to get back to the main menu.
Note only buttons that do not have a hardware equivalent are shown, in
order to prevent redundancy and confusion.
Change-Id: I7538749978837571a8c250c3c8e54ac127b39d84
28 files changed, 156 insertions, 17 deletions
@@ -139,6 +139,12 @@ Device::BuiltinAction Device::InvokeMenuItem(int menu_position) { return entry->action.action; } +void Device::GoHome() { + while (menu_stack.size() > 1) { + menu_stack.pop(); + } +} + int Device::HandleMenuKey(int key, int visible) { if (!visible) { return kNoAction; @@ -164,8 +170,6 @@ int Device::HandleMenuKey(int key, int visible) { case KEY_ENTER: case KEY_POWER: case BTN_MOUSE: - case KEY_HOME: - case KEY_HOMEPAGE: case KEY_SEND: return kInvokeItem; @@ -173,6 +177,10 @@ int Device::HandleMenuKey(int key, int visible) { case KEY_BACK: return kGoBack; + case KEY_HOME: + case KEY_HOMEPAGE: + return kGoHome; + default: // If you have all of the above buttons, any other buttons // are ignored. Otherwise, any button cycles the highlight. @@ -92,12 +92,15 @@ class Device : public VoldWatcher { // actually perform it 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; static const int kInvokeItem = -4; static const int kGoBack = -5; - static const int kRefresh = -6; + static const int kGoHome = -6; + static const int kRefresh = -7; // Called before and after we do a wipe data/factory reset operation, // either via a reboot from the main system with the --wipe_data flag, diff --git a/recovery.cpp b/recovery.cpp index 35c6830..c13a689 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -662,7 +662,10 @@ get_menu_selection(const char* const * headers, const char* const * items, int selected = initial_selection; int chosen_item = -1; - while (chosen_item < 0 && chosen_item != Device::kGoBack && chosen_item != Device::kRefresh) { + while (chosen_item < 0 && + chosen_item != Device::kGoBack && + chosen_item != Device::kGoHome && + chosen_item != Device::kRefresh) { int key = ui->WaitKey(); int visible = ui->IsTextVisible(); @@ -713,6 +716,9 @@ get_menu_selection(const char* const * headers, const char* const * items, case Device::kGoBack: chosen_item = Device::kGoBack; break; + case Device::kGoHome: + chosen_item = Device::kGoHome; + break; case Device::kRefresh: chosen_item = Device::kRefresh; break; @@ -723,6 +729,9 @@ get_menu_selection(const char* const * headers, const char* const * items, } ui->EndMenu(); + if (chosen_item == Device::kGoHome) { + device->GoHome(); + } return chosen_item; } @@ -796,6 +805,11 @@ static char* browse_directory(const char* path, Device* device) { int chosen_item = 0; while (true) { chosen_item = get_menu_selection(headers, zips, 1, chosen_item, device); + if (chosen_item == Device::kGoHome) { + // go up and stop browsing + result = strdup(""); + break; + } if (chosen_item == 0 || chosen_item == Device::kGoBack) { // go up but continue browsing (if the caller is update_directory) result = NULL; @@ -936,6 +950,7 @@ static void choose_recovery_file(Device* device) { while (true) { int chosen_item = get_menu_selection(headers, entries, 1, 0, device); + if (chosen_item == Device::kGoHome) break; if (chosen_item == Device::kGoBack) break; if (chosen_item >= 0 && strcmp(entries[chosen_item], "Back") == 0) break; @@ -959,9 +974,10 @@ static int apply_from_storage(Device* device, const std::string& id, bool* wipe_ VolumeInfo vi = vdc->getVolume(id); char* path = browse_directory(vi.mInternalPath.c_str(), device); - if (path == NULL) { + if (path == NULL || *path == '\0') { ui->Print("\n-- No package file selected.\n"); vdc->volumeUnmount(vi.mId); + free(path); return INSTALL_NONE; } @@ -1013,6 +1029,9 @@ refresh: if (chosen == Device::kRefresh) { goto refresh; } + if (chosen == Device::kGoHome) { + return INSTALL_NONE; + } if (chosen == Device::kGoBack) { return INSTALL_NONE; } diff --git a/res-hdpi/images/icon_sysbar_back.png b/res-hdpi/images/icon_sysbar_back.png Binary files differnew file mode 100644 index 0000000..5aa8e62 --- /dev/null +++ b/res-hdpi/images/icon_sysbar_back.png diff --git a/res-hdpi/images/icon_sysbar_back_highlight.png b/res-hdpi/images/icon_sysbar_back_highlight.png Binary files differnew file mode 100644 index 0000000..5836504 --- /dev/null +++ b/res-hdpi/images/icon_sysbar_back_highlight.png diff --git a/res-hdpi/images/icon_sysbar_home.png b/res-hdpi/images/icon_sysbar_home.png Binary files differnew file mode 100644 index 0000000..b37422d --- /dev/null +++ b/res-hdpi/images/icon_sysbar_home.png diff --git a/res-hdpi/images/icon_sysbar_home_highlight.png b/res-hdpi/images/icon_sysbar_home_highlight.png Binary files differnew file mode 100644 index 0000000..ed0ccfa --- /dev/null +++ b/res-hdpi/images/icon_sysbar_home_highlight.png diff --git a/res-mdpi/images/icon_sysbar_back.png b/res-mdpi/images/icon_sysbar_back.png Binary files differnew file mode 100644 index 0000000..81e4637 --- /dev/null +++ b/res-mdpi/images/icon_sysbar_back.png diff --git a/res-mdpi/images/icon_sysbar_back_highlight.png b/res-mdpi/images/icon_sysbar_back_highlight.png Binary files differnew file mode 100644 index 0000000..d173042 --- /dev/null +++ b/res-mdpi/images/icon_sysbar_back_highlight.png diff --git a/res-mdpi/images/icon_sysbar_home.png b/res-mdpi/images/icon_sysbar_home.png Binary files differnew file mode 100644 index 0000000..d9e3a43 --- /dev/null +++ b/res-mdpi/images/icon_sysbar_home.png diff --git a/res-mdpi/images/icon_sysbar_home_highlight.png b/res-mdpi/images/icon_sysbar_home_highlight.png Binary files differnew file mode 100644 index 0000000..ef65d61 --- /dev/null +++ b/res-mdpi/images/icon_sysbar_home_highlight.png diff --git a/res-xhdpi/images/icon_sysbar_back.png b/res-xhdpi/images/icon_sysbar_back.png Binary files differnew file mode 100644 index 0000000..415715e --- /dev/null +++ b/res-xhdpi/images/icon_sysbar_back.png diff --git a/res-xhdpi/images/icon_sysbar_back_highlight.png b/res-xhdpi/images/icon_sysbar_back_highlight.png Binary files differnew file mode 100644 index 0000000..237af6a --- /dev/null +++ b/res-xhdpi/images/icon_sysbar_back_highlight.png diff --git a/res-xhdpi/images/icon_sysbar_home.png b/res-xhdpi/images/icon_sysbar_home.png Binary files differnew file mode 100644 index 0000000..425c0dc --- /dev/null +++ b/res-xhdpi/images/icon_sysbar_home.png diff --git a/res-xhdpi/images/icon_sysbar_home_highlight.png b/res-xhdpi/images/icon_sysbar_home_highlight.png Binary files differnew file mode 100644 index 0000000..f7b6ce3 --- /dev/null +++ b/res-xhdpi/images/icon_sysbar_home_highlight.png diff --git a/res-xxhdpi/images/icon_sysbar_back.png b/res-xxhdpi/images/icon_sysbar_back.png Binary files differnew file mode 100644 index 0000000..0b2e866 --- /dev/null +++ b/res-xxhdpi/images/icon_sysbar_back.png diff --git a/res-xxhdpi/images/icon_sysbar_back_highlight.png b/res-xxhdpi/images/icon_sysbar_back_highlight.png Binary files differnew file mode 100644 index 0000000..03cb8a1 --- /dev/null +++ b/res-xxhdpi/images/icon_sysbar_back_highlight.png diff --git a/res-xxhdpi/images/icon_sysbar_home.png b/res-xxhdpi/images/icon_sysbar_home.png Binary files differnew file mode 100644 index 0000000..7348841 --- /dev/null +++ b/res-xxhdpi/images/icon_sysbar_home.png diff --git a/res-xxhdpi/images/icon_sysbar_home_highlight.png b/res-xxhdpi/images/icon_sysbar_home_highlight.png Binary files differnew file mode 100644 index 0000000..a981495 --- /dev/null +++ b/res-xxhdpi/images/icon_sysbar_home_highlight.png diff --git a/res-xxxhdpi/images/icon_sysbar_back.png b/res-xxxhdpi/images/icon_sysbar_back.png Binary files differnew file mode 100644 index 0000000..f630553 --- /dev/null +++ b/res-xxxhdpi/images/icon_sysbar_back.png diff --git a/res-xxxhdpi/images/icon_sysbar_back_highlight.png b/res-xxxhdpi/images/icon_sysbar_back_highlight.png Binary files differnew file mode 100644 index 0000000..9211093 --- /dev/null +++ b/res-xxxhdpi/images/icon_sysbar_back_highlight.png diff --git a/res-xxxhdpi/images/icon_sysbar_home.png b/res-xxxhdpi/images/icon_sysbar_home.png Binary files differnew file mode 100644 index 0000000..9ee96ce --- /dev/null +++ b/res-xxxhdpi/images/icon_sysbar_home.png diff --git a/res-xxxhdpi/images/icon_sysbar_home_highlight.png b/res-xxxhdpi/images/icon_sysbar_home_highlight.png Binary files differnew file mode 100644 index 0000000..d63ecb0 --- /dev/null +++ b/res-xxxhdpi/images/icon_sysbar_home_highlight.png diff --git a/screen_ui.cpp b/screen_ui.cpp index 8e6c733..849f6d1 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -77,6 +77,7 @@ ScreenRecoveryUI::ScreenRecoveryUI() : show_menu(false), menu_items(0), menu_sel(0), + sysbar_state(0), file_viewer_text_(nullptr), animation_fps(20), installing_frames(-1), @@ -86,6 +87,10 @@ ScreenRecoveryUI::ScreenRecoveryUI() : wrap_count(0) { headerIcon = nullptr; + sysbarBackIcon = nullptr; + sysbarBackHighlightIcon = nullptr; + sysbarHomeIcon = nullptr; + sysbarHomeHighlightIcon = nullptr; for (int i = 0; i < NR_ICONS; i++) { backgroundIcon[i] = nullptr; } @@ -281,6 +286,45 @@ void ScreenRecoveryUI::draw_menu_item(int textrow, const char *text, int selecte } } +void ScreenRecoveryUI::draw_sysbar() +{ + GRSurface* surface; + int sw = gr_fb_width(); + int sh = gr_fb_height(); + int iw; + int ih; + SetColor(TEXT_FILL); + gr_fill(0, sh - sysbar_height_, sw, sh); + + // Left third is back button + if (!HasBackKey()) { + if (sysbar_state & SYSBAR_BACK) { + surface = sysbarBackHighlightIcon; + } + else { + surface = sysbarBackIcon; + } + iw = gr_get_width(surface); + ih = gr_get_height(surface); + gr_blit(surface, 0, 0, iw, ih, + 1 * (sw / 6) - (iw / 2), sh - ih); + } + + // Middle third is home button + if (!HasHomeKey()) { + if (sysbar_state & SYSBAR_HOME) { + surface = sysbarHomeHighlightIcon; + } + else { + surface = sysbarHomeIcon; + } + iw = gr_get_width(surface); + ih = gr_get_height(surface); + gr_blit(surface, 0, 0, iw, ih, + 3 * (sw / 6) - (iw / 2), sh - ih); + } +} + void ScreenRecoveryUI::draw_dialog() { int x, y, w, h; @@ -289,6 +333,7 @@ void ScreenRecoveryUI::draw_dialog() return; } draw_header_icon(); + draw_sysbar(); int iconHeight = gr_get_height(backgroundIcon[dialog_icon]); @@ -374,9 +419,9 @@ void ScreenRecoveryUI::draw_screen_locked() { } if (show_menu) { - int i; + int i, y; draw_header_icon(); - int y; + draw_sysbar(); // Divider y = text_first_row_ * char_height_; @@ -519,23 +564,31 @@ void ScreenRecoveryUI::Init() { gr_font_size(&log_char_width_, &log_char_height_); gr_set_font("menu"); gr_font_size(&char_width_, &char_height_); - text_rows_ = gr_fb_height() / char_height_; - text_cols_ = gr_fb_width() / char_width_; - - log_text_rows_ = gr_fb_height() / log_char_height_; - log_text_cols_ = gr_fb_width() / log_char_width_; - - text_ = Alloc2d(log_text_rows_, log_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("icon_header", &headerIcon); + LoadBitmap("icon_sysbar_back", &sysbarBackIcon); + LoadBitmap("icon_sysbar_back_highlight", &sysbarBackHighlightIcon); + LoadBitmap("icon_sysbar_home", &sysbarHomeIcon); + LoadBitmap("icon_sysbar_home_highlight", &sysbarHomeHighlightIcon); + header_height_ = gr_get_height(headerIcon); header_width_ = gr_get_width(headerIcon); + sysbar_height_ = gr_get_height(sysbarBackIcon); + + text_rows_ = (gr_fb_height() - sysbar_height_) / char_height_; + text_cols_ = gr_fb_width() / char_width_; + + log_text_rows_ = (gr_fb_height() - sysbar_height_) / log_char_height_; + log_text_cols_ = gr_fb_width() / log_char_width_; + + text_ = Alloc2d(log_text_rows_, log_text_cols_ + 1); + file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1); + menu_ = Alloc2d(text_rows_, text_cols_ + 1); + text_first_row_ = (header_height_ / char_height_) + 1; menu_item_start_ = text_first_row_ * char_height_; max_menu_rows_ = (text_rows_ - text_first_row_) / 3; diff --git a/screen_ui.h b/screen_ui.h index 93d06bc..9d7b263 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -23,6 +23,9 @@ #include "ui.h" #include "minui/minui.h" +#define SYSBAR_BACK 0x01 +#define SYSBAR_HOME 0x02 + // Implementation of RecoveryUI appropriate for devices with a screen // (shows an icon + a progress bar, text logging, menu, etc.) class ScreenRecoveryUI : public RecoveryUI { @@ -60,6 +63,11 @@ class ScreenRecoveryUI : public RecoveryUI { void DialogDismiss(); void SetHeadlessMode(); + // sysbar + int GetSysbarHeight() { return gr_get_height(sysbarBackHighlightIcon); } + int GetSysbarState() { return sysbar_state; } + void SetSysbarState(int state) { sysbar_state = state; Redraw(); } + // menu display virtual int MenuItemStart() const { return menu_item_start_; } virtual int MenuItemHeight() const { return 3 * char_height_; } @@ -87,6 +95,10 @@ class ScreenRecoveryUI : public RecoveryUI { pthread_cond_t progressCondition; GRSurface* headerIcon; + GRSurface* sysbarBackIcon; + GRSurface* sysbarBackHighlightIcon; + GRSurface* sysbarHomeIcon; + GRSurface* sysbarHomeHighlightIcon; GRSurface* backgroundIcon[NR_ICONS]; GRSurface* backgroundText[NR_ICONS]; GRSurface** installation; @@ -126,6 +138,8 @@ class ScreenRecoveryUI : public RecoveryUI { int menu_show_start_; int max_menu_rows_; + int sysbar_state; + // An alternate text screen, swapped with 'text_' when we're viewing a log file. char** file_viewer_text_; @@ -147,6 +161,7 @@ class ScreenRecoveryUI : public RecoveryUI { int char_height_, char_width_; int header_height_, header_width_; + int sysbar_height_; int text_first_row_; bool update_waiting; @@ -155,6 +170,7 @@ class ScreenRecoveryUI : public RecoveryUI { void draw_progress_locked(); int draw_header_icon(); void draw_menu_item(int textrow, const char *text, int selected); + void draw_sysbar(); void draw_dialog(); void draw_screen_locked(); void update_screen_locked(); @@ -144,7 +144,9 @@ RecoveryUI::RecoveryUI() last_key(-1), has_power_key(false), has_up_key(false), - has_down_key(false) { + has_down_key(false), + has_back_key(false), + has_home_key(false) { pthread_mutex_init(&key_queue_mutex, nullptr); pthread_cond_init(&key_queue_cond, nullptr); memset(key_pressed, 0, sizeof(key_pressed)); @@ -157,6 +159,12 @@ void RecoveryUI::OnKeyDetected(int key_code) { has_down_key = true; } else if (key_code == KEY_UP || key_code == KEY_VOLUMEUP) { has_up_key = true; + } else if (key_code == KEY_BACK) { + has_back_key = true; + LOGI("Detected back key, disabling virtual back button\n"); + } else if (key_code == KEY_HOMEPAGE) { + has_home_key = true; + LOGI("Detected home key, disabling virtual home button\n"); } } @@ -566,6 +574,12 @@ void RecoveryUI::handle_press(input_device* dev) { dev->touch_start = dev->touch_track = dev->touch_pos; dev->in_touch = true; dev->in_swipe = false; + if (dev->touch_pos.y >= gr_fb_height() - GetSysbarHeight()) { + SetSysbarState(1 << (3 * dev->touch_pos.x / gr_fb_width())); + } + else { + SetSysbarState(0); + } } void RecoveryUI::handle_release(input_device* dev) { @@ -588,6 +602,19 @@ void RecoveryUI::handle_release(input_device* dev) { return; } } + + int sysbar_state = GetSysbarState(); + SetSysbarState(0); + if (sysbar_state == 0x01) { + ProcessKey(dev, KEY_BACK, 1); + ProcessKey(dev, KEY_BACK, 0); + return; + } + if (sysbar_state == 0x02) { + ProcessKey(dev, KEY_HOME, 1); + ProcessKey(dev, KEY_HOME, 0); + return; + } } if (DialogShowing()) { @@ -162,6 +162,9 @@ class RecoveryUI { // of phones and tablets, false otherwise. virtual bool HasThreeButtons(); + virtual bool HasBackKey() const { return has_back_key; } + virtual bool HasHomeKey() const { return has_home_key; } + // Erase any queued-up keys. virtual void FlushKeys(); @@ -191,6 +194,10 @@ class RecoveryUI { virtual int MenuItemStart() const = 0; virtual int MenuItemHeight() const = 0; + virtual int GetSysbarHeight() = 0; + virtual int GetSysbarState() = 0; + virtual void SetSysbarState(int state) = 0; + // 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). @@ -230,6 +237,8 @@ private: bool has_power_key; bool has_up_key; bool has_down_key; + bool has_back_key; + bool has_home_key; input_device input_devices[MAX_NR_INPUT_DEVICES]; diff --git a/verifier_test.cpp b/verifier_test.cpp index 623ae64..a9d42c0 100644 --- a/verifier_test.cpp +++ b/verifier_test.cpp @@ -165,6 +165,10 @@ class FakeUI : public RecoveryUI { virtual int MenuItemStart() const { return 0; } virtual int MenuItemHeight() const { return 0; } + + virtual int GetSysbarHeight() { return 0; } + virtual int GetSysbarState() { return 0; } + virtual void SetSysbarState(int state) {} }; void |