aboutsummaryrefslogtreecommitdiffstats
path: root/ui.c
diff options
context:
space:
mode:
authorDoug Zongker2011-03-01 16:04:34 -0600
committerDoug Zongker2011-03-01 16:04:34 -0600
commit6809c51f8db86f1ab00a076cf570439d11920d3a (patch)
tree1c00a572803d0c73f7935855681f31969b527151 /ui.c
parentc007b961d7ed28388fca00a779b846b8646a9cf8 (diff)
downloadplatform-bootable-recovery-6809c51f8db86f1ab00a076cf570439d11920d3a.tar.gz
platform-bootable-recovery-6809c51f8db86f1ab00a076cf570439d11920d3a.tar.xz
platform-bootable-recovery-6809c51f8db86f1ab00a076cf570439d11920d3a.zip
make recovery UI images more general; allow for installation animation
Change some of the UI parameters (# of indeterminate progress bar frames, fps, etc.) from #defined constants to variables that can be set by the device-specific recovery_ui code (via a new function). Support overlaying different images on top of the base installation icon to animate it. Make the FPS control more accurate. Change-Id: I9268b389b7ea6b3ed9e0c7eae37baf4272e60edd
Diffstat (limited to 'ui.c')
-rw-r--r--ui.c186
1 files changed, 136 insertions, 50 deletions
diff --git a/ui.c b/ui.c
index 82004f03..054e53f6 100644
--- a/ui.c
+++ b/ui.c
@@ -36,32 +36,32 @@
36#define CHAR_WIDTH 10 36#define CHAR_WIDTH 10
37#define CHAR_HEIGHT 18 37#define CHAR_HEIGHT 18
38 38
39#define PROGRESSBAR_INDETERMINATE_STATES 6
40#define PROGRESSBAR_INDETERMINATE_FPS 15
41
42#define UI_WAIT_KEY_TIMEOUT_SEC 120 39#define UI_WAIT_KEY_TIMEOUT_SEC 120
43 40
41UIParameters ui_parameters = {
42 6, // indeterminate progress bar frames
43 15, // fps
44 0, // installation icon frames (0 == static image)
45 0, 0, // installation icon overlay offset
46};
47
44static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER; 48static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER;
45static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS]; 49static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS];
46static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES]; 50static gr_surface *gInstallationOverlay;
51static gr_surface *gProgressBarIndeterminate;
47static gr_surface gProgressBarEmpty; 52static gr_surface gProgressBarEmpty;
48static gr_surface gProgressBarFill; 53static gr_surface gProgressBarFill;
49 54
50static const struct { gr_surface* surface; const char *name; } BITMAPS[] = { 55static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
51 { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" }, 56 { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" },
52 { &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" }, 57 { &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" },
53 { &gProgressBarIndeterminate[0], "indeterminate1" },
54 { &gProgressBarIndeterminate[1], "indeterminate2" },
55 { &gProgressBarIndeterminate[2], "indeterminate3" },
56 { &gProgressBarIndeterminate[3], "indeterminate4" },
57 { &gProgressBarIndeterminate[4], "indeterminate5" },
58 { &gProgressBarIndeterminate[5], "indeterminate6" },
59 { &gProgressBarEmpty, "progress_empty" }, 58 { &gProgressBarEmpty, "progress_empty" },
60 { &gProgressBarFill, "progress_fill" }, 59 { &gProgressBarFill, "progress_fill" },
61 { NULL, NULL }, 60 { NULL, NULL },
62}; 61};
63 62
64static gr_surface gCurrentIcon = NULL; 63static int gCurrentIcon = 0;
64static int gInstallingFrame = 0;
65 65
66static enum ProgressBarType { 66static enum ProgressBarType {
67 PROGRESSBAR_TYPE_NONE, 67 PROGRESSBAR_TYPE_NONE,
@@ -71,7 +71,7 @@ static enum ProgressBarType {
71 71
72// Progress bar scope of current operation 72// Progress bar scope of current operation
73static float gProgressScopeStart = 0, gProgressScopeSize = 0, gProgress = 0; 73static float gProgressScopeStart = 0, gProgressScopeSize = 0, gProgress = 0;
74static time_t gProgressScopeTime, gProgressScopeDuration; 74static double gProgressScopeTime, gProgressScopeDuration;
75 75
76// Set to 1 when both graphics pages are the same (except for the progress bar) 76// Set to 1 when both graphics pages are the same (except for the progress bar)
77static int gPagesIdentical = 0; 77static int gPagesIdentical = 0;
@@ -93,20 +93,46 @@ static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER;
93static int key_queue[256], key_queue_len = 0; 93static int key_queue[256], key_queue_len = 0;
94static volatile char key_pressed[KEY_MAX + 1]; 94static volatile char key_pressed[KEY_MAX + 1];
95 95
96// Return the current time as a double (including fractions of a second).
97static double now() {
98 struct timeval tv;
99 gettimeofday(&tv, NULL);
100 return tv.tv_sec + tv.tv_usec / 1000000.0;
101}
102
103// Draw the given frame over the installation overlay animation. The
104// background is not cleared or draw with the base icon first; we
105// assume that the frame already contains some other frame of the
106// animation. Does nothing if no overlay animation is defined.
107// Should only be called with gUpdateMutex locked.
108static void draw_install_overlay_locked(int frame) {
109 if (gInstallationOverlay == NULL) return;
110 gr_surface surface = gInstallationOverlay[frame];
111 int iconWidth = gr_get_width(surface);
112 int iconHeight = gr_get_height(surface);
113 gr_blit(surface, 0, 0, iconWidth, iconHeight,
114 ui_parameters.install_overlay_offset_x,
115 ui_parameters.install_overlay_offset_y);
116}
117
96// Clear the screen and draw the currently selected background icon (if any). 118// Clear the screen and draw the currently selected background icon (if any).
97// Should only be called with gUpdateMutex locked. 119// Should only be called with gUpdateMutex locked.
98static void draw_background_locked(gr_surface icon) 120static void draw_background_locked(int icon)
99{ 121{
100 gPagesIdentical = 0; 122 gPagesIdentical = 0;
101 gr_color(0, 0, 0, 255); 123 gr_color(0, 0, 0, 255);
102 gr_fill(0, 0, gr_fb_width(), gr_fb_height()); 124 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
103 125
104 if (icon) { 126 if (icon) {
105 int iconWidth = gr_get_width(icon); 127 gr_surface surface = gBackgroundIcon[icon];
106 int iconHeight = gr_get_height(icon); 128 int iconWidth = gr_get_width(surface);
129 int iconHeight = gr_get_height(surface);
107 int iconX = (gr_fb_width() - iconWidth) / 2; 130 int iconX = (gr_fb_width() - iconWidth) / 2;
108 int iconY = (gr_fb_height() - iconHeight) / 2; 131 int iconY = (gr_fb_height() - iconHeight) / 2;
109 gr_blit(icon, 0, 0, iconWidth, iconHeight, iconX, iconY); 132 gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
133 if (icon == BACKGROUND_ICON_INSTALLING) {
134 draw_install_overlay_locked(gInstallingFrame);
135 }
110 } 136 }
111} 137}
112 138
@@ -114,35 +140,39 @@ static void draw_background_locked(gr_surface icon)
114// Should only be called with gUpdateMutex locked. 140// Should only be called with gUpdateMutex locked.
115static void draw_progress_locked() 141static void draw_progress_locked()
116{ 142{
117 if (gProgressBarType == PROGRESSBAR_TYPE_NONE) return; 143 if (gCurrentIcon == BACKGROUND_ICON_INSTALLING) {
144 draw_install_overlay_locked(gInstallingFrame);
145 }
118 146
119 int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]); 147 if (gProgressBarType != PROGRESSBAR_TYPE_NONE) {
120 int width = gr_get_width(gProgressBarEmpty); 148 int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]);
121 int height = gr_get_height(gProgressBarEmpty); 149 int width = gr_get_width(gProgressBarEmpty);
150 int height = gr_get_height(gProgressBarEmpty);
122 151
123 int dx = (gr_fb_width() - width)/2; 152 int dx = (gr_fb_width() - width)/2;
124 int dy = (3*gr_fb_height() + iconHeight - 2*height)/4; 153 int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
125 154
126 // Erase behind the progress bar (in case this was a progress-only update) 155 // Erase behind the progress bar (in case this was a progress-only update)
127 gr_color(0, 0, 0, 255); 156 gr_color(0, 0, 0, 255);
128 gr_fill(dx, dy, width, height); 157 gr_fill(dx, dy, width, height);
129 158
130 if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) { 159 if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) {
131 float progress = gProgressScopeStart + gProgress * gProgressScopeSize; 160 float progress = gProgressScopeStart + gProgress * gProgressScopeSize;
132 int pos = (int) (progress * width); 161 int pos = (int) (progress * width);
133 162
134 if (pos > 0) { 163 if (pos > 0) {
135 gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy); 164 gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy);
136 } 165 }
137 if (pos < width-1) { 166 if (pos < width-1) {
138 gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy); 167 gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
168 }
139 } 169 }
140 }
141 170
142 if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) { 171 if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
143 static int frame = 0; 172 static int frame = 0;
144 gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy); 173 gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
145 frame = (frame + 1) % PROGRESSBAR_INDETERMINATE_STATES; 174 frame = (frame + 1) % ui_parameters.indeterminate_frames;
175 }
146 } 176 }
147} 177}
148 178
@@ -207,7 +237,7 @@ static void update_progress_locked(void)
207 draw_screen_locked(); // Must redraw the whole screen 237 draw_screen_locked(); // Must redraw the whole screen
208 gPagesIdentical = 1; 238 gPagesIdentical = 1;
209 } else { 239 } else {
210 draw_progress_locked(); // Draw only the progress bar 240 draw_progress_locked(); // Draw only the progress bar and overlays
211 } 241 }
212 gr_flip(); 242 gr_flip();
213} 243}
@@ -215,29 +245,49 @@ static void update_progress_locked(void)
215// Keeps the progress bar updated, even when the process is otherwise busy. 245// Keeps the progress bar updated, even when the process is otherwise busy.
216static void *progress_thread(void *cookie) 246static void *progress_thread(void *cookie)
217{ 247{
248 double interval = 1.0 / ui_parameters.update_fps;
218 for (;;) { 249 for (;;) {
219 usleep(1000000 / PROGRESSBAR_INDETERMINATE_FPS); 250 double start = now();
220 pthread_mutex_lock(&gUpdateMutex); 251 pthread_mutex_lock(&gUpdateMutex);
221 252
253 int redraw = 0;
254
255 // update the installation animation, if active
256 // skip this if we have a text overlay (too expensive to update)
257 if (gCurrentIcon == BACKGROUND_ICON_INSTALLING &&
258 ui_parameters.installing_frames > 0 &&
259 !show_text) {
260 gInstallingFrame =
261 (gInstallingFrame + 1) % ui_parameters.installing_frames;
262 redraw = 1;
263 }
264
222 // update the progress bar animation, if active 265 // update the progress bar animation, if active
223 // skip this if we have a text overlay (too expensive to update) 266 // skip this if we have a text overlay (too expensive to update)
224 if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE && !show_text) { 267 if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE && !show_text) {
225 update_progress_locked(); 268 redraw = 1;
226 } 269 }
227 270
228 // move the progress bar forward on timed intervals, if configured 271 // move the progress bar forward on timed intervals, if configured
229 int duration = gProgressScopeDuration; 272 int duration = gProgressScopeDuration;
230 if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && duration > 0) { 273 if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && duration > 0) {
231 int elapsed = time(NULL) - gProgressScopeTime; 274 double elapsed = now() - gProgressScopeTime;
232 float progress = 1.0 * elapsed / duration; 275 float progress = 1.0 * elapsed / duration;
233 if (progress > 1.0) progress = 1.0; 276 if (progress > 1.0) progress = 1.0;
234 if (progress > gProgress) { 277 if (progress > gProgress) {
235 gProgress = progress; 278 gProgress = progress;
236 update_progress_locked(); 279 redraw = 1;
237 } 280 }
238 } 281 }
239 282
283 if (redraw) update_progress_locked();
284
240 pthread_mutex_unlock(&gUpdateMutex); 285 pthread_mutex_unlock(&gUpdateMutex);
286 double end = now();
287 // minimum of 20ms delay between frames
288 double delay = interval - (end-start);
289 if (delay < 0.02) delay = 0.02;
290 usleep((long)(delay * 1000000));
241 } 291 }
242 return NULL; 292 return NULL;
243} 293}
@@ -328,13 +378,49 @@ void ui_init(void)
328 for (i = 0; BITMAPS[i].name != NULL; ++i) { 378 for (i = 0; BITMAPS[i].name != NULL; ++i) {
329 int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface); 379 int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface);
330 if (result < 0) { 380 if (result < 0) {
331 if (result == -2) { 381 LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result);
332 LOGI("Bitmap %s missing header\n", BITMAPS[i].name); 382 }
333 } else { 383 }
334 LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result); 384
385 gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames *
386 sizeof(gr_surface));
387 for (i = 0; i < ui_parameters.indeterminate_frames; ++i) {
388 char filename[40];
389 // "indeterminateN" if fewer than 10 frames, else "indeterminateNN".
390 sprintf(filename, "indeterminate%0*d",
391 ui_parameters.indeterminate_frames < 10 ? 1 : 2,
392 i+1);
393 int result = res_create_surface(filename, gProgressBarIndeterminate+i);
394 if (result < 0) {
395 LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
396 }
397 }
398
399 if (ui_parameters.installing_frames > 0) {
400 gInstallationOverlay = malloc(ui_parameters.installing_frames *
401 sizeof(gr_surface));
402 for (i = 0; i < ui_parameters.installing_frames; ++i) {
403 char filename[40];
404 sprintf(filename, "icon_installing_overlay%0*d",
405 ui_parameters.installing_frames < 10 ? 1 : 2,
406 i+1);
407 int result = res_create_surface(filename, gInstallationOverlay+i);
408 if (result < 0) {
409 LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
335 } 410 }
336 *BITMAPS[i].surface = NULL;
337 } 411 }
412
413 // Adjust the offset to account for the positioning of the
414 // base image on the screen.
415 if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) {
416 gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING];
417 ui_parameters.install_overlay_offset_x +=
418 (gr_fb_width() - gr_get_width(bg)) / 2;
419 ui_parameters.install_overlay_offset_y +=
420 (gr_fb_height() - gr_get_height(bg)) / 2;
421 }
422 } else {
423 gInstallationOverlay = NULL;
338 } 424 }
339 425
340 pthread_t t; 426 pthread_t t;
@@ -345,7 +431,7 @@ void ui_init(void)
345void ui_set_background(int icon) 431void ui_set_background(int icon)
346{ 432{
347 pthread_mutex_lock(&gUpdateMutex); 433 pthread_mutex_lock(&gUpdateMutex);
348 gCurrentIcon = gBackgroundIcon[icon]; 434 gCurrentIcon = icon;
349 update_screen_locked(); 435 update_screen_locked();
350 pthread_mutex_unlock(&gUpdateMutex); 436 pthread_mutex_unlock(&gUpdateMutex);
351} 437}
@@ -366,7 +452,7 @@ void ui_show_progress(float portion, int seconds)
366 gProgressBarType = PROGRESSBAR_TYPE_NORMAL; 452 gProgressBarType = PROGRESSBAR_TYPE_NORMAL;
367 gProgressScopeStart += gProgressScopeSize; 453 gProgressScopeStart += gProgressScopeSize;
368 gProgressScopeSize = portion; 454 gProgressScopeSize = portion;
369 gProgressScopeTime = time(NULL); 455 gProgressScopeTime = now();
370 gProgressScopeDuration = seconds; 456 gProgressScopeDuration = seconds;
371 gProgress = 0; 457 gProgress = 0;
372 update_progress_locked(); 458 update_progress_locked();