| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2007 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 17 | #include <errno.h> | 
 | 18 | #include <fcntl.h> | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 19 | #include <linux/input.h> | 
 | 20 | #include <pthread.h> | 
 | 21 | #include <stdarg.h> | 
 | 22 | #include <stdio.h> | 
 | 23 | #include <stdlib.h> | 
 | 24 | #include <string.h> | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 25 | #include <sys/stat.h> | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 26 | #include <sys/time.h> | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 27 | #include <sys/types.h> | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 28 | #include <time.h> | 
 | 29 | #include <unistd.h> | 
 | 30 |  | 
 | 31 | #include "common.h" | 
| Ken Sumrall | 6e4472a | 2011-03-07 23:37:27 -0800 | [diff] [blame] | 32 | #include <cutils/android_reboot.h> | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 33 | #include "minui/minui.h" | 
| Doug Zongker | 23412e6 | 2009-07-23 10:16:07 -0700 | [diff] [blame] | 34 | #include "recovery_ui.h" | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 35 |  | 
| Tanguy Pruvot | 67d358c | 2011-06-10 20:26:44 +0200 | [diff] [blame] | 36 | extern int __system(const char *command); | 
 | 37 |  | 
| Koushik Dutta | d90ad5d | 2010-11-27 14:41:07 -0800 | [diff] [blame] | 38 | #ifdef BOARD_HAS_NO_SELECT_BUTTON | 
| Koushik Dutta | 4ca9b4c | 2010-07-14 18:37:33 -0700 | [diff] [blame] | 39 | static int gShowBackButton = 1; | 
 | 40 | #else | 
 | 41 | static int gShowBackButton = 0; | 
 | 42 | #endif | 
 | 43 |  | 
| Doug Zongker | 8a8e6cc | 2010-07-07 13:55:25 -0700 | [diff] [blame] | 44 | #define MAX_COLS 96 | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 45 | #define MAX_ROWS 32 | 
 | 46 |  | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 47 | #define MENU_MAX_COLS 64 | 
 | 48 | #define MENU_MAX_ROWS 250 | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 49 |  | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 50 | #define MIN_LOG_ROWS 3 | 
 | 51 |  | 
| Koushik Dutta | 18e3f62 | 2012-01-26 16:49:33 -0800 | [diff] [blame] | 52 | #define CHAR_WIDTH BOARD_RECOVERY_CHAR_WIDTH | 
 | 53 | #define CHAR_HEIGHT BOARD_RECOVERY_CHAR_HEIGHT | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 54 |  | 
| Koushik Dutta | 0e7d886 | 2011-11-16 16:47:53 -0800 | [diff] [blame] | 55 | #define UI_WAIT_KEY_TIMEOUT_SEC    3600 | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 56 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 57 | UIParameters ui_parameters = { | 
| Doug Zongker | be6d4d1 | 2011-03-02 10:38:02 -0800 | [diff] [blame] | 58 |     6,       // indeterminate progress bar frames | 
 | 59 |     20,      // fps | 
 | 60 |     7,       // installation icon frames (0 == static image) | 
| Doug Zongker | fdfb636 | 2011-09-20 14:16:46 -0700 | [diff] [blame] | 61 |     13, 190, // installation icon overlay offset | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 62 | }; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 63 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 64 | static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER; | 
 | 65 | static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS]; | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 66 | static gr_surface *gInstallationOverlay; | 
 | 67 | static gr_surface *gProgressBarIndeterminate; | 
| Doug Zongker | d93a254 | 2009-10-08 16:32:58 -0700 | [diff] [blame] | 68 | static gr_surface gProgressBarEmpty; | 
 | 69 | static gr_surface gProgressBarFill; | 
| Koushik Dutta | d3cc60b | 2010-07-03 13:56:45 -0700 | [diff] [blame] | 70 | static int ui_has_initialized = 0; | 
| Tanguy Pruvot | 67d358c | 2011-06-10 20:26:44 +0200 | [diff] [blame] | 71 | static int ui_log_stdout = 1; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 72 |  | 
 | 73 | static const struct { gr_surface* surface; const char *name; } BITMAPS[] = { | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 74 |     { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" }, | 
 | 75 |     { &gBackgroundIcon[BACKGROUND_ICON_ERROR],      "icon_error" }, | 
| Koushik Dutta | 5d80817 | 2010-12-18 22:29:27 -0800 | [diff] [blame] | 76 |     { &gBackgroundIcon[BACKGROUND_ICON_CLOCKWORK],  "icon_clockwork" }, | 
| Koushik Dutta | 7f13e15 | 2011-09-08 16:55:35 -0700 | [diff] [blame] | 77 |     { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_INSTALLING], "icon_firmware_install" }, | 
 | 78 |     { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_ERROR], "icon_firmware_error" }, | 
| Doug Zongker | d93a254 | 2009-10-08 16:32:58 -0700 | [diff] [blame] | 79 |     { &gProgressBarEmpty,               "progress_empty" }, | 
 | 80 |     { &gProgressBarFill,                "progress_fill" }, | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 81 |     { NULL,                             NULL }, | 
 | 82 | }; | 
 | 83 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 84 | static int gCurrentIcon = 0; | 
 | 85 | static int gInstallingFrame = 0; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 86 |  | 
 | 87 | static enum ProgressBarType { | 
 | 88 |     PROGRESSBAR_TYPE_NONE, | 
 | 89 |     PROGRESSBAR_TYPE_INDETERMINATE, | 
 | 90 |     PROGRESSBAR_TYPE_NORMAL, | 
 | 91 | } gProgressBarType = PROGRESSBAR_TYPE_NONE; | 
 | 92 |  | 
 | 93 | // Progress bar scope of current operation | 
 | 94 | static float gProgressScopeStart = 0, gProgressScopeSize = 0, gProgress = 0; | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 95 | static double gProgressScopeTime, gProgressScopeDuration; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 96 |  | 
 | 97 | // Set to 1 when both graphics pages are the same (except for the progress bar) | 
 | 98 | static int gPagesIdentical = 0; | 
 | 99 |  | 
 | 100 | // Log text overlay, displayed when a magic key is pressed | 
 | 101 | static char text[MAX_ROWS][MAX_COLS]; | 
 | 102 | static int text_cols = 0, text_rows = 0; | 
 | 103 | static int text_col = 0, text_row = 0, text_top = 0; | 
