From 337db14f274fc73dd540aa71d2c21c431fe686ec Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 20 Aug 2015 14:52:57 -0700 Subject: recovery: Factor out wear_ui.{cpp,h} into bootable/recovery. Every watch has a (mostly identical) copy of the wear_ui. Factor them out into a single copy for easier maintenance. Device-specific settings should be defined in recovery_ui.cpp that inherits WearRecoveryUI class. Bug: 22451422 Change-Id: Id07efca37d1b1d330e6327506c7b73ccf6ae9241 --- Android.mk | 1 + wear_ui.cpp | 650 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wear_ui.h | 137 +++++++++++++ 3 files changed, 788 insertions(+) create mode 100644 wear_ui.cpp create mode 100644 wear_ui.h diff --git a/Android.mk b/Android.mk index 0484065..b31f730 100644 --- a/Android.mk +++ b/Android.mk @@ -41,6 +41,7 @@ LOCAL_SRC_FILES := \ screen_ui.cpp \ ui.cpp \ verifier.cpp \ + wear_ui.cpp \ LOCAL_MODULE := recovery diff --git a/wear_ui.cpp b/wear_ui.cpp new file mode 100644 index 0000000..4ae42c4 --- /dev/null +++ b/wear_ui.cpp @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "device.h" +#include "minui/minui.h" +#include "wear_ui.h" +#include "ui.h" +#include "cutils/properties.h" +#include "base/strings.h" + +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 WearRecoveryUI* self = NULL; + +// Return the current time as a double (including fractions of a second). +static double now() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec / 1000000.0; +} + +WearRecoveryUI::WearRecoveryUI() : + progress_bar_height(3), + progress_bar_width(200), + progress_bar_y(259), + outer_height(0), + outer_width(0), + menu_unusable_rows(0), + intro_frames(22), + loop_frames(60), + currentIcon(NONE), + intro_done(false), + current_frame(0), + animation_fps(30), + rtl_locale(false), + progressBarType(EMPTY), + progressScopeStart(0), + progressScopeSize(0), + progress(0), + text_cols(0), + text_rows(0), + text_col(0), + text_row(0), + text_top(0), + show_text(false), + show_text_ever(false), + show_menu(false), + menu_items(0), + menu_sel(0) { + + for (size_t i = 0; i < 5; i++) + backgroundIcon[i] = NULL; + + pthread_mutex_init(&updateMutex, NULL); + self = this; +} + +// Draw background frame on the screen. Does not flip pages. +// Should only be called with updateMutex locked. +void WearRecoveryUI::draw_background_locked(Icon icon) +{ + gr_color(0, 0, 0, 255); + gr_fill(0, 0, gr_fb_width(), gr_fb_height()); + + if (icon) { + GRSurface* surface; + if (icon == INSTALLING_UPDATE || icon == ERASING) { + if (!intro_done) { + surface = introFrames[current_frame]; + } else { + surface = loopFrames[current_frame]; + } + } + else { + surface = backgroundIcon[icon]; + } + + int width = gr_get_width(surface); + int height = gr_get_height(surface); + + int x = (gr_fb_width() - width) / 2; + int y = (gr_fb_height() - height) / 2; + + gr_blit(surface, 0, 0, width, height, x, y); + } +} + +// Draw the progress bar (if any) on the screen. Does not flip pages. +// Should only be called with updateMutex locked. +void WearRecoveryUI::draw_progress_locked() +{ + if (currentIcon == ERROR) return; + if (progressBarType != DETERMINATE) return; + + int width = progress_bar_width; + int height = progress_bar_height; + int dx = (gr_fb_width() - width)/2; + int dy = progress_bar_y; + + float p = progressScopeStart + progress * progressScopeSize; + int pos = (int) (p * width); + + gr_color(0x43, 0x43, 0x43, 0xff); + gr_fill(dx, dy, dx + width, dy + height); + + if (pos > 0) { + gr_color(0x02, 0xa8, 0xf3, 255); + if (rtl_locale) { + // Fill the progress bar from right to left. + gr_fill(dx + width - pos, dy, dx + width, dy + height); + } else { + // Fill the progress bar from left to right. + gr_fill(dx, dy, dx + pos, dy + height); + } + } +} + +void WearRecoveryUI::SetColor(UIElement e) { + switch (e) { + case HEADER: + gr_color(247, 0, 6, 255); + break; + case MENU: + case MENU_SEL_BG: + gr_color(0, 106, 157, 255); + break; + case MENU_SEL_FG: + gr_color(255, 255, 255, 255); + break; + case LOG: + gr_color(249, 194, 0, 255); + break; + case TEXT_FILL: + gr_color(0, 0, 0, 160); + break; + default: + gr_color(255, 255, 255, 255); + break; + } +} + +void WearRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) { + gr_text(x, *y, line, bold); + *y += char_height + 4; +} + +void WearRecoveryUI::DrawTextLines(int x, int* y, const char* const* lines) { + for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) { + DrawTextLine(x, y, lines[i], false); + } +} + +static const char* HEADERS[] = { + "Swipe up/down to move.", + "Swipe left/right to select.", + "", + NULL +}; + +void WearRecoveryUI::draw_screen_locked() +{ + draw_background_locked(currentIcon); + draw_progress_locked(); + char cur_selection_str[50]; + + if (show_text) { + SetColor(TEXT_FILL); + gr_fill(0, 0, gr_fb_width(), gr_fb_height()); + + int y = outer_height; + int x = outer_width; + if (show_menu) { + char recovery_fingerprint[PROPERTY_VALUE_MAX]; + property_get("ro.bootimage.build.fingerprint", recovery_fingerprint, ""); + SetColor(HEADER); + DrawTextLine(x + 4, &y, "Android Recovery", true); + for (auto& chunk: android::base::Split(recovery_fingerprint, ":")) { + DrawTextLine(x +4, &y, chunk.c_str(), false); + } + + // This is actually the help strings. + DrawTextLines(x + 4, &y, HEADERS); + SetColor(HEADER); + DrawTextLines(x + 4, &y, menu_headers_); + + // Show the current menu item number in relation to total number if + // items don't fit on the screen. + if (menu_items > menu_end - menu_start) { + sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items); + gr_text(x+4, y, cur_selection_str, 1); + y += char_height+4; + } + + // Menu begins here + SetColor(MENU); + + for (int i = menu_start; i < menu_end; ++i) { + + if (i == menu_sel) { + // draw the highlight bar + SetColor(MENU_SEL_BG); + gr_fill(x, y-2, gr_fb_width()-x, y+char_height+2); + // white text of selected item + SetColor(MENU_SEL_FG); + if (menu[i][0]) gr_text(x+4, y, menu[i], 1); + SetColor(MENU); + } else { + if (menu[i][0]) gr_text(x+4, y, menu[i], 0); + } + y += char_height+4; + } + SetColor(MENU); + y += 4; + gr_fill(0, y, gr_fb_width(), y+2); + y += 4; + } + + 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. + int ty; + int row = (text_top+text_rows-1) % text_rows; + size_t count = 0; + for (int ty = gr_fb_height() - char_height - outer_height; + ty > y+2 && count < text_rows; + ty -= char_height, ++count) { + gr_text(x+4, ty, text[row], 0); + --row; + if (row < 0) row = text_rows-1; + } + } +} + +void WearRecoveryUI::update_screen_locked() +{ + draw_screen_locked(); + gr_flip(); +} + +// Keeps the progress bar updated, even when the process is otherwise busy. +void* WearRecoveryUI::progress_thread(void *cookie) { + self->progress_loop(); + return NULL; +} + +void WearRecoveryUI::progress_loop() { + double interval = 1.0 / animation_fps; + for (;;) { + double start = now(); + pthread_mutex_lock(&updateMutex); + int redraw = 0; + + if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) + && !show_text) { + if (!intro_done) { + if (current_frame == intro_frames - 1) { + intro_done = true; + current_frame = 0; + } else { + current_frame++; + } + } else { + current_frame = (current_frame + 1) % loop_frames; + } + redraw = 1; + } + + // move the progress bar forward on timed intervals, if configured + int duration = progressScopeDuration; + if (progressBarType == DETERMINATE && duration > 0) { + double elapsed = now() - progressScopeTime; + float p = 1.0 * elapsed / duration; + if (p > 1.0) p = 1.0; + if (p > progress) { + progress = p; + redraw = 1; + } + } + + if (redraw) + update_screen_locked(); + + pthread_mutex_unlock(&updateMutex); + double end = now(); + // minimum of 20ms delay between frames + double delay = interval - (end-start); + if (delay < 0.02) delay = 0.02; + usleep((long)(delay * 1000000)); + } +} + +void WearRecoveryUI::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 WearRecoveryUI::Init() +{ + gr_init(); + + gr_font_size(&char_width, &char_height); + + text_col = text_row = 0; + text_rows = (gr_fb_height()) / char_height; + visible_text_rows = (gr_fb_height() - (outer_height * 2)) / char_height; + if (text_rows > kMaxRows) text_rows = kMaxRows; + text_top = 1; + + text_cols = (gr_fb_width() - (outer_width * 2)) / char_width; + if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1; + + LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]); + backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE]; + LoadBitmap("icon_error", &backgroundIcon[ERROR]); + backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR]; + + introFrames = (GRSurface**)malloc(intro_frames * sizeof(GRSurface*)); + for (int i = 0; i < intro_frames; ++i) { + char filename[40]; + sprintf(filename, "intro%02d", i); + LoadBitmap(filename, introFrames + i); + } + + loopFrames = (GRSurface**)malloc(loop_frames * sizeof(GRSurface*)); + for (int i = 0; i < loop_frames; ++i) { + char filename[40]; + sprintf(filename, "loop%02d", i); + LoadBitmap(filename, loopFrames + i); + } + + pthread_create(&progress_t, NULL, progress_thread, NULL); + RecoveryUI::Init(); +} + +void WearRecoveryUI::SetLocale(const char* locale) { + if (locale) { + char* lang = strdup(locale); + for (char* p = lang; *p; ++p) { + if (*p == '_') { + *p = '\0'; + break; + } + } + + // A bit cheesy: keep an explicit list of supported languages + // that are RTL. + if (strcmp(lang, "ar") == 0 || // Arabic + strcmp(lang, "fa") == 0 || // Persian (Farsi) + strcmp(lang, "he") == 0 || // Hebrew (new language code) + strcmp(lang, "iw") == 0 || // Hebrew (old language code) + strcmp(lang, "ur") == 0) { // Urdu + rtl_locale = true; + } + free(lang); + } +} + +void WearRecoveryUI::SetBackground(Icon icon) +{ + pthread_mutex_lock(&updateMutex); + currentIcon = icon; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::SetProgressType(ProgressType type) +{ + pthread_mutex_lock(&updateMutex); + if (progressBarType != type) { + progressBarType = type; + } + progressScopeStart = 0; + progressScopeSize = 0; + progress = 0; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::ShowProgress(float portion, float seconds) +{ + pthread_mutex_lock(&updateMutex); + progressBarType = DETERMINATE; + progressScopeStart += progressScopeSize; + progressScopeSize = portion; + progressScopeTime = now(); + progressScopeDuration = seconds; + progress = 0; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::SetProgress(float fraction) +{ + pthread_mutex_lock(&updateMutex); + if (fraction < 0.0) fraction = 0.0; + if (fraction > 1.0) fraction = 1.0; + if (progressBarType == DETERMINATE && fraction > progress) { + // Skip updates that aren't visibly different. + int width = progress_bar_width; + float scale = width * progressScopeSize; + if ((int) (progress * scale) != (int) (fraction * scale)) { + progress = fraction; + update_screen_locked(); + } + } + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::SetStage(int current, int max) +{ +} + +void WearRecoveryUI::Print(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 256, fmt, ap); + va_end(ap); + + fputs(buf, stdout); + + // 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) { + 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'; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::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; + 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; + show_menu = 1; + menu_sel = initial_selection; + menu_start = 0; + menu_end = visible_text_rows - 1 - menu_unusable_rows; + if (menu_items <= menu_end) + menu_end = menu_items; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); +} + +int WearRecoveryUI::SelectMenu(int sel) { + int old_sel; + pthread_mutex_lock(&updateMutex); + 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; + if (menu_sel < menu_start) { + menu_start--; + menu_end--; + } else if (menu_sel >= menu_end && menu_sel < menu_items) { + menu_end++; + menu_start++; + } + sel = menu_sel; + if (menu_sel != old_sel) update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); + return sel; +} + +void WearRecoveryUI::EndMenu() { + int i; + pthread_mutex_lock(&updateMutex); + if (show_menu > 0 && text_rows > 0 && text_cols > 0) { + show_menu = 0; + update_screen_locked(); + } + pthread_mutex_unlock(&updateMutex); +} + +bool WearRecoveryUI::IsTextVisible() +{ + pthread_mutex_lock(&updateMutex); + int visible = show_text; + pthread_mutex_unlock(&updateMutex); + return visible; +} + +bool WearRecoveryUI::WasTextEverVisible() +{ + pthread_mutex_lock(&updateMutex); + int ever_visible = show_text_ever; + pthread_mutex_unlock(&updateMutex); + return ever_visible; +} + +void WearRecoveryUI::ShowText(bool visible) +{ + pthread_mutex_lock(&updateMutex); + // Don't show text during ota install or factory reset + if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { + pthread_mutex_unlock(&updateMutex); + return; + } + show_text = visible; + if (show_text) show_text_ever = 1; + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::Redraw() +{ + pthread_mutex_lock(&updateMutex); + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::ShowFile(FILE* fp) { + std::vector offsets; + offsets.push_back(ftell(fp)); + ClearText(); + + struct stat sb; + fstat(fileno(fp), &sb); + + 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 || key == KEY_ENTER) { + 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)); + } + } + 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; + } + } + } +} + +void WearRecoveryUI::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; + } + pthread_mutex_unlock(&updateMutex); +} + +void WearRecoveryUI::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); +} + +void WearRecoveryUI::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); +} diff --git a/wear_ui.h b/wear_ui.h new file mode 100644 index 0000000..839a264 --- /dev/null +++ b/wear_ui.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RECOVERY_WEAR_UI_H +#define RECOVERY_WEAR_UI_H + +#include +#include + +#include "ui.h" +#include "minui/minui.h" + +class WearRecoveryUI : public RecoveryUI { + public: + WearRecoveryUI(); + + void Init(); + void SetLocale(const char* locale); + + // overall recovery state ("background image") + void SetBackground(Icon icon); + + // progress indicator + void SetProgressType(ProgressType type); + void ShowProgress(float portion, float seconds); + void SetProgress(float fraction); + + void SetStage(int current, int max); + + // text log + void ShowText(bool visible); + bool IsTextVisible(); + bool WasTextEverVisible(); + + // printing messages + void Print(const char* fmt, ...); + void ShowFile(const char* filename); + void ShowFile(FILE* fp); + + // menu display + void StartMenu(const char* const * headers, const char* const * items, + int initial_selection); + int SelectMenu(int sel); + void EndMenu(); + + void Redraw(); + + enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL }; + virtual void SetColor(UIElement e); + + protected: + int progress_bar_height, progress_bar_width; + + // progress bar vertical position, it's centered horizontally + int progress_bar_y; + + // outer of window + int outer_height, outer_width; + + // Unusable rows when displaying the recovery menu, including the lines + // for headers (Android Recovery, build id and etc) and the bottom lines + // that may otherwise go out of the screen. + int menu_unusable_rows; + + // number of intro frames (default: 22) and loop frames (default: 60) + int intro_frames; + int loop_frames; + + private: + Icon currentIcon; + + bool intro_done; + + int current_frame; + + int animation_fps; + + bool rtl_locale; + + pthread_mutex_t updateMutex; + GRSurface* backgroundIcon[5]; + GRSurface* *introFrames; + GRSurface* *loopFrames; + + ProgressType progressBarType; + + float progressScopeStart, progressScopeSize, progress; + double progressScopeTime, progressScopeDuration; + + static const int kMaxCols = 96; + static const int kMaxRows = 96; + + // Log text overlay, displayed when a magic key is pressed + char text[kMaxRows][kMaxCols]; + size_t text_cols, text_rows; + // Number of text rows seen on screen + int visible_text_rows; + size_t text_col, text_row, text_top; + bool show_text; + bool show_text_ever; // has show_text ever been true? + + char menu[kMaxRows][kMaxCols]; + bool show_menu; + const char* const* menu_headers_; + int menu_items, menu_sel; + int menu_start, menu_end; + + pthread_t progress_t; + + private: + void draw_background_locked(Icon icon); + void draw_progress_locked(); + void draw_screen_locked(); + void update_screen_locked(); + static void* progress_thread(void* cookie); + void progress_loop(); + void LoadBitmap(const char* filename, GRSurface** surface); + void PutChar(char); + void ClearText(); + void DrawTextLine(int x, int* y, const char* line, bool bold); + void DrawTextLines(int x, int* y, const char* const* lines); +}; + +#endif // RECOVERY_WEAR_UI_H -- cgit v1.1 From 8e9c68019f9c284b89155c71922ad8ac84af6ab6 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 2 Sep 2015 11:20:30 -0700 Subject: recovery: Fix the bug that truncates menu entries. When there are 20 entries (like 10 last_log* and 10 last_kmg* in "view recovery logs"), there's no "Back" entry. Because the number of entries (21) exceeds text_rows (20) in WearRecoveryUI::StartMenu(). Since we have scrollable menu, having more entries than text_rows won't be an issue. Bug: 23752519 Change-Id: I12573d7a34852a1a3d130c9e88522cee737eb08f --- wear_ui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wear_ui.cpp b/wear_ui.cpp index 4ae42c4..55b7afc 100644 --- a/wear_ui.cpp +++ b/wear_ui.cpp @@ -482,7 +482,12 @@ void WearRecoveryUI::StartMenu(const char* const * headers, const char* const * if (text_rows > 0 && text_cols > 0) { menu_headers_ = headers; size_t i = 0; - for (; i < text_rows && items[i] != nullptr; i++) { + // "i < text_rows" is removed from the loop termination condition, + // which is different from the one in ScreenRecoveryUI::StartMenu(). + // Because WearRecoveryUI supports scrollable menu, it's fine to have + // more entries than text_rows. The menu may be truncated otherwise. + // Bug: 23752519 + for (; items[i] != nullptr; i++) { strncpy(menu[i], items[i], text_cols - 1); menu[i][text_cols - 1] = '\0'; } -- cgit v1.1 From a5d5082222b7420801cdb77f09305dd4c3afb4db Mon Sep 17 00:00:00 2001 From: Andriy Naborskyy Date: Fri, 8 Jan 2016 10:11:41 -0800 Subject: Revert "Byte swap to support BGRA in recovery mode" This reverts commit e5879c3639789d61803605c12371a4f291e0b3cc. The swap in page flip code is not needed any more. New changes take care of ABGR and BGRA formats swapping bytes in png and drawing routines See commit fd778e3e406a7e83536ea66776996f032f24af64 Bug: 26243152 Change-Id: I313ee41bee2c143b4e5412515285a65ac394ec77 --- minui/graphics_fbdev.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp index 997e9ca..0788f75 100644 --- a/minui/graphics_fbdev.cpp +++ b/minui/graphics_fbdev.cpp @@ -176,18 +176,6 @@ static GRSurface* fbdev_init(minui_backend* backend) { static GRSurface* fbdev_flip(minui_backend* backend __unused) { if (double_buffered) { -#if defined(RECOVERY_BGRA) - // In case of BGRA, do some byte swapping - unsigned int idx; - unsigned char tmp; - unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data; - for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes); - idx += 4) { - tmp = ucfb_vaddr[idx]; - ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2]; - ucfb_vaddr[idx + 2] = tmp; - } -#endif // Change gr_draw to point to the buffer currently displayed, // then flip the driver so we're displaying the other buffer // instead. -- cgit v1.1