diff options
Diffstat (limited to 'wear_ui.cpp')
-rw-r--r-- | wear_ui.cpp | 503 |
1 files changed, 247 insertions, 256 deletions
diff --git a/wear_ui.cpp b/wear_ui.cpp index 6c028655..adc316df 100644 --- a/wear_ui.cpp +++ b/wear_ui.cpp | |||
@@ -45,167 +45,158 @@ static WearRecoveryUI* self = NULL; | |||
45 | 45 | ||
46 | // Return the current time as a double (including fractions of a second). | 46 | // Return the current time as a double (including fractions of a second). |
47 | static double now() { | 47 | static double now() { |
48 | struct timeval tv; | 48 | struct timeval tv; |
49 | gettimeofday(&tv, NULL); | 49 | gettimeofday(&tv, NULL); |
50 | return tv.tv_sec + tv.tv_usec / 1000000.0; | 50 | return tv.tv_sec + tv.tv_usec / 1000000.0; |
51 | } | 51 | } |
52 | 52 | ||
53 | WearRecoveryUI::WearRecoveryUI() : | 53 | WearRecoveryUI::WearRecoveryUI() |
54 | progress_bar_y(259), | 54 | : progress_bar_y(259), outer_height(0), outer_width(0), menu_unusable_rows(0) { |
55 | outer_height(0), | 55 | intro_frames = 22; |
56 | outer_width(0), | 56 | loop_frames = 60; |
57 | menu_unusable_rows(0) { | 57 | animation_fps = 30; |
58 | intro_frames = 22; | ||
59 | loop_frames = 60; | ||
60 | animation_fps = 30; | ||
61 | 58 | ||
62 | for (size_t i = 0; i < 5; i++) | 59 | for (size_t i = 0; i < 5; i++) backgroundIcon[i] = NULL; |
63 | backgroundIcon[i] = NULL; | ||
64 | 60 | ||
65 | self = this; | 61 | self = this; |
66 | } | 62 | } |
67 | 63 | ||
68 | int WearRecoveryUI::GetProgressBaseline() { | 64 | int WearRecoveryUI::GetProgressBaseline() { |
69 | return progress_bar_y; | 65 | return progress_bar_y; |
70 | } | 66 | } |
71 | 67 | ||
72 | // Draw background frame on the screen. Does not flip pages. | 68 | // Draw background frame on the screen. Does not flip pages. |
73 | // Should only be called with updateMutex locked. | 69 | // Should only be called with updateMutex locked. |
74 | // TODO merge drawing routines with screen_ui | 70 | // TODO merge drawing routines with screen_ui |
75 | void WearRecoveryUI::draw_background_locked() | 71 | void WearRecoveryUI::draw_background_locked() { |
76 | { | 72 | pagesIdentical = false; |
77 | pagesIdentical = false; | 73 | gr_color(0, 0, 0, 255); |
78 | gr_color(0, 0, 0, 255); | 74 | gr_fill(0, 0, gr_fb_width(), gr_fb_height()); |
79 | gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | 75 | |
80 | 76 | if (currentIcon != NONE) { | |
81 | if (currentIcon != NONE) { | 77 | GRSurface* surface; |
82 | GRSurface* surface; | 78 | if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { |
83 | if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { | 79 | if (!intro_done) { |
84 | if (!intro_done) { | 80 | surface = introFrames[current_frame]; |
85 | surface = introFrames[current_frame]; | 81 | } else { |
86 | } else { | 82 | surface = loopFrames[current_frame]; |
87 | surface = loopFrames[current_frame]; | 83 | } |
88 | } | 84 | } else { |
89 | } | 85 | surface = backgroundIcon[currentIcon]; |
90 | else { | 86 | } |
91 | surface = backgroundIcon[currentIcon]; | ||
92 | } | ||
93 | 87 | ||
94 | int width = gr_get_width(surface); | 88 | int width = gr_get_width(surface); |
95 | int height = gr_get_height(surface); | 89 | int height = gr_get_height(surface); |
96 | 90 | ||
97 | int x = (gr_fb_width() - width) / 2; | 91 | int x = (gr_fb_width() - width) / 2; |
98 | int y = (gr_fb_height() - height) / 2; | 92 | int y = (gr_fb_height() - height) / 2; |
99 | 93 | ||
100 | gr_blit(surface, 0, 0, width, height, x, y); | 94 | gr_blit(surface, 0, 0, width, height, x, y); |
101 | } | 95 | } |
102 | } | 96 | } |
103 | 97 | ||
104 | static const char* HEADERS[] = { | 98 | static const char* HEADERS[] = { |
105 | "Swipe up/down to move.", | 99 | "Swipe up/down to move.", |
106 | "Swipe left/right to select.", | 100 | "Swipe left/right to select.", |
107 | "", | 101 | "", |
108 | NULL | 102 | NULL |
109 | }; | 103 | }; |
110 | 104 | ||
111 | // TODO merge drawing routines with screen_ui | 105 | // TODO merge drawing routines with screen_ui |
112 | void WearRecoveryUI::draw_screen_locked() | 106 | void WearRecoveryUI::draw_screen_locked() { |
113 | { | 107 | char cur_selection_str[50]; |
114 | char cur_selection_str[50]; | 108 | |
109 | draw_background_locked(); | ||
110 | if (!show_text) { | ||
111 | draw_foreground_locked(); | ||
112 | } else { | ||
113 | SetColor(TEXT_FILL); | ||
114 | gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | ||
115 | 115 | ||
116 | draw_background_locked(); | 116 | int y = outer_height; |
117 | if (!show_text) { | 117 | int x = outer_width; |
118 | draw_foreground_locked(); | 118 | if (show_menu) { |
119 | } else { | 119 | std::string recovery_fingerprint = |
120 | SetColor(TEXT_FILL); | 120 | android::base::GetProperty("ro.bootimage.build.fingerprint", ""); |
121 | gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | 121 | SetColor(HEADER); |
122 | 122 | DrawTextLine(x + 4, &y, "Android Recovery", true); | |
123 | int y = outer_height; | 123 | for (auto& chunk : android::base::Split(recovery_fingerprint, ":")) { |
124 | int x = outer_width; | 124 | DrawTextLine(x + 4, &y, chunk.c_str(), false); |
125 | if (show_menu) { | 125 | } |
126 | std::string recovery_fingerprint = | ||
127 | android::base::GetProperty("ro.bootimage.build.fingerprint", ""); | ||
128 | SetColor(HEADER); | ||
129 | DrawTextLine(x + 4, &y, "Android Recovery", true); | ||
130 | for (auto& chunk: android::base::Split(recovery_fingerprint, ":")) { | ||
131 | DrawTextLine(x +4, &y, chunk.c_str(), false); | ||
132 | } | ||
133 | |||
134 | // This is actually the help strings. | ||
135 | DrawTextLines(x + 4, &y, HEADERS); | ||
136 | SetColor(HEADER); | ||
137 | DrawTextLines(x + 4, &y, menu_headers_); | ||
138 | |||
139 | // Show the current menu item number in relation to total number if | ||
140 | // items don't fit on the screen. | ||
141 | if (menu_items > menu_end - menu_start) { | ||
142 | sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items); | ||
143 | gr_text(gr_sys_font(), x+4, y, cur_selection_str, 1); | ||
144 | y += char_height_+4; | ||
145 | } | ||
146 | |||
147 | // Menu begins here | ||
148 | SetColor(MENU); | ||
149 | |||
150 | for (int i = menu_start; i < menu_end; ++i) { | ||
151 | |||
152 | if (i == menu_sel) { | ||
153 | // draw the highlight bar | ||
154 | SetColor(MENU_SEL_BG); | ||
155 | gr_fill(x, y-2, gr_fb_width()-x, y+char_height_+2); | ||
156 | // white text of selected item | ||
157 | SetColor(MENU_SEL_FG); | ||
158 | if (menu_[i][0]) { | ||
159 | gr_text(gr_sys_font(), x + 4, y, menu_[i], 1); | ||
160 | } | ||
161 | SetColor(MENU); | ||
162 | } else if (menu_[i][0]) { | ||
163 | gr_text(gr_sys_font(), x + 4, y, menu_[i], 0); | ||
164 | } | ||
165 | y += char_height_+4; | ||
166 | } | ||
167 | SetColor(MENU); | ||
168 | y += 4; | ||
169 | gr_fill(0, y, gr_fb_width(), y+2); | ||
170 | y += 4; | ||
171 | } | ||
172 | 126 | ||
173 | SetColor(LOG); | 127 | // This is actually the help strings. |
174 | 128 | DrawTextLines(x + 4, &y, HEADERS); | |
175 | // display from the bottom up, until we hit the top of the | 129 | SetColor(HEADER); |
176 | // screen, the bottom of the menu, or we've displayed the | 130 | DrawTextLines(x + 4, &y, menu_headers_); |
177 | // entire text buffer. | 131 | |
178 | int ty; | 132 | // Show the current menu item number in relation to total number if |
179 | int row = (text_top_ + text_rows_ - 1) % text_rows_; | 133 | // items don't fit on the screen. |
180 | size_t count = 0; | 134 | if (menu_items > menu_end - menu_start) { |
181 | for (int ty = gr_fb_height() - char_height_ - outer_height; | 135 | sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items); |
182 | ty > y + 2 && count < text_rows_; | 136 | gr_text(gr_sys_font(), x + 4, y, cur_selection_str, 1); |
183 | ty -= char_height_, ++count) { | 137 | y += char_height_ + 4; |
184 | gr_text(gr_sys_font(), x+4, ty, text_[row], 0); | 138 | } |
185 | --row; | 139 | |
186 | if (row < 0) row = text_rows_ - 1; | 140 | // Menu begins here |
141 | SetColor(MENU); | ||
142 | |||
143 | for (int i = menu_start; i < menu_end; ++i) { | ||
144 | if (i == menu_sel) { | ||
145 | // draw the highlight bar | ||
146 | SetColor(MENU_SEL_BG); | ||
147 | gr_fill(x, y - 2, gr_fb_width() - x, y + char_height_ + 2); | ||
148 | // white text of selected item | ||
149 | SetColor(MENU_SEL_FG); | ||
150 | if (menu_[i][0]) { | ||
151 | gr_text(gr_sys_font(), x + 4, y, menu_[i], 1); | ||
152 | } | ||
153 | SetColor(MENU); | ||
154 | } else if (menu_[i][0]) { | ||
155 | gr_text(gr_sys_font(), x + 4, y, menu_[i], 0); | ||
187 | } | 156 | } |
157 | y += char_height_ + 4; | ||
158 | } | ||
159 | SetColor(MENU); | ||
160 | y += 4; | ||
161 | gr_fill(0, y, gr_fb_width(), y + 2); | ||
162 | y += 4; | ||
163 | } | ||
164 | |||
165 | SetColor(LOG); | ||
166 | |||
167 | // display from the bottom up, until we hit the top of the | ||
168 | // screen, the bottom of the menu, or we've displayed the | ||
169 | // entire text buffer. | ||
170 | int ty; | ||
171 | int row = (text_top_ + text_rows_ - 1) % text_rows_; | ||
172 | size_t count = 0; | ||
173 | for (int ty = gr_fb_height() - char_height_ - outer_height; ty > y + 2 && count < text_rows_; | ||
174 | ty -= char_height_, ++count) { | ||
175 | gr_text(gr_sys_font(), x + 4, ty, text_[row], 0); | ||
176 | --row; | ||
177 | if (row < 0) row = text_rows_ - 1; | ||
188 | } | 178 | } |
179 | } | ||
189 | } | 180 | } |
190 | 181 | ||
191 | // TODO merge drawing routines with screen_ui | 182 | // TODO merge drawing routines with screen_ui |
192 | void WearRecoveryUI::update_progress_locked() { | 183 | void WearRecoveryUI::update_progress_locked() { |
193 | draw_screen_locked(); | 184 | draw_screen_locked(); |
194 | gr_flip(); | 185 | gr_flip(); |
195 | } | 186 | } |
196 | 187 | ||
197 | bool WearRecoveryUI::InitTextParams() { | 188 | bool WearRecoveryUI::InitTextParams() { |
198 | if (!ScreenRecoveryUI::InitTextParams()) { | 189 | if (!ScreenRecoveryUI::InitTextParams()) { |
199 | return false; | 190 | return false; |
200 | } | 191 | } |
201 | 192 | ||
202 | text_cols_ = (gr_fb_width() - (outer_width * 2)) / char_width_; | 193 | text_cols_ = (gr_fb_width() - (outer_width * 2)) / char_width_; |
203 | 194 | ||
204 | if (text_rows_ > kMaxRows) text_rows_ = kMaxRows; | 195 | if (text_rows_ > kMaxRows) text_rows_ = kMaxRows; |
205 | if (text_cols_ > kMaxCols) text_cols_ = kMaxCols; | 196 | if (text_cols_ > kMaxCols) text_cols_ = kMaxCols; |
206 | 197 | ||
207 | visible_text_rows = (gr_fb_height() - (outer_height * 2)) / char_height_; | 198 | visible_text_rows = (gr_fb_height() - (outer_height * 2)) / char_height_; |
208 | return true; | 199 | return true; |
209 | } | 200 | } |
210 | 201 | ||
211 | bool WearRecoveryUI::Init(const std::string& locale) { | 202 | bool WearRecoveryUI::Init(const std::string& locale) { |
@@ -222,7 +213,8 @@ bool WearRecoveryUI::Init(const std::string& locale) { | |||
222 | return true; | 213 | return true; |
223 | } | 214 | } |
224 | 215 | ||
225 | void WearRecoveryUI::SetStage(int current, int max) {} | 216 | void WearRecoveryUI::SetStage(int current, int max) { |
217 | } | ||
226 | 218 | ||
227 | void WearRecoveryUI::Print(const char* fmt, ...) { | 219 | void WearRecoveryUI::Print(const char* fmt, ...) { |
228 | char buf[256]; | 220 | char buf[256]; |
@@ -252,165 +244,164 @@ void WearRecoveryUI::Print(const char* fmt, ...) { | |||
252 | pthread_mutex_unlock(&updateMutex); | 244 | pthread_mutex_unlock(&updateMutex); |
253 | } | 245 | } |
254 | 246 | ||
255 | void WearRecoveryUI::StartMenu(const char* const * headers, const char* const * items, | 247 | void WearRecoveryUI::StartMenu(const char* const* headers, const char* const* items, |
256 | int initial_selection) { | 248 | int initial_selection) { |
257 | pthread_mutex_lock(&updateMutex); | 249 | pthread_mutex_lock(&updateMutex); |
258 | if (text_rows_ > 0 && text_cols_ > 0) { | 250 | if (text_rows_ > 0 && text_cols_ > 0) { |
259 | menu_headers_ = headers; | 251 | menu_headers_ = headers; |
260 | size_t i = 0; | 252 | size_t i = 0; |
261 | // "i < text_rows_" is removed from the loop termination condition, | 253 | // "i < text_rows_" is removed from the loop termination condition, |
262 | // which is different from the one in ScreenRecoveryUI::StartMenu(). | 254 | // which is different from the one in ScreenRecoveryUI::StartMenu(). |
263 | // Because WearRecoveryUI supports scrollable menu, it's fine to have | 255 | // Because WearRecoveryUI supports scrollable menu, it's fine to have |
264 | // more entries than text_rows_. The menu may be truncated otherwise. | 256 | // more entries than text_rows_. The menu may be truncated otherwise. |
265 | // Bug: 23752519 | 257 | // Bug: 23752519 |
266 | for (; items[i] != nullptr; i++) { | 258 | for (; items[i] != nullptr; i++) { |
267 | strncpy(menu_[i], items[i], text_cols_ - 1); | 259 | strncpy(menu_[i], items[i], text_cols_ - 1); |
268 | menu_[i][text_cols_ - 1] = '\0'; | 260 | menu_[i][text_cols_ - 1] = '\0'; |
269 | } | ||
270 | menu_items = i; | ||
271 | show_menu = true; | ||
272 | menu_sel = initial_selection; | ||
273 | menu_start = 0; | ||
274 | menu_end = visible_text_rows - 1 - menu_unusable_rows; | ||
275 | if (menu_items <= menu_end) | ||
276 | menu_end = menu_items; | ||
277 | update_screen_locked(); | ||
278 | } | 261 | } |
279 | pthread_mutex_unlock(&updateMutex); | 262 | menu_items = i; |
263 | show_menu = true; | ||
264 | menu_sel = initial_selection; | ||
265 | menu_start = 0; | ||
266 | menu_end = visible_text_rows - 1 - menu_unusable_rows; | ||
267 | if (menu_items <= menu_end) menu_end = menu_items; | ||
268 | update_screen_locked(); | ||
269 | } | ||
270 | pthread_mutex_unlock(&updateMutex); | ||
280 | } | 271 | } |
281 | 272 | ||
282 | int WearRecoveryUI::SelectMenu(int sel) { | 273 | int WearRecoveryUI::SelectMenu(int sel) { |
283 | int old_sel; | 274 | int old_sel; |
284 | pthread_mutex_lock(&updateMutex); | 275 | pthread_mutex_lock(&updateMutex); |
285 | if (show_menu) { | 276 | if (show_menu) { |
286 | old_sel = menu_sel; | 277 | old_sel = menu_sel; |
287 | menu_sel = sel; | 278 | menu_sel = sel; |
288 | if (menu_sel < 0) menu_sel = 0; | 279 | if (menu_sel < 0) menu_sel = 0; |
289 | if (menu_sel >= menu_items) menu_sel = menu_items-1; | 280 | if (menu_sel >= menu_items) menu_sel = menu_items - 1; |
290 | if (menu_sel < menu_start) { | 281 | if (menu_sel < menu_start) { |
291 | menu_start--; | 282 | menu_start--; |
292 | menu_end--; | 283 | menu_end--; |
293 | } else if (menu_sel >= menu_end && menu_sel < menu_items) { | 284 | } else if (menu_sel >= menu_end && menu_sel < menu_items) { |
294 | menu_end++; | 285 | menu_end++; |
295 | menu_start++; | 286 | menu_start++; |
296 | } | ||
297 | sel = menu_sel; | ||
298 | if (menu_sel != old_sel) update_screen_locked(); | ||
299 | } | 287 | } |
300 | pthread_mutex_unlock(&updateMutex); | 288 | sel = menu_sel; |
301 | return sel; | 289 | if (menu_sel != old_sel) update_screen_locked(); |
290 | } | ||
291 | pthread_mutex_unlock(&updateMutex); | ||
292 | return sel; | ||
302 | } | 293 | } |
303 | 294 | ||
304 | void WearRecoveryUI::ShowFile(FILE* fp) { | 295 | void WearRecoveryUI::ShowFile(FILE* fp) { |
305 | std::vector<off_t> offsets; | 296 | std::vector<off_t> offsets; |
306 | offsets.push_back(ftello(fp)); | 297 | offsets.push_back(ftello(fp)); |
307 | ClearText(); | 298 | ClearText(); |
308 | 299 | ||
309 | struct stat sb; | 300 | struct stat sb; |
310 | fstat(fileno(fp), &sb); | 301 | fstat(fileno(fp), &sb); |
311 | 302 | ||
312 | bool show_prompt = false; | 303 | bool show_prompt = false; |
313 | while (true) { | 304 | while (true) { |
314 | if (show_prompt) { | 305 | if (show_prompt) { |
315 | Print("--(%d%% of %d bytes)--", | 306 | Print("--(%d%% of %d bytes)--", |
316 | static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))), | 307 | static_cast<int>(100 * (double(ftello(fp)) / double(sb.st_size))), |
317 | static_cast<int>(sb.st_size)); | 308 | static_cast<int>(sb.st_size)); |
318 | Redraw(); | 309 | Redraw(); |
319 | while (show_prompt) { | 310 | while (show_prompt) { |
320 | show_prompt = false; | 311 | show_prompt = false; |
321 | int key = WaitKey(); | 312 | int key = WaitKey(); |
322 | if (key == KEY_POWER || key == KEY_ENTER) { | 313 | if (key == KEY_POWER || key == KEY_ENTER) { |
323 | return; | 314 | return; |
324 | } else if (key == KEY_UP || key == KEY_VOLUMEUP) { | 315 | } else if (key == KEY_UP || key == KEY_VOLUMEUP) { |
325 | if (offsets.size() <= 1) { | 316 | if (offsets.size() <= 1) { |
326 | show_prompt = true; | ||
327 | } else { | ||
328 | offsets.pop_back(); | ||
329 | fseek(fp, offsets.back(), SEEK_SET); | ||
330 | } | ||
331 | } else { | ||
332 | if (feof(fp)) { | ||
333 | return; | ||
334 | } | ||
335 | offsets.push_back(ftello(fp)); | ||
336 | } | ||
337 | } | ||
338 | ClearText(); | ||
339 | } | ||
340 | |||
341 | int ch = getc(fp); | ||
342 | if (ch == EOF) { | ||
343 | text_row_ = text_top_ = text_rows_ - 2; | ||
344 | show_prompt = true; | 317 | show_prompt = true; |
318 | } else { | ||
319 | offsets.pop_back(); | ||
320 | fseek(fp, offsets.back(), SEEK_SET); | ||
321 | } | ||
345 | } else { | 322 | } else { |
346 | PutChar(ch); | 323 | if (feof(fp)) { |
347 | if (text_col_ == 0 && text_row_ >= text_rows_ - 2) { | 324 | return; |
348 | text_top_ = text_row_; | 325 | } |
349 | show_prompt = true; | 326 | offsets.push_back(ftello(fp)); |
350 | } | ||
351 | } | 327 | } |
328 | } | ||
329 | ClearText(); | ||
330 | } | ||
331 | |||
332 | int ch = getc(fp); | ||
333 | if (ch == EOF) { | ||
334 | text_row_ = text_top_ = text_rows_ - 2; | ||
335 | show_prompt = true; | ||
336 | } else { | ||
337 | PutChar(ch); | ||
338 | if (text_col_ == 0 && text_row_ >= text_rows_ - 2) { | ||
339 | text_top_ = text_row_; | ||
340 | show_prompt = true; | ||
341 | } | ||
352 | } | 342 | } |
343 | } | ||
353 | } | 344 | } |
354 | 345 | ||
355 | void WearRecoveryUI::PutChar(char ch) { | 346 | void WearRecoveryUI::PutChar(char ch) { |
356 | pthread_mutex_lock(&updateMutex); | 347 | pthread_mutex_lock(&updateMutex); |
357 | if (ch != '\n') text_[text_row_][text_col_++] = ch; | 348 | if (ch != '\n') text_[text_row_][text_col_++] = ch; |
358 | if (ch == '\n' || text_col_ >= text_cols_) { | 349 | if (ch == '\n' || text_col_ >= text_cols_) { |
359 | text_col_ = 0; | 350 | text_col_ = 0; |
360 | ++text_row_; | 351 | ++text_row_; |
361 | } | 352 | } |
362 | pthread_mutex_unlock(&updateMutex); | 353 | pthread_mutex_unlock(&updateMutex); |
363 | } | 354 | } |
364 | 355 | ||
365 | void WearRecoveryUI::ShowFile(const char* filename) { | 356 | void WearRecoveryUI::ShowFile(const char* filename) { |
366 | FILE* fp = fopen_path(filename, "re"); | 357 | FILE* fp = fopen_path(filename, "re"); |
367 | if (fp == nullptr) { | 358 | if (fp == nullptr) { |
368 | Print(" Unable to open %s: %s\n", filename, strerror(errno)); | 359 | Print(" Unable to open %s: %s\n", filename, strerror(errno)); |
369 | return; | 360 | return; |
370 | } | 361 | } |
371 | ShowFile(fp); | 362 | ShowFile(fp); |
372 | fclose(fp); | 363 | fclose(fp); |
373 | } | 364 | } |
374 | 365 | ||
375 | void WearRecoveryUI::ClearText() { | 366 | void WearRecoveryUI::ClearText() { |
376 | pthread_mutex_lock(&updateMutex); | 367 | pthread_mutex_lock(&updateMutex); |
377 | text_col_ = 0; | 368 | text_col_ = 0; |
378 | text_row_ = 0; | 369 | text_row_ = 0; |
379 | text_top_ = 1; | 370 | text_top_ = 1; |
380 | for (size_t i = 0; i < text_rows_; ++i) { | 371 | for (size_t i = 0; i < text_rows_; ++i) { |
381 | memset(text_[i], 0, text_cols_ + 1); | 372 | memset(text_[i], 0, text_cols_ + 1); |
382 | } | 373 | } |
383 | pthread_mutex_unlock(&updateMutex); | 374 | pthread_mutex_unlock(&updateMutex); |
384 | } | 375 | } |
385 | 376 | ||
386 | void WearRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) { | 377 | void WearRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) { |
387 | va_list ap; | 378 | va_list ap; |
388 | va_start(ap, fmt); | 379 | va_start(ap, fmt); |
389 | PrintV(fmt, false, ap); | 380 | PrintV(fmt, false, ap); |
390 | va_end(ap); | 381 | va_end(ap); |
391 | } | 382 | } |
392 | 383 | ||
393 | void WearRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) { | 384 | void WearRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) { |
394 | std::string str; | 385 | std::string str; |
395 | android::base::StringAppendV(&str, fmt, ap); | 386 | android::base::StringAppendV(&str, fmt, ap); |
396 | 387 | ||
397 | if (copy_to_stdout) { | 388 | if (copy_to_stdout) { |
398 | fputs(str.c_str(), stdout); | 389 | fputs(str.c_str(), stdout); |
399 | } | 390 | } |
400 | 391 | ||
401 | pthread_mutex_lock(&updateMutex); | 392 | pthread_mutex_lock(&updateMutex); |
402 | if (text_rows_ > 0 && text_cols_ > 0) { | 393 | if (text_rows_ > 0 && text_cols_ > 0) { |
403 | for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) { | 394 | for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) { |
404 | if (*ptr == '\n' || text_col_ >= text_cols_) { | 395 | if (*ptr == '\n' || text_col_ >= text_cols_) { |
405 | text_[text_row_][text_col_] = '\0'; | ||
406 | text_col_ = 0; | ||
407 | text_row_ = (text_row_ + 1) % text_rows_; | ||
408 | if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; | ||
409 | } | ||
410 | if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; | ||
411 | } | ||
412 | text_[text_row_][text_col_] = '\0'; | 396 | text_[text_row_][text_col_] = '\0'; |
413 | update_screen_locked(); | 397 | text_col_ = 0; |
398 | text_row_ = (text_row_ + 1) % text_rows_; | ||
399 | if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_; | ||
400 | } | ||
401 | if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr; | ||
414 | } | 402 | } |
415 | pthread_mutex_unlock(&updateMutex); | 403 | text_[text_row_][text_col_] = '\0'; |
404 | update_screen_locked(); | ||
405 | } | ||
406 | pthread_mutex_unlock(&updateMutex); | ||
416 | } | 407 | } |