| Ying Wang | 532c860 | 2010-09-01 14:52:22 -0700 | [diff] [blame] | 104 | static int show_text = 0; | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 105 | static int show_text_ever = 0;   // has show_text ever been 1? | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 106 |  | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 107 | static char menu[MENU_MAX_ROWS][MENU_MAX_COLS]; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 108 | static int show_menu = 0; | 
 | 109 | static int menu_top = 0, menu_items = 0, menu_sel = 0; | 
| Tanguy Pruvot | 67d358c | 2011-06-10 20:26:44 +0200 | [diff] [blame] | 110 | static int menu_show_start = 0;             // this is line which menu display is starting at | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 111 | static int max_menu_rows; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 112 |  | 
 | 113 | // Key event input queue | 
 | 114 | static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 | 115 | static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER; | 
 | 116 | static int key_queue[256], key_queue_len = 0; | 
 | 117 | static volatile char key_pressed[KEY_MAX + 1]; | 
 | 118 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 119 | // Return the current time as a double (including fractions of a second). | 
 | 120 | static double now() { | 
 | 121 |     struct timeval tv; | 
 | 122 |     gettimeofday(&tv, NULL); | 
 | 123 |     return tv.tv_sec + tv.tv_usec / 1000000.0; | 
 | 124 | } | 
 | 125 |  | 
 | 126 | // Draw the given frame over the installation overlay animation.  The | 
 | 127 | // background is not cleared or draw with the base icon first; we | 
 | 128 | // assume that the frame already contains some other frame of the | 
 | 129 | // animation.  Does nothing if no overlay animation is defined. | 
 | 130 | // Should only be called with gUpdateMutex locked. | 
 | 131 | static void draw_install_overlay_locked(int frame) { | 
 | 132 |     if (gInstallationOverlay == NULL) return; | 
 | 133 |     gr_surface surface = gInstallationOverlay[frame]; | 
 | 134 |     int iconWidth = gr_get_width(surface); | 
 | 135 |     int iconHeight = gr_get_height(surface); | 
 | 136 |     gr_blit(surface, 0, 0, iconWidth, iconHeight, | 
 | 137 |             ui_parameters.install_overlay_offset_x, | 
 | 138 |             ui_parameters.install_overlay_offset_y); | 
 | 139 | } | 
 | 140 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 141 | // Clear the screen and draw the currently selected background icon (if any). | 
 | 142 | // Should only be called with gUpdateMutex locked. | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 143 | static void draw_background_locked(int icon) | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 144 | { | 
 | 145 |     gPagesIdentical = 0; | 
 | 146 |     gr_color(0, 0, 0, 255); | 
 | 147 |     gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | 
 | 148 |  | 
 | 149 |     if (icon) { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 150 |         gr_surface surface = gBackgroundIcon[icon]; | 
 | 151 |         int iconWidth = gr_get_width(surface); | 
 | 152 |         int iconHeight = gr_get_height(surface); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 153 |         int iconX = (gr_fb_width() - iconWidth) / 2; | 
 | 154 |         int iconY = (gr_fb_height() - iconHeight) / 2; | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 155 |         gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY); | 
 | 156 |         if (icon == BACKGROUND_ICON_INSTALLING) { | 
 | 157 |             draw_install_overlay_locked(gInstallingFrame); | 
 | 158 |         } | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 159 |     } | 
 | 160 | } | 
 | 161 |  | 
 | 162 | // Draw the progress bar (if any) on the screen.  Does not flip pages. | 
 | 163 | // Should only be called with gUpdateMutex locked. | 
 | 164 | static void draw_progress_locked() | 
 | 165 | { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 166 |     if (gCurrentIcon == BACKGROUND_ICON_INSTALLING) { | 
 | 167 |         draw_install_overlay_locked(gInstallingFrame); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 168 |     } | 
 | 169 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 170 |     if (gProgressBarType != PROGRESSBAR_TYPE_NONE) { | 
 | 171 |         int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]); | 
 | 172 |         int width = gr_get_width(gProgressBarEmpty); | 
 | 173 |         int height = gr_get_height(gProgressBarEmpty); | 
 | 174 |  | 
 | 175 |         int dx = (gr_fb_width() - width)/2; | 
 | 176 |         int dy = (3*gr_fb_height() + iconHeight - 2*height)/4; | 
 | 177 |  | 
 | 178 |         // Erase behind the progress bar (in case this was a progress-only update) | 
 | 179 |         gr_color(0, 0, 0, 255); | 
 | 180 |         gr_fill(dx, dy, width, height); | 
 | 181 |  | 
 | 182 |         if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) { | 
 | 183 |             float progress = gProgressScopeStart + gProgress * gProgressScopeSize; | 
 | 184 |             int pos = (int) (progress * width); | 
 | 185 |  | 
 | 186 |             if (pos > 0) { | 
 | 187 |                 gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy); | 
 | 188 |             } | 
 | 189 |             if (pos < width-1) { | 
 | 190 |                 gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy); | 
 | 191 |             } | 
 | 192 |         } | 
 | 193 |  | 
 | 194 |         if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) { | 
 | 195 |             static int frame = 0; | 
 | 196 |             gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy); | 
 | 197 |             frame = (frame + 1) % ui_parameters.indeterminate_frames; | 
 | 198 |         } | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 199 |     } | 
 | 200 | } | 
 | 201 |  | 
 | 202 | static void draw_text_line(int row, const char* t) { | 
 | 203 |   if (t[0] != '\0') { | 
 | 204 |     gr_text(0, (row+1)*CHAR_HEIGHT-1, t); | 
 | 205 |   } | 
 | 206 | } | 
 | 207 |  | 
