From 6c20b00105e405823aa3ec12479e52cc30c0df9c Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Mon, 15 Feb 2016 15:36:06 -0800 Subject: 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 --- device.cpp | 12 +++- device.h | 5 +- recovery.cpp | 23 ++++++- res-hdpi/images/icon_sysbar_back.png | Bin 0 -> 762 bytes res-hdpi/images/icon_sysbar_back_highlight.png | Bin 0 -> 2674 bytes res-hdpi/images/icon_sysbar_home.png | Bin 0 -> 860 bytes res-hdpi/images/icon_sysbar_home_highlight.png | Bin 0 -> 2852 bytes res-mdpi/images/icon_sysbar_back.png | Bin 0 -> 555 bytes res-mdpi/images/icon_sysbar_back_highlight.png | Bin 0 -> 1491 bytes res-mdpi/images/icon_sysbar_home.png | Bin 0 -> 576 bytes res-mdpi/images/icon_sysbar_home_highlight.png | Bin 0 -> 1567 bytes res-xhdpi/images/icon_sysbar_back.png | Bin 0 -> 946 bytes res-xhdpi/images/icon_sysbar_back_highlight.png | Bin 0 -> 3481 bytes res-xhdpi/images/icon_sysbar_home.png | Bin 0 -> 1150 bytes res-xhdpi/images/icon_sysbar_home_highlight.png | Bin 0 -> 3788 bytes res-xxhdpi/images/icon_sysbar_back.png | Bin 0 -> 1450 bytes res-xxhdpi/images/icon_sysbar_back_highlight.png | Bin 0 -> 4942 bytes res-xxhdpi/images/icon_sysbar_home.png | Bin 0 -> 1759 bytes res-xxhdpi/images/icon_sysbar_home_highlight.png | Bin 0 -> 5398 bytes res-xxxhdpi/images/icon_sysbar_back.png | Bin 0 -> 1245 bytes res-xxxhdpi/images/icon_sysbar_back_highlight.png | Bin 0 -> 8323 bytes res-xxxhdpi/images/icon_sysbar_home.png | Bin 0 -> 1445 bytes res-xxxhdpi/images/icon_sysbar_home_highlight.png | Bin 0 -> 8905 bytes screen_ui.cpp | 75 ++++++++++++++++++---- screen_ui.h | 16 +++++ ui.cpp | 29 ++++++++- ui.h | 9 +++ verifier_test.cpp | 4 ++ 28 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 res-hdpi/images/icon_sysbar_back.png create mode 100644 res-hdpi/images/icon_sysbar_back_highlight.png create mode 100644 res-hdpi/images/icon_sysbar_home.png create mode 100644 res-hdpi/images/icon_sysbar_home_highlight.png create mode 100644 res-mdpi/images/icon_sysbar_back.png create mode 100644 res-mdpi/images/icon_sysbar_back_highlight.png create mode 100644 res-mdpi/images/icon_sysbar_home.png create mode 100644 res-mdpi/images/icon_sysbar_home_highlight.png create mode 100644 res-xhdpi/images/icon_sysbar_back.png create mode 100644 res-xhdpi/images/icon_sysbar_back_highlight.png create mode 100644 res-xhdpi/images/icon_sysbar_home.png create mode 100644 res-xhdpi/images/icon_sysbar_home_highlight.png create mode 100644 res-xxhdpi/images/icon_sysbar_back.png create mode 100644 res-xxhdpi/images/icon_sysbar_back_highlight.png create mode 100644 res-xxhdpi/images/icon_sysbar_home.png create mode 100644 res-xxhdpi/images/icon_sysbar_home_highlight.png create mode 100644 res-xxxhdpi/images/icon_sysbar_back.png create mode 100644 res-xxxhdpi/images/icon_sysbar_back_highlight.png create mode 100644 res-xxxhdpi/images/icon_sysbar_home.png create mode 100644 res-xxxhdpi/images/icon_sysbar_home_highlight.png diff --git a/device.cpp b/device.cpp index 7f579cf..95608d6 100644 --- a/device.cpp +++ b/device.cpp @@ -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. diff --git a/device.h b/device.h index dba4ac1..98427a2 100644 --- a/device.h +++ b/device.h @@ -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 new file mode 100644 index 0000000..5aa8e62 Binary files /dev/null and b/res-hdpi/images/icon_sysbar_back.png differ diff --git a/res-hdpi/images/icon_sysbar_back_highlight.png b/res-hdpi/images/icon_sysbar_back_highlight.png new file mode 100644 index 0000000..5836504 Binary files /dev/null and b/res-hdpi/images/icon_sysbar_back_highlight.png differ diff --git a/res-hdpi/images/icon_sysbar_home.png b/res-hdpi/images/icon_sysbar_home.png new file mode 100644 index 0000000..b37422d Binary files /dev/null and b/res-hdpi/images/icon_sysbar_home.png differ diff --git a/res-hdpi/images/icon_sysbar_home_highlight.png b/res-hdpi/images/icon_sysbar_home_highlight.png new file mode 100644 index 0000000..ed0ccfa Binary files /dev/null and b/res-hdpi/images/icon_sysbar_home_highlight.png differ diff --git a/res-mdpi/images/icon_sysbar_back.png b/res-mdpi/images/icon_sysbar_back.png new file mode 100644 index 0000000..81e4637 Binary files /dev/null and b/res-mdpi/images/icon_sysbar_back.png differ diff --git a/res-mdpi/images/icon_sysbar_back_highlight.png b/res-mdpi/images/icon_sysbar_back_highlight.png new file mode 100644 index 0000000..d173042 Binary files /dev/null and b/res-mdpi/images/icon_sysbar_back_highlight.png differ diff --git a/res-mdpi/images/icon_sysbar_home.png b/res-mdpi/images/icon_sysbar_home.png new file mode 100644 index 0000000..d9e3a43 Binary files /dev/null and b/res-mdpi/images/icon_sysbar_home.png differ diff --git a/res-mdpi/images/icon_sysbar_home_highlight.png b/res-mdpi/images/icon_sysbar_home_highlight.png new file mode 100644 index 0000000..ef65d61 Binary files /dev/null and b/res-mdpi/images/icon_sysbar_home_highlight.png differ diff --git a/res-xhdpi/images/icon_sysbar_back.png b/res-xhdpi/images/icon_sysbar_back.png new file mode 100644 index 0000000..415715e Binary files /dev/null and b/res-xhdpi/images/icon_sysbar_back.png differ diff --git a/res-xhdpi/images/icon_sysbar_back_highlight.png b/res-xhdpi/images/icon_sysbar_back_highlight.png new file mode 100644 index 0000000..237af6a Binary files /dev/null and b/res-xhdpi/images/icon_sysbar_back_highlight.png differ diff --git a/res-xhdpi/images/icon_sysbar_home.png b/res-xhdpi/images/icon_sysbar_home.png new file mode 100644 index 0000000..425c0dc Binary files /dev/null and b/res-xhdpi/images/icon_sysbar_home.png differ diff --git a/res-xhdpi/images/icon_sysbar_home_highlight.png b/res-xhdpi/images/icon_sysbar_home_highlight.png new file mode 100644 index 0000000..f7b6ce3 Binary files /dev/null and b/res-xhdpi/images/icon_sysbar_home_highlight.png differ diff --git a/res-xxhdpi/images/icon_sysbar_back.png b/res-xxhdpi/images/icon_sysbar_back.png new file mode 100644 index 0000000..0b2e866 Binary files /dev/null and b/res-xxhdpi/images/icon_sysbar_back.png differ diff --git a/res-xxhdpi/images/icon_sysbar_back_highlight.png b/res-xxhdpi/images/icon_sysbar_back_highlight.png new file mode 100644 index 0000000..03cb8a1 Binary files /dev/null and b/res-xxhdpi/images/icon_sysbar_back_highlight.png differ diff --git a/res-xxhdpi/images/icon_sysbar_home.png b/res-xxhdpi/images/icon_sysbar_home.png new file mode 100644 index 0000000..7348841 Binary files /dev/null and b/res-xxhdpi/images/icon_sysbar_home.png differ diff --git a/res-xxhdpi/images/icon_sysbar_home_highlight.png b/res-xxhdpi/images/icon_sysbar_home_highlight.png new file mode 100644 index 0000000..a981495 Binary files /dev/null and b/res-xxhdpi/images/icon_sysbar_home_highlight.png differ diff --git a/res-xxxhdpi/images/icon_sysbar_back.png b/res-xxxhdpi/images/icon_sysbar_back.png new file mode 100644 index 0000000..f630553 Binary files /dev/null and b/res-xxxhdpi/images/icon_sysbar_back.png differ diff --git a/res-xxxhdpi/images/icon_sysbar_back_highlight.png b/res-xxxhdpi/images/icon_sysbar_back_highlight.png new file mode 100644 index 0000000..9211093 Binary files /dev/null and b/res-xxxhdpi/images/icon_sysbar_back_highlight.png differ diff --git a/res-xxxhdpi/images/icon_sysbar_home.png b/res-xxxhdpi/images/icon_sysbar_home.png new file mode 100644 index 0000000..9ee96ce Binary files /dev/null and b/res-xxxhdpi/images/icon_sysbar_home.png differ diff --git a/res-xxxhdpi/images/icon_sysbar_home_highlight.png b/res-xxxhdpi/images/icon_sysbar_home_highlight.png new file mode 100644 index 0000000..d63ecb0 Binary files /dev/null and b/res-xxxhdpi/images/icon_sysbar_home_highlight.png differ 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(); diff --git a/ui.cpp b/ui.cpp index 1594580..14f92b4 100644 --- a/ui.cpp +++ b/ui.cpp @@ -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()) { diff --git a/ui.h b/ui.h index abe4bca..e71dbe2 100644 --- a/ui.h +++ b/ui.h @@ -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 -- cgit v1.1