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