| Koushik Dutta | 30a937a | 2011-09-05 21:14:06 -0700 | [diff] [blame] | 208 | //#define MENU_TEXT_COLOR 255, 160, 49, 255 | 
 | 209 | #define MENU_TEXT_COLOR 0, 191, 255, 255 | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 210 | #define NORMAL_TEXT_COLOR 200, 200, 200, 255 | 
 | 211 | #define HEADER_TEXT_COLOR NORMAL_TEXT_COLOR | 
 | 212 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 213 | // Redraw everything on the screen.  Does not flip pages. | 
 | 214 | // Should only be called with gUpdateMutex locked. | 
 | 215 | static void draw_screen_locked(void) | 
 | 216 | { | 
| Koushik Dutta | d3cc60b | 2010-07-03 13:56:45 -0700 | [diff] [blame] | 217 |     if (!ui_has_initialized) return; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 218 |     draw_background_locked(gCurrentIcon); | 
 | 219 |     draw_progress_locked(); | 
 | 220 |  | 
 | 221 |     if (show_text) { | 
 | 222 |         gr_color(0, 0, 0, 160); | 
 | 223 |         gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | 
 | 224 |  | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 225 |         int total_rows = gr_fb_height() / CHAR_HEIGHT; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 226 |         int i = 0; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 227 |         int j = 0; | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 228 |         int offset = 0;         // offset of separating bar under menus | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 229 |         int row = 0;            // current row that we are drawing on | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 230 |         if (show_menu) { | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 231 |             gr_color(MENU_TEXT_COLOR); | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 232 |             gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT, | 
 | 233 |                     gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 234 |  | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 235 |             gr_color(HEADER_TEXT_COLOR); | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 236 |             for (i = 0; i < menu_top; ++i) { | 
 | 237 |                 draw_text_line(i, menu[i]); | 
 | 238 |                 row++; | 
 | 239 |             } | 
 | 240 |  | 
 | 241 |             if (menu_items - menu_show_start + menu_top >= MAX_ROWS) | 
 | 242 |                 j = MAX_ROWS - menu_top; | 
 | 243 |             else | 
 | 244 |                 j = menu_items - menu_show_start; | 
 | 245 |  | 
 | 246 |             gr_color(MENU_TEXT_COLOR); | 
 | 247 |             for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) { | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 248 |                 if (i == menu_top + menu_sel) { | 
 | 249 |                     gr_color(255, 255, 255, 255); | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 250 |                     draw_text_line(i - menu_show_start , menu[i]); | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 251 |                     gr_color(MENU_TEXT_COLOR); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 252 |                 } else { | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 253 |                     gr_color(MENU_TEXT_COLOR); | 
 | 254 |                     draw_text_line(i - menu_show_start, menu[i]); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 255 |                 } | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 256 |                 row++; | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 257 |                 if (row == max_menu_rows) | 
 | 258 |                     break; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 259 |             } | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 260 |  | 
 | 261 |             if (menu_items <= MAX_ROWS) | 
 | 262 |                 offset = 1; | 
 | 263 |                      | 
 | 264 |             gr_fill(0, (row-offset)*CHAR_HEIGHT+CHAR_HEIGHT/2-1, | 
 | 265 |                     gr_fb_width(), (row-offset)*CHAR_HEIGHT+CHAR_HEIGHT/2+1); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 266 |         } | 
 | 267 |  | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 268 |         gr_color(NORMAL_TEXT_COLOR); | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 269 |         int cur_row = text_row; | 
 | 270 |         int available_rows = total_rows - row - 1; | 
 | 271 |         int start_row = row + 1; | 
 | 272 |         if (available_rows < MAX_ROWS) | 
 | 273 |             cur_row = (cur_row + (MAX_ROWS - available_rows)) % MAX_ROWS; | 
 | 274 |         else | 
 | 275 |             start_row = total_rows - MAX_ROWS; | 
 | 276 |  | 
 | 277 |         int r; | 
 | 278 |         for (r = 0; r < (available_rows < MAX_ROWS ? available_rows : MAX_ROWS); r++) { | 
 | 279 |             draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS]); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 280 |         } | 
 | 281 |     } | 
 | 282 | } | 
 | 283 |  | 
 | 284 | // Redraw everything on the screen and flip the screen (make it visible). | 
 | 285 | // Should only be called with gUpdateMutex locked. | 
 | 286 | static void update_screen_locked(void) | 
 | 287 | { | 
| Koushik Dutta | d3cc60b | 2010-07-03 13:56:45 -0700 | [diff] [blame] | 288 |     if (!ui_has_initialized) return; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 289 |     draw_screen_locked(); | 
 | 290 |     gr_flip(); | 
 | 291 | } | 
 | 292 |  | 
 | 293 | // Updates only the progress bar, if possible, otherwise redraws the screen. | 
 | 294 | // Should only be called with gUpdateMutex locked. | 
 | 295 | static void update_progress_locked(void) | 
 | 296 | { | 
| Koushik Dutta | d3cc60b | 2010-07-03 13:56:45 -0700 | [diff] [blame] | 297 |     if (!ui_has_initialized) return; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 298 |     if (show_text || !gPagesIdentical) { | 
 | 299 |         draw_screen_locked();    // Must redraw the whole screen | 
 | 300 |         gPagesIdentical = 1; | 
 | 301 |     } else { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 302 |         draw_progress_locked();  // Draw only the progress bar and overlays | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 303 |     } | 
 | 304 |     gr_flip(); | 
 | 305 | } | 
 | 306 |  | 
 | 307 | // Keeps the progress bar updated, even when the process is otherwise busy. | 
 | 308 | static void *progress_thread(void *cookie) | 
 | 309 | { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 310 |     double interval = 1.0 / ui_parameters.update_fps; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 311 |     for (;;) { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 312 |         double start = now(); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 313 |         pthread_mutex_lock(&gUpdateMutex); | 
 | 314 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 315 |         int redraw = 0; | 
 | 316 |  | 
 | 317 |         // update the installation animation, if active | 
 | 318 |         // skip this if we have a text overlay (too expensive to update) | 
 | 319 |         if (gCurrentIcon == BACKGROUND_ICON_INSTALLING && | 
 | 320 |             ui_parameters.installing_frames > 0 && | 
 | 321 |             !show_text) { | 
 | 322 |             gInstallingFrame = | 
 | 323 |                 (gInstallingFrame + 1) % ui_parameters.installing_frames; | 
 | 324 |             redraw = 1; | 
 | 325 |         } | 
 | 326 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 327 |         // update the progress bar animation, if active | 
 | 328 |         // skip this if we have a text overlay (too expensive to update) | 
 | 329 |         if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE && !show_text) { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 330 |             redraw = 1; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 331 |         } | 
 | 332 |  | 
 | 333 |         // move the progress bar forward on timed intervals, if configured | 
 | 334 |         int duration = gProgressScopeDuration; | 
 | 335 |         if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && duration > 0) { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 336 |             double elapsed = now() - gProgressScopeTime; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 337 |             float progress = 1.0 * elapsed / duration; | 
 | 338 |             if (progress > 1.0) progress = 1.0; | 
 | 339 |             if (progress > gProgress) { | 
 | 340 |                 gProgress = progress; | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 341 |                 redraw = 1; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 342 |             } | 
 | 343 |         } | 
 | 344 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 345 |         if (redraw) update_progress_locked(); | 
 | 346 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 347 |         pthread_mutex_unlock(&gUpdateMutex); | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 348 |         double end = now(); | 
 | 349 |         // minimum of 20ms delay between frames | 
 | 350 |         double delay = interval - (end-start); | 
 | 351 |         if (delay < 0.02) delay = 0.02; | 
 | 352 |         usleep((long)(delay * 1000000)); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 353 |     } | 
 | 354 |     return NULL; | 
 | 355 | } | 
 | 356 |  | 
