From fc06f87ecc71cb79887b1365dca8ac5555fe1205 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 23 Mar 2015 13:45:31 -0700 Subject: Make the recovery menus wrap. The real problem is that the recovery UI is sluggish. But being able to wrap off the top to the bottom halves the maximum distance you'll have to go. Change-Id: Ifebe5b818f9c9a1c4187d4ac609422da1f38537f --- screen_ui.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 03ef049ae..5e3a24fd2 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -526,8 +526,11 @@ int ScreenRecoveryUI::SelectMenu(int sel) { if (show_menu > 0) { old_sel = menu_sel; menu_sel = sel; - if (menu_sel < 0) menu_sel = 0; - if (menu_sel >= menu_items) menu_sel = menu_items-1; + + // Wrap at top and bottom. + if (menu_sel < 0) menu_sel = menu_items - 1; + if (menu_sel >= menu_items) menu_sel = 0; + sel = menu_sel; if (menu_sel != old_sel) update_screen_locked(); } -- cgit v1.2.3 From 01a4d08010d1c26cc2cb37ca62b624829a7e1506 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 24 Mar 2015 15:21:48 -0700 Subject: Fix recovery image text rendering. Previously most devices would lose the character before a line wrap. The log's text rendering was starting at offset 4 but none of the arithmetic was taking this into account. It just happened to work on the Nexus 9's 1536-pixel wide display (1536/18=85.3) but not on a device such as the Nexus 5 (1080/18=60). The only active part of this change is the change from 4 to 0 in the gr_text call. The rest is just a few bits of trivial cleanup while I was working out what was going on. Change-Id: I9279ae323c77bc8b6ea87dc0fe009aaaec6bfa0e --- screen_ui.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 5e3a24fd2..edc41abc0 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -246,12 +246,11 @@ void ScreenRecoveryUI::draw_screen_locked() // display from the bottom up, until we hit the top of the // screen, the bottom of the menu, or we've displayed the // entire text buffer. - int ty; int row = (text_top+text_rows-1) % text_rows; for (int ty = gr_fb_height() - char_height, count = 0; ty > y+2 && count < text_rows; ty -= char_height, ++count) { - gr_text(4, ty, text[row], 0); + gr_text(0, ty, text[row], 0); --row; if (row < 0) row = text_rows-1; } @@ -480,8 +479,7 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) // This can get called before ui_init(), so be careful. pthread_mutex_lock(&updateMutex); if (text_rows > 0 && text_cols > 0) { - char *ptr; - for (ptr = buf; *ptr != '\0'; ++ptr) { + for (char* ptr = buf; *ptr != '\0'; ++ptr) { if (*ptr == '\n' || text_col >= text_cols) { text[text_row][text_col] = '\0'; text_col = 0; @@ -521,10 +519,9 @@ void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const } int ScreenRecoveryUI::SelectMenu(int sel) { - int old_sel; pthread_mutex_lock(&updateMutex); if (show_menu > 0) { - old_sel = menu_sel; + int old_sel = menu_sel; menu_sel = sel; // Wrap at top and bottom. @@ -539,7 +536,6 @@ int ScreenRecoveryUI::SelectMenu(int sel) { } void ScreenRecoveryUI::EndMenu() { - int i; pthread_mutex_lock(&updateMutex); if (show_menu > 0 && text_rows > 0 && text_cols > 0) { show_menu = 0; -- cgit v1.2.3 From aa0d6afb61f4cf928e87c7a21bcb59fc973f15a0 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 8 Apr 2015 12:42:50 -0700 Subject: Remove the fixed screen size assumptions. Dynamically allocate the text and menu arrays instead. Change-Id: Idbfc3fe4e4b50db4fee62ac2b6a7323cad369749 --- screen_ui.cpp | 56 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index edc41abc0..a0df455cd 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -40,25 +40,26 @@ static int char_height; // There's only (at most) one of these objects, and global callbacks // (for pthread_create, and the input event system) need to find it, // so use a global variable. -static ScreenRecoveryUI* self = NULL; +static ScreenRecoveryUI* self = nullptr; // Return the current time as a double (including fractions of a second). static double now() { struct timeval tv; - gettimeofday(&tv, NULL); + gettimeofday(&tv, nullptr); return tv.tv_sec + tv.tv_usec / 1000000.0; } ScreenRecoveryUI::ScreenRecoveryUI() : currentIcon(NONE), installingFrame(0), - locale(NULL), + locale(nullptr), rtl_locale(false), progressBarType(EMPTY), progressScopeStart(0), progressScopeSize(0), progress(0), pagesIdentical(false), + text(nullptr), text_cols(0), text_rows(0), text_col(0), @@ -66,6 +67,7 @@ ScreenRecoveryUI::ScreenRecoveryUI() : text_top(0), show_text(false), show_text_ever(false), + menu(nullptr), show_menu(false), menu_top(0), menu_items(0), @@ -75,12 +77,10 @@ ScreenRecoveryUI::ScreenRecoveryUI() : stage(-1), max_stage(-1) { - for (int i = 0; i < 5; i++) - backgroundIcon[i] = NULL; - - memset(text, 0, sizeof(text)); - - pthread_mutex_init(&updateMutex, NULL); + for (int i = 0; i < 5; i++) { + backgroundIcon[i] = nullptr; + } + pthread_mutex_init(&updateMutex, nullptr); self = this; } @@ -247,7 +247,8 @@ void ScreenRecoveryUI::draw_screen_locked() // screen, the bottom of the menu, or we've displayed the // entire text buffer. int row = (text_top+text_rows-1) % text_rows; - for (int ty = gr_fb_height() - char_height, count = 0; + size_t count = 0; + for (int ty = gr_fb_height() - char_height; ty > y+2 && count < text_rows; ty -= char_height, ++count) { gr_text(0, ty, text[row], 0); @@ -281,7 +282,7 @@ void ScreenRecoveryUI::update_progress_locked() // Keeps the progress bar updated, even when the process is otherwise busy. void* ScreenRecoveryUI::progress_thread(void *cookie) { self->progress_loop(); - return NULL; + return nullptr; } void ScreenRecoveryUI::progress_loop() { @@ -344,23 +345,32 @@ void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, gr_surface* sur } } +static char** Alloc2d(size_t rows, size_t cols) { + char** result = new char*[rows]; + for (size_t i = 0; i < rows; ++i) { + result[i] = new char[cols]; + memset(result[i], 0, cols); + } + return result; +} + void ScreenRecoveryUI::Init() { gr_init(); gr_font_size(&char_width, &char_height); + text_rows = gr_fb_height() / char_height; + text_cols = gr_fb_width() / char_width; + + text = Alloc2d(text_rows, text_cols + 1); + menu = Alloc2d(text_rows, text_cols + 1); text_col = text_row = 0; - text_rows = gr_fb_height() / char_height; - if (text_rows > kMaxRows) text_rows = kMaxRows; text_top = 1; - text_cols = gr_fb_width() / char_width; - if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1; - - backgroundIcon[NONE] = NULL; + backgroundIcon[NONE] = nullptr; LoadBitmapArray("icon_installing", &installing_frames, &installation); - backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : NULL; + backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr; backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE]; LoadBitmap("icon_error", &backgroundIcon[ERROR]); backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR]; @@ -375,7 +385,7 @@ void ScreenRecoveryUI::Init() LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]); LoadLocalizedBitmap("error_text", &backgroundText[ERROR]); - pthread_create(&progress_t, NULL, progress_thread, NULL); + pthread_create(&progress_t, nullptr, progress_thread, nullptr); RecoveryUI::Init(); } @@ -402,7 +412,7 @@ void ScreenRecoveryUI::SetLocale(const char* new_locale) { } free(lang); } else { - new_locale = NULL; + new_locale = nullptr; } } @@ -496,17 +506,17 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, int initial_selection) { - int i; pthread_mutex_lock(&updateMutex); if (text_rows > 0 && text_cols > 0) { + size_t i; for (i = 0; i < text_rows; ++i) { - if (headers[i] == NULL) break; + if (headers[i] == nullptr) break; strncpy(menu[i], headers[i], text_cols-1); menu[i][text_cols-1] = '\0'; } menu_top = i; for (; i < text_rows; ++i) { - if (items[i-menu_top] == NULL) break; + if (items[i-menu_top] == nullptr) break; strncpy(menu[i], items[i-menu_top], text_cols-1); menu[i][text_cols-1] = '\0'; } -- cgit v1.2.3 From 8de52078a42882873322b19becb42612f7708b54 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 8 Apr 2015 20:06:50 -0700 Subject: Move file paging into ScreenRecoveryUI. This fixes the N9 performance problem. Change-Id: I00c10d4162ff266a6243285e5a5e768217f6f799 --- screen_ui.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 33 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index a0df455cd..6d8df68b3 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -86,8 +86,7 @@ ScreenRecoveryUI::ScreenRecoveryUI() : // Clear the screen and draw the currently selected background icon (if any). // Should only be called with updateMutex locked. -void ScreenRecoveryUI::draw_background_locked(Icon icon) -{ +void ScreenRecoveryUI::draw_background_locked(Icon icon) { pagesIdentical = false; gr_color(0, 0, 0, 255); gr_clear(); @@ -132,8 +131,7 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon) // Draw the progress bar (if any) on the screen. Does not flip pages. // Should only be called with updateMutex locked. -void ScreenRecoveryUI::draw_progress_locked() -{ +void ScreenRecoveryUI::draw_progress_locked() { if (currentIcon == ERROR) return; if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { @@ -204,8 +202,7 @@ void ScreenRecoveryUI::SetColor(UIElement e) { // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. -void ScreenRecoveryUI::draw_screen_locked() -{ +void ScreenRecoveryUI::draw_screen_locked() { if (!show_text) { draw_background_locked(currentIcon); draw_progress_locked(); @@ -260,16 +257,14 @@ void ScreenRecoveryUI::draw_screen_locked() // Redraw everything on the screen and flip the screen (make it visible). // Should only be called with updateMutex locked. -void ScreenRecoveryUI::update_screen_locked() -{ +void ScreenRecoveryUI::update_screen_locked() { draw_screen_locked(); gr_flip(); } // Updates only the progress bar, if possible, otherwise redraws the screen. // Should only be called with updateMutex locked. -void ScreenRecoveryUI::update_progress_locked() -{ +void ScreenRecoveryUI::update_progress_locked() { if (show_text || !pagesIdentical) { draw_screen_locked(); // Must redraw the whole screen pagesIdentical = true; @@ -354,8 +349,7 @@ static char** Alloc2d(size_t rows, size_t cols) { return result; } -void ScreenRecoveryUI::Init() -{ +void ScreenRecoveryUI::Init() { gr_init(); gr_font_size(&char_width, &char_height); @@ -416,8 +410,7 @@ void ScreenRecoveryUI::SetLocale(const char* new_locale) { } } -void ScreenRecoveryUI::SetBackground(Icon icon) -{ +void ScreenRecoveryUI::SetBackground(Icon icon) { pthread_mutex_lock(&updateMutex); currentIcon = icon; @@ -426,8 +419,7 @@ void ScreenRecoveryUI::SetBackground(Icon icon) pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::SetProgressType(ProgressType type) -{ +void ScreenRecoveryUI::SetProgressType(ProgressType type) { pthread_mutex_lock(&updateMutex); if (progressBarType != type) { progressBarType = type; @@ -439,8 +431,7 @@ void ScreenRecoveryUI::SetProgressType(ProgressType type) pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::ShowProgress(float portion, float seconds) -{ +void ScreenRecoveryUI::ShowProgress(float portion, float seconds) { pthread_mutex_lock(&updateMutex); progressBarType = DETERMINATE; progressScopeStart += progressScopeSize; @@ -452,8 +443,7 @@ void ScreenRecoveryUI::ShowProgress(float portion, float seconds) pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::SetProgress(float fraction) -{ +void ScreenRecoveryUI::SetProgress(float fraction) { pthread_mutex_lock(&updateMutex); if (fraction < 0.0) fraction = 0.0; if (fraction > 1.0) fraction = 1.0; @@ -476,8 +466,7 @@ void ScreenRecoveryUI::SetStage(int current, int max) { pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::Print(const char *fmt, ...) -{ +void ScreenRecoveryUI::Print(const char *fmt, ...) { char buf[256]; va_list ap; va_start(ap, fmt); @@ -486,10 +475,9 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) fputs(buf, stdout); - // This can get called before ui_init(), so be careful. pthread_mutex_lock(&updateMutex); if (text_rows > 0 && text_cols > 0) { - for (char* ptr = buf; *ptr != '\0'; ++ptr) { + for (const char* ptr = buf; *ptr != '\0'; ++ptr) { if (*ptr == '\n' || text_col >= text_cols) { text[text_row][text_col] = '\0'; text_col = 0; @@ -504,6 +492,75 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) pthread_mutex_unlock(&updateMutex); } +// TODO: replace this with something not line-based so we can wrap correctly without getting +// confused about what line we're on. +void ScreenRecoveryUI::print_no_update(const char* s) { + pthread_mutex_lock(&updateMutex); + if (text_rows > 0 && text_cols > 0) { + for (const char* ptr = s; *ptr != '\0'; ++ptr) { + if (*ptr == '\n' || text_col >= text_cols) { + text[text_row][text_col] = '\0'; + text_col = 0; + text_row = (text_row + 1) % text_rows; + if (text_row == text_top) text_top = (text_top + 1) % text_rows; + } + if (*ptr != '\n') text[text_row][text_col++] = *ptr; + } + text[text_row][text_col] = '\0'; + } + pthread_mutex_unlock(&updateMutex); +} + +void ScreenRecoveryUI::ShowFile(const char* filename) { + FILE* fp = fopen_path(filename, "re"); + if (fp == nullptr) { + Print(" Unable to open %s: %s\n", filename, strerror(errno)); + return; + } + + char line[1024]; + int ct = 0; + int key = 0; + while (fgets(line, sizeof(line), fp) != nullptr) { + print_no_update(line); + ct++; + if (ct % text_rows == 0) { + Redraw(); + + // give the user time to glance at the entries + key = WaitKey(); + + if (key == KEY_POWER) { + break; + } else if (key == KEY_VOLUMEUP) { + // Go back by seeking to the beginning and dumping ct - n + // lines. It's ugly, but this way we don't need to store + // the previous offsets. The files we're dumping here aren't + // expected to be very large. + ct -= 2 * text_rows; + if (ct < 0) { + ct = 0; + } + fseek(fp, 0, SEEK_SET); + for (int i = 0; i < ct; i++) { + fgets(line, sizeof(line), fp); + } + Print("^^^^^^^^^^\n"); + } else { + // Next page. + } + } + } + + // If the user didn't abort, then give the user time to glance at + // the end of the log, sorry, no rewind here + if (key != KEY_POWER) { + Print("\n--END-- (press any key)\n"); + WaitKey(); + } + fclose(fp); +} + void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, int initial_selection) { pthread_mutex_lock(&updateMutex); @@ -554,33 +611,29 @@ void ScreenRecoveryUI::EndMenu() { pthread_mutex_unlock(&updateMutex); } -bool ScreenRecoveryUI::IsTextVisible() -{ +bool ScreenRecoveryUI::IsTextVisible() { pthread_mutex_lock(&updateMutex); int visible = show_text; pthread_mutex_unlock(&updateMutex); return visible; } -bool ScreenRecoveryUI::WasTextEverVisible() -{ +bool ScreenRecoveryUI::WasTextEverVisible() { pthread_mutex_lock(&updateMutex); int ever_visible = show_text_ever; pthread_mutex_unlock(&updateMutex); return ever_visible; } -void ScreenRecoveryUI::ShowText(bool visible) -{ +void ScreenRecoveryUI::ShowText(bool visible) { pthread_mutex_lock(&updateMutex); show_text = visible; - if (show_text) show_text_ever = 1; + if (show_text) show_text_ever = true; update_screen_locked(); pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::Redraw() -{ +void ScreenRecoveryUI::Redraw() { pthread_mutex_lock(&updateMutex); update_screen_locked(); pthread_mutex_unlock(&updateMutex); -- cgit v1.2.3 From 642aaa7a3e11b2de719fc9decc45174bcc235c0c Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Apr 2015 12:47:46 -0700 Subject: Fix ScreenRecoveryUI to handle devices without power/up/down. Currently fugu has a custom subclass to handle this. The default code supports devices with trackballs but not all shipping Nexus devices? That's just silly. Change-Id: Id2779c91284899a26b4bb1af41e7033aa889df10 --- screen_ui.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 6d8df68b3..b62417f5f 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -185,6 +185,9 @@ void ScreenRecoveryUI::SetColor(UIElement e) { case MENU_SEL_BG: gr_color(0, 106, 157, 255); break; + case MENU_SEL_BG_ACTIVE: + gr_color(0, 156, 100, 255); + break; case MENU_SEL_FG: gr_color(255, 255, 255, 255); break; @@ -220,7 +223,7 @@ void ScreenRecoveryUI::draw_screen_locked() { if (i == menu_top + menu_sel) { // draw the highlight bar - SetColor(MENU_SEL_BG); + SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG); gr_fill(0, y-2, gr_fb_width(), y+char_height+2); // white text of selected item SetColor(MENU_SEL_FG); @@ -638,3 +641,9 @@ void ScreenRecoveryUI::Redraw() { update_screen_locked(); pthread_mutex_unlock(&updateMutex); } + +void ScreenRecoveryUI::KeyLongPress(int) { + // Redraw so that if we're in the menu, the highlight + // will change color to indicate a successful long press. + Redraw(); +} -- cgit v1.2.3 From 95fc63e87b7cd04cce65f78954b56b5cbc5d6c23 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Apr 2015 19:12:01 -0700 Subject: Rewritten file pager. Most importantly, this one no longer skips lines because of wrapping. Change-Id: Ic1c1944682ab8cbf3d542418ee86d29819173fc9 --- screen_ui.cpp | 146 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 64 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index b62417f5f..1e42ee7b4 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include "common.h" #include "device.h" #include "minui/minui.h" @@ -203,6 +205,13 @@ void ScreenRecoveryUI::SetColor(UIElement e) { } } +void ScreenRecoveryUI::DrawHorizontalRule(int* y) { + SetColor(MENU); + *y += 4; + gr_fill(0, *y, gr_fb_width(), *y + 2); + *y += 8; +} + // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. void ScreenRecoveryUI::draw_screen_locked() { @@ -214,12 +223,11 @@ void ScreenRecoveryUI::draw_screen_locked() { gr_clear(); int y = 0; - int i = 0; if (show_menu) { SetColor(HEADER); - for (; i < menu_top + menu_items; ++i) { - if (i == menu_top) SetColor(MENU); + for (int i = 0; i < menu_top + menu_items; ++i) { + if (i == menu_top) DrawHorizontalRule(&y); if (i == menu_top + menu_sel) { // draw the highlight bar @@ -234,11 +242,8 @@ void ScreenRecoveryUI::draw_screen_locked() { } y += char_height+4; } - SetColor(MENU); - y += 4; - gr_fill(0, y, gr_fb_width(), y+2); - y += 4; - ++i; + + DrawHorizontalRule(&y); } SetColor(LOG); @@ -249,7 +254,7 @@ void ScreenRecoveryUI::draw_screen_locked() { int row = (text_top+text_rows-1) % text_rows; size_t count = 0; for (int ty = gr_fb_height() - char_height; - ty > y+2 && count < text_rows; + ty >= y && count < text_rows; ty -= char_height, ++count) { gr_text(0, ty, text[row], 0); --row; @@ -495,72 +500,85 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { pthread_mutex_unlock(&updateMutex); } -// TODO: replace this with something not line-based so we can wrap correctly without getting -// confused about what line we're on. -void ScreenRecoveryUI::print_no_update(const char* s) { +void ScreenRecoveryUI::PutChar(char ch) { pthread_mutex_lock(&updateMutex); - if (text_rows > 0 && text_cols > 0) { - for (const char* ptr = s; *ptr != '\0'; ++ptr) { - if (*ptr == '\n' || text_col >= text_cols) { - text[text_row][text_col] = '\0'; - text_col = 0; - text_row = (text_row + 1) % text_rows; - if (text_row == text_top) text_top = (text_top + 1) % text_rows; - } - if (*ptr != '\n') text[text_row][text_col++] = *ptr; - } - text[text_row][text_col] = '\0'; + if (ch != '\n') text[text_row][text_col++] = ch; + if (ch == '\n' || text_col >= text_cols) { + text_col = 0; + ++text_row; } pthread_mutex_unlock(&updateMutex); } -void ScreenRecoveryUI::ShowFile(const char* filename) { - FILE* fp = fopen_path(filename, "re"); - if (fp == nullptr) { - Print(" Unable to open %s: %s\n", filename, strerror(errno)); - return; +void ScreenRecoveryUI::ClearText() { + pthread_mutex_lock(&updateMutex); + text_col = 0; + text_row = 0; + text_top = 1; + for (size_t i = 0; i < text_rows; ++i) { + memset(text[i], 0, text_cols + 1); } + pthread_mutex_unlock(&updateMutex); +} - char line[1024]; - int ct = 0; - int key = 0; - while (fgets(line, sizeof(line), fp) != nullptr) { - print_no_update(line); - ct++; - if (ct % text_rows == 0) { - Redraw(); +void ScreenRecoveryUI::ShowFile(FILE* fp) { + std::vector offsets; + offsets.push_back(ftell(fp)); + ClearText(); - // give the user time to glance at the entries - key = WaitKey(); + struct stat sb; + fstat(fileno(fp), &sb); - if (key == KEY_POWER) { - break; - } else if (key == KEY_VOLUMEUP) { - // Go back by seeking to the beginning and dumping ct - n - // lines. It's ugly, but this way we don't need to store - // the previous offsets. The files we're dumping here aren't - // expected to be very large. - ct -= 2 * text_rows; - if (ct < 0) { - ct = 0; - } - fseek(fp, 0, SEEK_SET); - for (int i = 0; i < ct; i++) { - fgets(line, sizeof(line), fp); + bool show_prompt = false; + while (true) { + if (show_prompt) { + Print("--(%d%% of %d bytes)--", + static_cast(100 * (double(ftell(fp)) / double(sb.st_size))), + static_cast(sb.st_size)); + Redraw(); + while (show_prompt) { + show_prompt = false; + int key = WaitKey(); + if (key == KEY_POWER) { + return; + } else if (key == KEY_UP || key == KEY_VOLUMEUP) { + if (offsets.size() <= 1) { + show_prompt = true; + } else { + offsets.pop_back(); + fseek(fp, offsets.back(), SEEK_SET); + } + } else { + if (feof(fp)) { + return; + } + offsets.push_back(ftell(fp)); } - Print("^^^^^^^^^^\n"); - } else { - // Next page. + } + ClearText(); + } + + int ch = getc(fp); + if (ch == EOF) { + text_row = text_top = text_rows - 2; + show_prompt = true; + } else { + PutChar(ch); + if (text_col == 0 && text_row >= text_rows - 2) { + text_top = text_row; + show_prompt = true; } } } +} - // If the user didn't abort, then give the user time to glance at - // the end of the log, sorry, no rewind here - if (key != KEY_POWER) { - Print("\n--END-- (press any key)\n"); - WaitKey(); +void ScreenRecoveryUI::ShowFile(const char* filename) { + FILE* fp = fopen_path(filename, "re"); + if (fp == nullptr) { + Print(" Unable to open %s: %s\n", filename, strerror(errno)); + return; } + ShowFile(fp); fclose(fp); } @@ -581,7 +599,7 @@ void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const menu[i][text_cols-1] = '\0'; } menu_items = i - menu_top; - show_menu = 1; + show_menu = true; menu_sel = initial_selection; update_screen_locked(); } @@ -590,7 +608,7 @@ void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const int ScreenRecoveryUI::SelectMenu(int sel) { pthread_mutex_lock(&updateMutex); - if (show_menu > 0) { + if (show_menu) { int old_sel = menu_sel; menu_sel = sel; @@ -607,8 +625,8 @@ int ScreenRecoveryUI::SelectMenu(int sel) { void ScreenRecoveryUI::EndMenu() { pthread_mutex_lock(&updateMutex); - if (show_menu > 0 && text_rows > 0 && text_cols > 0) { - show_menu = 0; + if (show_menu && text_rows > 0 && text_cols > 0) { + show_menu = false; update_screen_locked(); } pthread_mutex_unlock(&updateMutex); -- cgit v1.2.3 From 300ed089b3c5717ddf46eb3a25d94c8d017e7be2 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 13 Apr 2015 10:47:59 -0700 Subject: Treat KEY_ENTER the same as KEY_POWER in the pager. Our long-press UI sends KEY_ENTER for long presses, which the long-press UI treats as equivalent to KEY_POWER in the regular UI. So anywhere we accept KEY_POWER we should accept KEY_ENTER too. Change-Id: I99d376c961887043cf02037c26d000c8ba4d66f9 --- screen_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 1e42ee7b4..cca261fc4 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -539,7 +539,7 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) { while (show_prompt) { show_prompt = false; int key = WaitKey(); - if (key == KEY_POWER) { + if (key == KEY_POWER || key == KEY_ENTER) { return; } else if (key == KEY_UP || key == KEY_VOLUMEUP) { if (offsets.size() <= 1) { -- cgit v1.2.3 From 985022a6231814de2bfaf621fd0725c48bb98411 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 13 Apr 2015 13:04:32 -0700 Subject: Remove unnecessary globals. Change-Id: I76a042432aede08ceaf250319cf5eeb25d601150 --- screen_ui.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 1e42ee7b4..2aa3dab19 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -39,11 +39,6 @@ static int char_width; static int char_height; -// There's only (at most) one of these objects, and global callbacks -// (for pthread_create, and the input event system) need to find it, -// so use a global variable. -static ScreenRecoveryUI* self = nullptr; - // Return the current time as a double (including fractions of a second). static double now() { struct timeval tv; @@ -83,7 +78,6 @@ ScreenRecoveryUI::ScreenRecoveryUI() : backgroundIcon[i] = nullptr; } pthread_mutex_init(&updateMutex, nullptr); - self = this; } // Clear the screen and draw the currently selected background icon (if any). @@ -283,14 +277,14 @@ void ScreenRecoveryUI::update_progress_locked() { } // Keeps the progress bar updated, even when the process is otherwise busy. -void* ScreenRecoveryUI::progress_thread(void *cookie) { - self->progress_loop(); +void* ScreenRecoveryUI::ProgressThreadStartRoutine(void* data) { + reinterpret_cast(data)->ProgressThreadLoop(); return nullptr; } -void ScreenRecoveryUI::progress_loop() { +void ScreenRecoveryUI::ProgressThreadLoop() { double interval = 1.0 / animation_fps; - for (;;) { + while (true) { double start = now(); pthread_mutex_lock(&updateMutex); @@ -387,7 +381,7 @@ void ScreenRecoveryUI::Init() { LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]); LoadLocalizedBitmap("error_text", &backgroundText[ERROR]); - pthread_create(&progress_t, nullptr, progress_thread, nullptr); + pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this); RecoveryUI::Init(); } -- cgit v1.2.3 From 8fd86d77f1a2f15c6fa95bc390bcbe646374873a Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 13 Apr 2015 14:36:02 -0700 Subject: Move the menu header out of the menu. This makes it easier for us to deal with arbitrary information at the top, and means that headers added by specific commands don't overwrite the default ones. Add the fingerprint back, but broken up so it fits even on sprout's display. Change-Id: Id71da79ab1aa455a611d72756a3100a97ceb4c1c --- screen_ui.cpp | 86 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 28 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 76793350a..52f22c246 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -30,6 +30,8 @@ #include +#include "base/strings.h" +#include "cutils/properties.h" #include "common.h" #include "device.h" #include "minui/minui.h" @@ -66,7 +68,6 @@ ScreenRecoveryUI::ScreenRecoveryUI() : show_text_ever(false), menu(nullptr), show_menu(false), - menu_top(0), menu_items(0), menu_sel(0), animation_fps(20), @@ -174,6 +175,9 @@ void ScreenRecoveryUI::draw_progress_locked() { void ScreenRecoveryUI::SetColor(UIElement e) { switch (e) { + case INFO: + gr_color(249, 194, 0, 255); + break; case HEADER: gr_color(247, 0, 6, 255); break; @@ -188,7 +192,7 @@ void ScreenRecoveryUI::SetColor(UIElement e) { gr_color(255, 255, 255, 255); break; case LOG: - gr_color(249, 194, 0, 255); + gr_color(196, 196, 196, 255); break; case TEXT_FILL: gr_color(0, 0, 0, 160); @@ -203,9 +207,31 @@ void ScreenRecoveryUI::DrawHorizontalRule(int* y) { SetColor(MENU); *y += 4; gr_fill(0, *y, gr_fb_width(), *y + 2); - *y += 8; + *y += 4; +} + +void ScreenRecoveryUI::DrawTextLine(int* y, const char* line, bool bold) { + gr_text(4, *y, line, bold); + *y += char_height + 4; } +void ScreenRecoveryUI::DrawTextLines(int* y, const char* const* lines) { + for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) { + DrawTextLine(y, lines[i], false); + } +} + +static const char* REGULAR_HELP[] = { + "Use volume up/down and power.", + NULL +}; + +static const char* LONG_PRESS_HELP[] = { + "Any button cycles highlight.", + "Long-press activates.", + NULL +}; + // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. void ScreenRecoveryUI::draw_screen_locked() { @@ -218,39 +244,49 @@ void ScreenRecoveryUI::draw_screen_locked() { int y = 0; if (show_menu) { - SetColor(HEADER); + char recovery_fingerprint[PROPERTY_VALUE_MAX]; + property_get("ro.bootimage.build.fingerprint", recovery_fingerprint, ""); + + SetColor(INFO); + DrawTextLine(&y, "Android Recovery", true); + for (auto& chunk : android::base::Split(recovery_fingerprint, ":")) { + DrawTextLine(&y, chunk.c_str(), false); + } + DrawTextLines(&y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP); - for (int i = 0; i < menu_top + menu_items; ++i) { - if (i == menu_top) DrawHorizontalRule(&y); + SetColor(HEADER); + DrawTextLines(&y, menu_headers); - if (i == menu_top + menu_sel) { - // draw the highlight bar + SetColor(MENU); + DrawHorizontalRule(&y); + y += 4; + for (int i = 0; i < menu_items; ++i) { + if (i == menu_sel) { + // Draw the highlight bar. SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG); - gr_fill(0, y-2, gr_fb_width(), y+char_height+2); - // white text of selected item + gr_fill(0, y - 2, gr_fb_width(), y + char_height + 2); + // Bold white text for the selected item. SetColor(MENU_SEL_FG); - if (menu[i][0]) gr_text(4, y, menu[i], 1); + gr_text(4, y, menu[i], true); SetColor(MENU); } else { - if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top); + gr_text(4, y, menu[i], false); } - y += char_height+4; + y += char_height + 4; } - DrawHorizontalRule(&y); } - SetColor(LOG); - // display from the bottom up, until we hit the top of the // screen, the bottom of the menu, or we've displayed the // entire text buffer. + SetColor(LOG); int row = (text_top+text_rows-1) % text_rows; size_t count = 0; for (int ty = gr_fb_height() - char_height; ty >= y && count < text_rows; ty -= char_height, ++count) { - gr_text(0, ty, text[row], 0); + gr_text(0, ty, text[row], false); --row; if (row < 0) row = text_rows-1; } @@ -580,19 +616,13 @@ void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const int initial_selection) { pthread_mutex_lock(&updateMutex); if (text_rows > 0 && text_cols > 0) { - size_t i; - for (i = 0; i < text_rows; ++i) { - if (headers[i] == nullptr) break; - strncpy(menu[i], headers[i], text_cols-1); - menu[i][text_cols-1] = '\0'; - } - menu_top = i; - for (; i < text_rows; ++i) { - if (items[i-menu_top] == nullptr) break; - strncpy(menu[i], items[i-menu_top], text_cols-1); + menu_headers = headers; + size_t i = 0; + for (; i < text_rows && items[i] != nullptr; ++i) { + strncpy(menu[i], items[i], text_cols-1); menu[i][text_cols-1] = '\0'; } - menu_items = i - menu_top; + menu_items = i; show_menu = true; menu_sel = initial_selection; update_screen_locked(); -- cgit v1.2.3 From 0a5cb0c7cd995ae0330a7d54a8d0db5d892a48a9 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 15 Apr 2015 10:58:56 -0700 Subject: Don't use typedefs that hide *s. gr_surface was causing confusion for no good reason. Change-Id: If7120187f9a00dd16297877fc49352185a4d4ea6 --- screen_ui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 52f22c246..5e73d37c4 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -89,11 +89,11 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon) { gr_clear(); if (icon) { - gr_surface surface = backgroundIcon[icon]; + GRSurface* surface = backgroundIcon[icon]; if (icon == INSTALLING_UPDATE || icon == ERASING) { surface = installation[installingFrame]; } - gr_surface text_surface = backgroundText[icon]; + GRSurface* text_surface = backgroundText[icon]; int iconWidth = gr_get_width(surface); int iconHeight = gr_get_height(surface); @@ -132,7 +132,7 @@ void ScreenRecoveryUI::draw_progress_locked() { if (currentIcon == ERROR) return; if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { - gr_surface icon = installation[installingFrame]; + GRSurface* icon = installation[installingFrame]; gr_blit(icon, 0, 0, gr_get_width(icon), gr_get_height(icon), iconX, iconY); } @@ -357,21 +357,21 @@ void ScreenRecoveryUI::ProgressThreadLoop() { } } -void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) { +void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) { int result = res_create_display_surface(filename, surface); if (result < 0) { LOGE("missing bitmap %s\n(Code %d)\n", filename, result); } } -void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, gr_surface** surface) { +void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, GRSurface*** surface) { int result = res_create_multi_display_surface(filename, frames, surface); if (result < 0) { LOGE("missing bitmap %s\n(Code %d)\n", filename, result); } } -void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, gr_surface* surface) { +void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) { int result = res_create_localized_alpha_surface(filename, locale, surface); if (result < 0) { LOGE("missing bitmap %s\n(Code %d)\n", filename, result); -- cgit v1.2.3 From df52e1e119804cc5e7d0b7f77a7d1bf42b2da9dc Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 6 May 2015 12:40:05 -0700 Subject: Add an alternate screen for viewing recovery logs. This makes it easier to go back and forth without losing current output. Also make the display more like regular more(1). Bug: http://b/20834540 Change-Id: Icc5703e9c8a378cc7072d8ebb79e34451267ee1b (cherry picked from commit c049163234003ef463bca018920622bc8269c69b) --- screen_ui.cpp | 110 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 46 deletions(-) (limited to 'screen_ui.cpp') diff --git a/screen_ui.cpp b/screen_ui.cpp index 5e73d37c4..ff9591514 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -58,18 +58,19 @@ ScreenRecoveryUI::ScreenRecoveryUI() : progressScopeSize(0), progress(0), pagesIdentical(false), - text(nullptr), - text_cols(0), - text_rows(0), - text_col(0), - text_row(0), - text_top(0), + text_cols_(0), + text_rows_(0), + text_(nullptr), + text_col_(0), + text_row_(0), + text_top_(0), show_text(false), show_text_ever(false), - menu(nullptr), + menu_(nullptr), show_menu(false), menu_items(0), menu_sel(0), + file_viewer_text_(nullptr), animation_fps(20), installing_frames(-1), stage(-1), @@ -255,7 +256,7 @@ void ScreenRecoveryUI::draw_screen_locked() { DrawTextLines(&y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP); SetColor(HEADER); - DrawTextLines(&y, menu_headers); + DrawTextLines(&y, menu_headers_); SetColor(MENU); DrawHorizontalRule(&y); @@ -267,10 +268,10 @@ void ScreenRecoveryUI::draw_screen_locked() { gr_fill(0, y - 2, gr_fb_width(), y + char_height + 2); // Bold white text for the selected item. SetColor(MENU_SEL_FG); - gr_text(4, y, menu[i], true); + gr_text(4, y, menu_[i], true); SetColor(MENU); } else { - gr_text(4, y, menu[i], false); + gr_text(4, y, menu_[i], false); } y += char_height + 4; } @@ -281,14 +282,14 @@ void ScreenRecoveryUI::draw_screen_locked() { // screen, the bottom of the menu, or we've displayed the // entire text buffer. SetColor(LOG); - int row = (text_top+text_rows-1) % text_rows; + int row = (text_top_ + text_rows_ - 1) % text_rows_; size_t count = 0; for (int ty = gr_fb_height() - char_height; - ty >= y && count < text_rows; + ty >= y && count < text_rows_; ty -= char_height, ++count) { - gr_text(0, ty, text[row], false); + gr_text(0, ty, text_[row], false); --row; - if (row < 0) row = text_rows-1; + if (row < 0) row = text_rows_ - 1; } } } @@ -391,14 +392,15 @@ void ScreenRecoveryUI::Init() { gr_init(); gr_font_size(&char_width, &char_height); - text_rows = gr_fb_height() / char_height; - text_cols = gr_fb_width() / char_width; + text_rows_ = gr_fb_height() / char_height; + text_cols_ = gr_fb_width() / char_width; - text = Alloc2d(text_rows, text_cols + 1); - menu = Alloc2d(text_rows, text_cols + 1); + text_ = Alloc2d(text_rows_, 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; + text_col_ = text_row_ = 0; + text_top_ = 1; backgroundIcon[NONE] = nullptr; LoadBitmapArray("icon_installing", &installing_frames, &installation); @@ -514,17 +516,17 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { fputs(buf, stdout); pthread_mutex_lock(&updateMutex); - if (text_rows > 0 && text_cols > 0) { + if (text_rows_ > 0 && text_cols_ > 0) { for (const char* ptr = buf; *ptr != '\0'; ++ptr) { - if (*ptr == '\n' || text_col >= text_cols) { - text[text_row][text_col] = '\0'; - text_col = 0; - text_row = (text_row + 1) % text_rows; - if (text_row == text_top) text_top = (text_top + 1) % text_rows; + if (*ptr == '\n' || text_col_ >= text_cols_) { + text_[text_row_][text_col_] = '\0'; + text_col_ = 0; + text_row_ = (text_row_ + 1) % text_rows_; + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; } - if (*ptr != '\n') text[text_row][text_col++] = *ptr; + if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; } - text[text_row][text_col] = '\0'; + text_[text_row_][text_col_] = '\0'; update_screen_locked(); } pthread_mutex_unlock(&updateMutex); @@ -532,21 +534,23 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) { void ScreenRecoveryUI::PutChar(char ch) { pthread_mutex_lock(&updateMutex); - if (ch != '\n') text[text_row][text_col++] = ch; - if (ch == '\n' || text_col >= text_cols) { - text_col = 0; - ++text_row; + if (ch != '\n') text_[text_row_][text_col_++] = ch; + if (ch == '\n' || text_col_ >= text_cols_) { + text_col_ = 0; + ++text_row_; + + if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; } pthread_mutex_unlock(&updateMutex); } void ScreenRecoveryUI::ClearText() { pthread_mutex_lock(&updateMutex); - text_col = 0; - text_row = 0; - text_top = 1; - for (size_t i = 0; i < text_rows; ++i) { - memset(text[i], 0, text_cols + 1); + text_col_ = 0; + text_row_ = 0; + text_top_ = 1; + for (size_t i = 0; i < text_rows_; ++i) { + memset(text_[i], 0, text_cols_ + 1); } pthread_mutex_unlock(&updateMutex); } @@ -590,12 +594,11 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) { int ch = getc(fp); if (ch == EOF) { - text_row = text_top = text_rows - 2; + while (text_row_ < text_rows_ - 1) PutChar('\n'); show_prompt = true; } else { PutChar(ch); - if (text_col == 0 && text_row >= text_rows - 2) { - text_top = text_row; + if (text_col_ == 0 && text_row_ >= text_rows_ - 1) { show_prompt = true; } } @@ -608,19 +611,34 @@ void ScreenRecoveryUI::ShowFile(const char* filename) { Print(" Unable to open %s: %s\n", filename, strerror(errno)); return; } + + char** old_text = text_; + size_t old_text_col = text_col_; + size_t old_text_row = text_row_; + size_t old_text_top = text_top_; + + // Swap in the alternate screen and clear it. + text_ = file_viewer_text_; + ClearText(); + ShowFile(fp); fclose(fp); + + text_ = old_text; + text_col_ = old_text_col; + text_row_ = old_text_row; + text_top_ = old_text_top; } void ScreenRecoveryUI::StartMenu(const char* const * headers, const char* const * items, int initial_selection) { pthread_mutex_lock(&updateMutex); - if (text_rows > 0 && text_cols > 0) { - menu_headers = headers; + if (text_rows_ > 0 && text_cols_ > 0) { + menu_headers_ = headers; size_t i = 0; - for (; i < text_rows && items[i] != nullptr; ++i) { - strncpy(menu[i], items[i], text_cols-1); - menu[i][text_cols-1] = '\0'; + for (; i < text_rows_ && items[i] != nullptr; ++i) { + strncpy(menu_[i], items[i], text_cols_ - 1); + menu_[i][text_cols_ - 1] = '\0'; } menu_items = i; show_menu = true; @@ -649,7 +667,7 @@ int ScreenRecoveryUI::SelectMenu(int sel) { void ScreenRecoveryUI::EndMenu() { pthread_mutex_lock(&updateMutex); - if (show_menu && text_rows > 0 && text_cols > 0) { + if (show_menu && text_rows_ > 0 && text_cols_ > 0) { show_menu = false; update_screen_locked(); } -- cgit v1.2.3