| Dima Zavin | bc29063 | 2011-08-30 11:59:45 -0700 | [diff] [blame] | 357 | static int rel_sum = 0; | 
 | 358 |  | 
 | 359 | static int input_callback(int fd, short revents, void *data) | 
 | 360 | { | 
 | 361 |     struct input_event ev; | 
 | 362 |     int ret; | 
 | 363 |     int fake_key = 0; | 
 | 364 |  | 
 | 365 |     ret = ev_get_input(fd, revents, &ev); | 
 | 366 |     if (ret) | 
 | 367 |         return -1; | 
 | 368 |  | 
 | 369 |     if (ev.type == EV_SYN) { | 
 | 370 |         return 0; | 
 | 371 |     } else if (ev.type == EV_REL) { | 
 | 372 |         if (ev.code == REL_Y) { | 
 | 373 |             // accumulate the up or down motion reported by | 
 | 374 |             // the trackball.  When it exceeds a threshold | 
 | 375 |             // (positive or negative), fake an up/down | 
 | 376 |             // key event. | 
 | 377 |             rel_sum += ev.value; | 
 | 378 |             if (rel_sum > 3) { | 
 | 379 |                 fake_key = 1; | 
 | 380 |                 ev.type = EV_KEY; | 
 | 381 |                 ev.code = KEY_DOWN; | 
 | 382 |                 ev.value = 1; | 
 | 383 |                 rel_sum = 0; | 
 | 384 |             } else if (rel_sum < -3) { | 
 | 385 |                 fake_key = 1; | 
 | 386 |                 ev.type = EV_KEY; | 
 | 387 |                 ev.code = KEY_UP; | 
 | 388 |                 ev.value = 1; | 
 | 389 |                 rel_sum = 0; | 
 | 390 |             } | 
 | 391 |         } | 
 | 392 |     } else { | 
 | 393 |         rel_sum = 0; | 
 | 394 |     } | 
 | 395 |  | 
 | 396 |     if (ev.type != EV_KEY || ev.code > KEY_MAX) | 
 | 397 |         return 0; | 
 | 398 |  | 
 | 399 |     pthread_mutex_lock(&key_queue_mutex); | 
 | 400 |     if (!fake_key) { | 
 | 401 |         // our "fake" keys only report a key-down event (no | 
 | 402 |         // key-up), so don't record them in the key_pressed | 
 | 403 |         // table. | 
 | 404 |         key_pressed[ev.code] = ev.value; | 
 | 405 |     } | 
 | 406 |     const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]); | 
 | 407 |     if (ev.value > 0 && key_queue_len < queue_max) { | 
 | 408 |         key_queue[key_queue_len++] = ev.code; | 
 | 409 |         pthread_cond_signal(&key_queue_cond); | 
 | 410 |     } | 
 | 411 |     pthread_mutex_unlock(&key_queue_mutex); | 
 | 412 |  | 
 | 413 |     if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) { | 
 | 414 |         pthread_mutex_lock(&gUpdateMutex); | 
 | 415 |         show_text = !show_text; | 
 | 416 |         if (show_text) show_text_ever = 1; | 
 | 417 |         update_screen_locked(); | 
 | 418 |         pthread_mutex_unlock(&gUpdateMutex); | 
 | 419 |     } | 
 | 420 |  | 
 | 421 |     if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) { | 
 | 422 |         android_reboot(ANDROID_RB_RESTART, 0, 0); | 
 | 423 |     } | 
 | 424 |  | 
 | 425 |     return 0; | 
 | 426 | } | 
 | 427 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 428 | // Reads input events, handles special hot keys, and adds to the key queue. | 
 | 429 | static void *input_thread(void *cookie) | 
 | 430 | { | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 431 |     for (;;) { | 
| Dima Zavin | bc29063 | 2011-08-30 11:59:45 -0700 | [diff] [blame] | 432 |         if (!ev_wait(-1)) | 
 | 433 |             ev_dispatch(); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 434 |     } | 
 | 435 |     return NULL; | 
 | 436 | } | 
 | 437 |  | 
 | 438 | void ui_init(void) | 
 | 439 | { | 
| Koushik Dutta | d3cc60b | 2010-07-03 13:56:45 -0700 | [diff] [blame] | 440 |     ui_has_initialized = 1; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 441 |     gr_init(); | 
| Dima Zavin | bc29063 | 2011-08-30 11:59:45 -0700 | [diff] [blame] | 442 |     ev_init(input_callback, NULL); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 443 |  | 
 | 444 |     text_col = text_row = 0; | 
 | 445 |     text_rows = gr_fb_height() / CHAR_HEIGHT; | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 446 |     max_menu_rows = text_rows - MIN_LOG_ROWS; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 447 |     if (text_rows > MAX_ROWS) text_rows = MAX_ROWS; | 
 | 448 |     text_top = 1; | 
 | 449 |  | 
 | 450 |     text_cols = gr_fb_width() / CHAR_WIDTH; | 
 | 451 |     if (text_cols > MAX_COLS - 1) text_cols = MAX_COLS - 1; | 
 | 452 |  | 
 | 453 |     int i; | 
 | 454 |     for (i = 0; BITMAPS[i].name != NULL; ++i) { | 
 | 455 |         int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface); | 
 | 456 |         if (result < 0) { | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 457 |             LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 458 |         } | 
 | 459 |     } | 
 | 460 |  | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 461 |     gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames * | 
 | 462 |                                        sizeof(gr_surface)); | 
 | 463 |     for (i = 0; i < ui_parameters.indeterminate_frames; ++i) { | 
 | 464 |         char filename[40]; | 
| Doug Zongker | be6d4d1 | 2011-03-02 10:38:02 -0800 | [diff] [blame] | 465 |         // "indeterminate01.png", "indeterminate02.png", ... | 
 | 466 |         sprintf(filename, "indeterminate%02d", i+1); | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 467 |         int result = res_create_surface(filename, gProgressBarIndeterminate+i); | 
 | 468 |         if (result < 0) { | 
 | 469 |             LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); | 
 | 470 |         } | 
 | 471 |     } | 
 | 472 |  | 
 | 473 |     if (ui_parameters.installing_frames > 0) { | 
 | 474 |         gInstallationOverlay = malloc(ui_parameters.installing_frames * | 
 | 475 |                                       sizeof(gr_surface)); | 
 | 476 |         for (i = 0; i < ui_parameters.installing_frames; ++i) { | 
 | 477 |             char filename[40]; | 
| Doug Zongker | be6d4d1 | 2011-03-02 10:38:02 -0800 | [diff] [blame] | 478 |             // "icon_installing_overlay01.png", | 
 | 479 |             // "icon_installing_overlay02.png", ... | 
 | 480 |             sprintf(filename, "icon_installing_overlay%02d", i+1); | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 481 |             int result = res_create_surface(filename, gInstallationOverlay+i); | 
 | 482 |             if (result < 0) { | 
 | 483 |                 LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); | 
 | 484 |             } | 
 | 485 |         } | 
 | 486 |  | 
 | 487 |         // Adjust the offset to account for the positioning of the | 
 | 488 |         // base image on the screen. | 
 | 489 |         if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) { | 
 | 490 |             gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING]; | 
 | 491 |             ui_parameters.install_overlay_offset_x += | 
 | 492 |                 (gr_fb_width() - gr_get_width(bg)) / 2; | 
 | 493 |             ui_parameters.install_overlay_offset_y += | 
 | 494 |                 (gr_fb_height() - gr_get_height(bg)) / 2; | 
 | 495 |         } | 
 | 496 |     } else { | 
 | 497 |         gInstallationOverlay = NULL; | 
 | 498 |     } | 
 | 499 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 500 |     pthread_t t; | 
 | 501 |     pthread_create(&t, NULL, progress_thread, NULL); | 
 | 502 |     pthread_create(&t, NULL, input_thread, NULL); | 
 | 503 | } | 
 | 504 |  | 
| Koushik Dutta | 107629b | 2010-06-30 23:17:53 -0700 | [diff] [blame] | 505 | char *ui_copy_image(int icon, int *width, int *height, int *bpp) { | 
 | 506 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 507 |     draw_background_locked(gBackgroundIcon[icon]); | 
 | 508 |     *width = gr_fb_width(); | 
 | 509 |     *height = gr_fb_height(); | 
 | 510 |     *bpp = sizeof(gr_pixel) * 8; | 
 | 511 |     int size = *width * *height * sizeof(gr_pixel); | 
 | 512 |     char *ret = malloc(size); | 
 | 513 |     if (ret == NULL) { | 
 | 514 |         LOGE("Can't allocate %d bytes for image\n", size); | 
 | 515 |     } else { | 
 | 516 |         memcpy(ret, gr_fb_data(), size); | 
 | 517 |     } | 
 | 518 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 519 |     return ret; | 
 | 520 | } | 
 | 521 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 522 | void ui_set_background(int icon) | 
 | 523 | { | 
 | 524 |     pthread_mutex_lock(&gUpdateMutex); | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 525 |     gCurrentIcon = icon; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 526 |     update_screen_locked(); | 
 | 527 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 528 | } | 
 | 529 |  | 
 | 530 | void ui_show_indeterminate_progress() | 
 | 531 | { | 
 | 532 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 533 |     if (gProgressBarType != PROGRESSBAR_TYPE_INDETERMINATE) { | 
 | 534 |         gProgressBarType = PROGRESSBAR_TYPE_INDETERMINATE; | 
 | 535 |         update_progress_locked(); | 
 | 536 |     } | 
 | 537 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 538 | } | 
 | 539 |  | 
 | 540 | void ui_show_progress(float portion, int seconds) | 
 | 541 | { | 
 | 542 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 543 |     gProgressBarType = PROGRESSBAR_TYPE_NORMAL; | 
 | 544 |     gProgressScopeStart += gProgressScopeSize; | 
 | 545 |     gProgressScopeSize = portion; | 
| Doug Zongker | 6809c51 | 2011-03-01 14:04:34 -0800 | [diff] [blame] | 546 |     gProgressScopeTime = now(); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 547 |     gProgressScopeDuration = seconds; | 
 | 548 |     gProgress = 0; | 
 | 549 |     update_progress_locked(); | 
 | 550 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 551 | } | 
 | 552 |  | 
 | 553 | void ui_set_progress(float fraction) | 
 | 554 | { | 
 | 555 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 556 |     if (fraction < 0.0) fraction = 0.0; | 
 | 557 |     if (fraction > 1.0) fraction = 1.0; | 
 | 558 |     if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && fraction > gProgress) { | 
 | 559 |         // Skip updates that aren't visibly different. | 
 | 560 |         int width = gr_get_width(gProgressBarIndeterminate[0]); | 
 | 561 |         float scale = width * gProgressScopeSize; | 
 | 562 |         if ((int) (gProgress * scale) != (int) (fraction * scale)) { | 
 | 563 |             gProgress = fraction; | 
 | 564 |             update_progress_locked(); | 
 | 565 |         } | 
 | 566 |     } | 
 | 567 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 568 | } | 
 | 569 |  | 
 | 570 | void ui_reset_progress() | 
 | 571 | { | 
 | 572 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 573 |     gProgressBarType = PROGRESSBAR_TYPE_NONE; | 
 | 574 |     gProgressScopeStart = gProgressScopeSize = 0; | 
 | 575 |     gProgressScopeTime = gProgressScopeDuration = 0; | 
 | 576 |     gProgress = 0; | 
 | 577 |     update_screen_locked(); | 
 | 578 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 579 | } | 
 | 580 |  | 
 | 581 | void ui_print(const char *fmt, ...) | 
 | 582 | { | 
 | 583 |     char buf[256]; | 
 | 584 |     va_list ap; | 
 | 585 |     va_start(ap, fmt); | 
 | 586 |     vsnprintf(buf, 256, fmt, ap); | 
 | 587 |     va_end(ap); | 
 | 588 |  | 
| Tanguy Pruvot | 67d358c | 2011-06-10 20:26:44 +0200 | [diff] [blame] | 589 |     if (ui_log_stdout) | 
 | 590 |         fputs(buf, stdout); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 591 |  | 
 | 592 |     // This can get called before ui_init(), so be careful. | 
 | 593 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 594 |     if (text_rows > 0 && text_cols > 0) { | 
 | 595 |         char *ptr; | 
 | 596 |         for (ptr = buf; *ptr != '\0'; ++ptr) { | 
 | 597 |             if (*ptr == '\n' || text_col >= text_cols) { | 
 | 598 |                 text[text_row][text_col] = '\0'; | 
 | 599 |                 text_col = 0; | 
 | 600 |                 text_row = (text_row + 1) % text_rows; | 
 | 601 |                 if (text_row == text_top) text_top = (text_top + 1) % text_rows; | 
 | 602 |             } | 
 | 603 |             if (*ptr != '\n') text[text_row][text_col++] = *ptr; | 
 | 604 |         } | 
 | 605 |         text[text_row][text_col] = '\0'; | 
 | 606 |         update_screen_locked(); | 
 | 607 |     } | 
 | 608 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 609 | } | 
 | 610 |  | 
| Tanguy Pruvot | 67d358c | 2011-06-10 20:26:44 +0200 | [diff] [blame] | 611 | void ui_printlogtail(int nb_lines) { | 
 | 612 |     char * log_data; | 
 | 613 |     char tmp[PATH_MAX]; | 
 | 614 |     FILE * f; | 
 | 615 |     int line=0; | 
 | 616 |     //don't log output to recovery.log | 
 | 617 |     ui_log_stdout=0; | 
 | 618 |     sprintf(tmp, "tail -n %d /tmp/recovery.log > /tmp/tail.log", nb_lines); | 
 | 619 |     __system(tmp); | 
 | 620 |     f = fopen("/tmp/tail.log", "rb"); | 
 | 621 |     if (f != NULL) { | 
 | 622 |         while (line < nb_lines) { | 
 | 623 |             log_data = fgets(tmp, PATH_MAX, f); | 
 | 624 |             if (log_data == NULL) break; | 
 | 625 |             ui_print("%s", tmp); | 
 | 626 |             line++; | 
 | 627 |         } | 
 | 628 |         fclose(f); | 
 | 629 |     } | 
 | 630 |     ui_log_stdout=1; | 
 | 631 | } | 
 | 632 |  | 
| Koushik K. Dutta | ee57bbc | 2010-03-12 23:21:12 -0800 | [diff] [blame] | 633 | void ui_reset_text_col() | 
 | 634 | { | 
 | 635 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 636 |     text_col = 0; | 
 | 637 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 638 | } | 
 | 639 |  | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 640 | #define MENU_ITEM_HEADER " - " | 
 | 641 | #define MENU_ITEM_HEADER_LENGTH strlen(MENU_ITEM_HEADER) | 
 | 642 |  | 
| Koushik Dutta | df1e406 | 2010-12-18 17:42:31 -0800 | [diff] [blame] | 643 | int ui_start_menu(char** headers, char** items, int initial_selection) { | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 644 |     int i; | 
 | 645 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 646 |     if (text_rows > 0 && text_cols > 0) { | 
 | 647 |         for (i = 0; i < text_rows; ++i) { | 
 | 648 |             if (headers[i] == NULL) break; | 
 | 649 |             strncpy(menu[i], headers[i], text_cols-1); | 
 | 650 |             menu[i][text_cols-1] = '\0'; | 
 | 651 |         } | 
 | 652 |         menu_top = i; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 653 |         for (; i < MENU_MAX_ROWS; ++i) { | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 654 |             if (items[i-menu_top] == NULL) break; | 
| Koushik K. Dutta | 261dde9 | 2010-02-25 16:51:45 -0800 | [diff] [blame] | 655 |             strcpy(menu[i], MENU_ITEM_HEADER); | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 656 |             strncpy(menu[i] + MENU_ITEM_HEADER_LENGTH, items[i-menu_top], MENU_MAX_COLS - 1 - MENU_ITEM_HEADER_LENGTH); | 
 | 657 |             menu[i][MENU_MAX_COLS-1] = '\0'; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 658 |         } | 
| Koushik Dutta | 4ca9b4c | 2010-07-14 18:37:33 -0700 | [diff] [blame] | 659 |  | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 660 |         if (gShowBackButton && ui_menu_level > 0) { | 
| Koushik Dutta | 4ca9b4c | 2010-07-14 18:37:33 -0700 | [diff] [blame] | 661 |             strcpy(menu[i], " - +++++Go Back+++++"); | 
 | 662 |             ++i; | 
 | 663 |         } | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 664 |          | 
 | 665 |         strcpy(menu[i], " "); | 
 | 666 |         ++i; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 667 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 668 |         menu_items = i - menu_top; | 
 | 669 |         show_menu = 1; | 
| Koushik Dutta | df1e406 | 2010-12-18 17:42:31 -0800 | [diff] [blame] | 670 |         menu_sel = menu_show_start = initial_selection; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 671 |         update_screen_locked(); | 
 | 672 |     } | 
 | 673 |     pthread_mutex_unlock(&gUpdateMutex); | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 674 |     if (gShowBackButton && ui_menu_level > 0) { | 
| Koushik Dutta | 4ca9b4c | 2010-07-14 18:37:33 -0700 | [diff] [blame] | 675 |         return menu_items - 1; | 
 | 676 |     } | 
| Koushik Dutta | f4e3a67 | 2010-06-09 12:19:41 -0700 | [diff] [blame] | 677 |     return menu_items; | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 678 | } | 
 | 679 |  | 
 | 680 | int ui_menu_select(int sel) { | 
 | 681 |     int old_sel; | 
 | 682 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 683 |     if (show_menu > 0) { | 
 | 684 |         old_sel = menu_sel; | 
 | 685 |         menu_sel = sel; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 686 |  | 
| CEnnis91 | 4f78176 | 2012-01-14 23:51:58 -0500 | [diff] [blame] | 687 |         if (menu_sel < 0) menu_sel = menu_items-1 + menu_sel; | 
 | 688 |         if (menu_sel >= menu_items-1) menu_sel = menu_sel - menu_items+1; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 689 |  | 
 | 690 |  | 
 | 691 |         if (menu_sel < menu_show_start && menu_show_start > 0) { | 
| Koushik Dutta | 917c38a | 2010-05-24 16:43:39 -0700 | [diff] [blame] | 692 |             menu_show_start = menu_sel; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 693 |         } | 
 | 694 |  | 
| Koushik Dutta | 3cdfd13 | 2012-01-26 22:56:00 -0800 | [diff] [blame] | 695 |         if (menu_sel - menu_show_start + menu_top >= max_menu_rows) { | 
 | 696 |             menu_show_start = menu_sel + menu_top - max_menu_rows + 1; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 697 |         } | 
 | 698 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 699 |         sel = menu_sel; | 
| Magnus Eriksson | 8bbbbd4 | 2010-03-08 16:09:49 +0100 | [diff] [blame] | 700 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 701 |         if (menu_sel != old_sel) update_screen_locked(); | 
 | 702 |     } | 
 | 703 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 704 |     return sel; | 
 | 705 | } | 
 | 706 |  | 
 | 707 | void ui_end_menu() { | 
 | 708 |     int i; | 
 | 709 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 710 |     if (show_menu > 0 && text_rows > 0 && text_cols > 0) { | 
 | 711 |         show_menu = 0; | 
 | 712 |         update_screen_locked(); | 
 | 713 |     } | 
 | 714 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 715 | } | 
 | 716 |  | 
 | 717 | int ui_text_visible() | 
 | 718 | { | 
 | 719 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 720 |     int visible = show_text; | 
 | 721 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 722 |     return visible; | 
 | 723 | } | 
 | 724 |  | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 725 | int ui_text_ever_visible() | 
 | 726 | { | 
 | 727 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 728 |     int ever_visible = show_text_ever; | 
 | 729 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 730 |     return ever_visible; | 
 | 731 | } | 
 | 732 |  | 
| Doug Zongker | 4bc9806 | 2010-09-03 11:00:13 -0700 | [diff] [blame] | 733 | void ui_show_text(int visible) | 
 | 734 | { | 
 | 735 |     pthread_mutex_lock(&gUpdateMutex); | 
 | 736 |     show_text = visible; | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 737 |     if (show_text) show_text_ever = 1; | 
| Doug Zongker | 4bc9806 | 2010-09-03 11:00:13 -0700 | [diff] [blame] | 738 |     update_screen_locked(); | 
 | 739 |     pthread_mutex_unlock(&gUpdateMutex); | 
 | 740 | } | 
 | 741 |  | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 742 | // Return true if USB is connected. | 
 | 743 | static int usb_connected() { | 
| Benoit Goby | 7e6067e | 2011-06-24 17:54:19 -0700 | [diff] [blame] | 744 |     int fd = open("/sys/class/android_usb/android0/state", O_RDONLY); | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 745 |     if (fd < 0) { | 
| Benoit Goby | 7e6067e | 2011-06-24 17:54:19 -0700 | [diff] [blame] | 746 |         printf("failed to open /sys/class/android_usb/android0/state: %s\n", | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 747 |                strerror(errno)); | 
 | 748 |         return 0; | 
 | 749 |     } | 
 | 750 |  | 
 | 751 |     char buf; | 
| Benoit Goby | 7e6067e | 2011-06-24 17:54:19 -0700 | [diff] [blame] | 752 |     /* USB is connected if android_usb state is CONNECTED or CONFIGURED */ | 
 | 753 |     int connected = (read(fd, &buf, 1) == 1) && (buf == 'C'); | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 754 |     if (close(fd) < 0) { | 
| Benoit Goby | 7e6067e | 2011-06-24 17:54:19 -0700 | [diff] [blame] | 755 |         printf("failed to close /sys/class/android_usb/android0/state: %s\n", | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 756 |                strerror(errno)); | 
 | 757 |     } | 
 | 758 |     return connected; | 
 | 759 | } | 
 | 760 |  | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 761 | int ui_wait_key() | 
 | 762 | { | 
 | 763 |     pthread_mutex_lock(&key_queue_mutex); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 764 |  | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 765 |     // Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is | 
 | 766 |     // plugged in. | 
 | 767 |     do { | 
 | 768 |         struct timeval now; | 
 | 769 |         struct timespec timeout; | 
 | 770 |         gettimeofday(&now, NULL); | 
 | 771 |         timeout.tv_sec = now.tv_sec; | 
 | 772 |         timeout.tv_nsec = now.tv_usec * 1000; | 
 | 773 |         timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 774 |  | 
| Doug Zongker | 6ce4a32 | 2011-03-08 12:25:05 -0800 | [diff] [blame] | 775 |         int rc = 0; | 
 | 776 |         while (key_queue_len == 0 && rc != ETIMEDOUT) { | 
 | 777 |             rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, | 
 | 778 |                                         &timeout); | 
 | 779 |         } | 
 | 780 |     } while (usb_connected() && key_queue_len == 0); | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 781 |  | 
| Doug Zongker | 5cae445 | 2011-01-25 13:15:30 -0800 | [diff] [blame] | 782 |     int key = -1; | 
 | 783 |     if (key_queue_len > 0) { | 
 | 784 |         key = key_queue[0]; | 
 | 785 |         memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len); | 
 | 786 |     } | 
| The Android Open Source Project | c24a8e6 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 787 |     pthread_mutex_unlock(&key_queue_mutex); | 
 | 788 |     return key; | 
 | 789 | } | 
 | 790 |  | 
 | 791 | int ui_key_pressed(int key) | 
 | 792 | { | 
 | 793 |     // This is a volatile static array, don't bother locking | 
 | 794 |     return key_pressed[key]; | 
 | 795 | } | 
 | 796 |  | 
 | 797 | void ui_clear_key_queue() { | 
 | 798 |     pthread_mutex_lock(&key_queue_mutex); | 
 | 799 |     key_queue_len = 0; | 
 | 800 |     pthread_mutex_unlock(&key_queue_mutex); | 
 | 801 | } | 
| Koushik K. Dutta | a3c2f73 | 2010-02-19 14:17:22 -0800 | [diff] [blame] | 802 |  | 
| Koushik K. Dutta | 0317378 | 2010-02-26 14:14:23 -0800 | [diff] [blame] | 803 | void ui_set_show_text(int value) { | 
 | 804 |     show_text = value; | 
| Koushik K. Dutta | a3c2f73 | 2010-02-19 14:17:22 -0800 | [diff] [blame] | 805 | } | 
| Koushik Dutta | 4ca9b4c | 2010-07-14 18:37:33 -0700 | [diff] [blame] | 806 |  | 
 | 807 | void ui_set_showing_back_button(int showBackButton) { | 
 | 808 |     gShowBackButton = showBackButton; | 
 | 809 | } | 
 | 810 |  | 
 | 811 | int ui_get_showing_back_button() { | 
 | 812 |     return gShowBackButton; | 
 | 813 | } |