diff options
author | Dima Zavin | 2011-09-22 17:49:04 -0500 |
---|---|---|
committer | Dima Zavin | 2011-09-25 23:20:55 -0500 |
commit | 0052abdafd7179fc4a7458f09d2f95c74dda0021 (patch) | |
tree | 9e61cb4db1dd52d18c0ebd3604c6710b00d65e5f /charger/charger.c | |
parent | 29656d34a21f4bc3899264027664c9321b0b94e0 (diff) | |
download | platform-system-core-0052abdafd7179fc4a7458f09d2f95c74dda0021.tar.gz platform-system-core-0052abdafd7179fc4a7458f09d2f95c74dda0021.tar.xz platform-system-core-0052abdafd7179fc4a7458f09d2f95c74dda0021.zip |
charger: update charger UI with official graphics and animation
Change-Id: I1b36fa9e380797fe01812b57ac5d8c2c38857993
Signed-off-by: Dima Zavin <dima@android.com>
Diffstat (limited to 'charger/charger.c')
-rw-r--r-- | charger/charger.c | 283 |
1 files changed, 222 insertions, 61 deletions
diff --git a/charger/charger.c b/charger/charger.c index 9320e8a55..a6f8509da 100644 --- a/charger/charger.c +++ b/charger/charger.c | |||
@@ -49,10 +49,12 @@ | |||
49 | #define min(a,b) ((a) < (b) ? (a) : (b)) | 49 | #define min(a,b) ((a) < (b) ? (a) : (b)) |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | ||
53 | |||
52 | #define MSEC_PER_SEC (1000LL) | 54 | #define MSEC_PER_SEC (1000LL) |
53 | #define NSEC_PER_MSEC (1000000LL) | 55 | #define NSEC_PER_MSEC (1000000LL) |
54 | 56 | ||
55 | #define SCREEN_ON_TIME (5 * MSEC_PER_SEC) | 57 | #define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC) |
56 | #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC) | 58 | #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC) |
57 | #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC) | 59 | #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC) |
58 | 60 | ||
@@ -72,22 +74,46 @@ struct power_supply { | |||
72 | char type[32]; | 74 | char type[32]; |
73 | bool online; | 75 | bool online; |
74 | bool valid; | 76 | bool valid; |
77 | char cap_path[PATH_MAX]; | ||
78 | }; | ||
79 | |||
80 | struct frame { | ||
81 | const char *name; | ||
82 | int disp_time; | ||
83 | int min_capacity; | ||
84 | |||
85 | gr_surface surface; | ||
86 | }; | ||
87 | |||
88 | struct animation { | ||
89 | bool run; | ||
90 | |||
91 | struct frame *frames; | ||
92 | int cur_frame; | ||
93 | int num_frames; | ||
94 | |||
95 | int cur_cycle; | ||
96 | int num_cycles; | ||
97 | |||
98 | /* current capacity being animated */ | ||
99 | int capacity; | ||
75 | }; | 100 | }; |
76 | 101 | ||
77 | struct charger { | 102 | struct charger { |
78 | int64_t next_screen_transition; | 103 | int64_t next_screen_transition; |
79 | int64_t next_key_check; | 104 | int64_t next_key_check; |
80 | int64_t next_pwr_check; | 105 | int64_t next_pwr_check; |
81 | bool screen_on; | ||
82 | 106 | ||
83 | struct key_state keys[KEY_MAX + 1]; | 107 | struct key_state keys[KEY_MAX + 1]; |
84 | gr_surface surf_charging; | ||
85 | int uevent_fd; | 108 | int uevent_fd; |
86 | 109 | ||
87 | struct listnode supplies; | 110 | struct listnode supplies; |
88 | int num_supplies; | 111 | int num_supplies; |
89 | int num_supplies_online; | 112 | int num_supplies_online; |
90 | 113 | ||
114 | struct animation *batt_anim; | ||
115 | gr_surface surf_unknown; | ||
116 | |||
91 | struct power_supply *battery; | 117 | struct power_supply *battery; |
92 | }; | 118 | }; |
93 | 119 | ||
@@ -100,11 +126,47 @@ struct uevent { | |||
100 | const char *ps_online; | 126 | const char *ps_online; |
101 | }; | 127 | }; |
102 | 128 | ||
129 | static struct frame batt_anim_frames[] = { | ||
130 | { | ||
131 | .name = "charger/battery_0", | ||
132 | .disp_time = 750, | ||
133 | .min_capacity = 0, | ||
134 | }, | ||
135 | { | ||
136 | .name = "charger/battery_1", | ||
137 | .disp_time = 750, | ||
138 | .min_capacity = 20, | ||
139 | }, | ||
140 | { | ||
141 | .name = "charger/battery_2", | ||
142 | .disp_time = 750, | ||
143 | .min_capacity = 40, | ||
144 | }, | ||
145 | { | ||
146 | .name = "charger/battery_3", | ||
147 | .disp_time = 750, | ||
148 | .min_capacity = 60, | ||
149 | }, | ||
150 | { | ||
151 | .name = "charger/battery_4", | ||
152 | .disp_time = 750, | ||
153 | .min_capacity = 80, | ||
154 | }, | ||
155 | }; | ||
156 | |||
157 | static struct animation battery_animation = { | ||
158 | .frames = batt_anim_frames, | ||
159 | .num_frames = ARRAY_SIZE(batt_anim_frames), | ||
160 | .num_cycles = 3, | ||
161 | }; | ||
162 | |||
163 | static struct charger charger_state = { | ||
164 | .batt_anim = &battery_animation, | ||
165 | }; | ||
166 | |||
103 | static int char_width; | 167 | static int char_width; |
104 | static int char_height; | 168 | static int char_height; |
105 | 169 | ||
106 | struct charger charger_state; | ||
107 | |||
108 | /* current time in milliseconds */ | 170 | /* current time in milliseconds */ |
109 | static int64_t curr_time_ms(void) | 171 | static int64_t curr_time_ms(void) |
110 | { | 172 | { |
@@ -185,7 +247,7 @@ static struct power_supply *find_supply(struct charger *charger, | |||
185 | 247 | ||
186 | static struct power_supply *add_supply(struct charger *charger, | 248 | static struct power_supply *add_supply(struct charger *charger, |
187 | const char *name, const char *type, | 249 | const char *name, const char *type, |
188 | bool online) | 250 | const char *path, bool online) |
189 | { | 251 | { |
190 | struct power_supply *supply; | 252 | struct power_supply *supply; |
191 | 253 | ||
@@ -195,6 +257,8 @@ static struct power_supply *add_supply(struct charger *charger, | |||
195 | 257 | ||
196 | strlcpy(supply->name, name, sizeof(supply->name)); | 258 | strlcpy(supply->name, name, sizeof(supply->name)); |
197 | strlcpy(supply->type, type, sizeof(supply->type)); | 259 | strlcpy(supply->type, type, sizeof(supply->type)); |
260 | snprintf(supply->cap_path, sizeof(supply->cap_path), | ||
261 | "/sys/%s/capacity", path); | ||
198 | supply->online = online; | 262 | supply->online = online; |
199 | list_add_tail(&charger->supplies, &supply->list); | 263 | list_add_tail(&charger->supplies, &supply->list); |
200 | charger->num_supplies++; | 264 | charger->num_supplies++; |
@@ -293,7 +357,8 @@ static void process_ps_uevent(struct charger *charger, struct uevent *uevent) | |||
293 | 357 | ||
294 | if (!strcmp(uevent->action, "add")) { | 358 | if (!strcmp(uevent->action, "add")) { |
295 | if (!supply) { | 359 | if (!supply) { |
296 | supply = add_supply(charger, uevent->ps_name, ps_type, online); | 360 | supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path, |
361 | online); | ||
297 | if (!supply) { | 362 | if (!supply) { |
298 | LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name, | 363 | LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name, |
299 | uevent->ps_type, online); | 364 | uevent->ps_type, online); |
@@ -459,74 +524,153 @@ static void android_green(void) | |||
459 | gr_color(0xa4, 0xc6, 0x39, 255); | 524 | gr_color(0xa4, 0xc6, 0x39, 255); |
460 | } | 525 | } |
461 | 526 | ||
462 | static void redraw_screen(struct charger *charger) | 527 | /* returns the last y-offset of where the surface ends */ |
528 | static int draw_surface_centered(struct charger *charger, gr_surface surface) | ||
463 | { | 529 | { |
464 | int surf_height; | 530 | int w; |
465 | int surf_width; | 531 | int h; |
466 | int x; | 532 | int x; |
467 | int y = 0; | 533 | int y; |
468 | int batt_cap; | ||
469 | int ret; | ||
470 | char cap_string[128]; | ||
471 | char cap_path[256]; | ||
472 | 534 | ||
473 | clear_screen(); | 535 | w = gr_get_width(surface); |
536 | h = gr_get_height(surface); | ||
537 | x = (gr_fb_width() - w) / 2 ; | ||
538 | y = (gr_fb_height() - h) / 2 ; | ||
474 | 539 | ||
475 | if (charger->surf_charging) { | 540 | LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); |
476 | surf_width = gr_get_width(charger->surf_charging); | 541 | gr_blit(surface, 0, 0, w, h, x, y); |
477 | surf_height = gr_get_height(charger->surf_charging); | 542 | return y + h; |
478 | x = (gr_fb_width() - surf_width) / 2 ; | 543 | } |
479 | y = (gr_fb_height() - surf_height) / 2 ; | ||
480 | 544 | ||
481 | gr_blit(charger->surf_charging, 0, 0, | 545 | static void draw_unknown(struct charger *charger) |
482 | surf_width, surf_height, | 546 | { |
483 | x, y); | 547 | int y; |
484 | y += surf_height; | 548 | if (charger->surf_unknown) { |
549 | draw_surface_centered(charger, charger->surf_unknown); | ||
485 | } else { | 550 | } else { |
486 | android_green(); | 551 | android_green(); |
487 | y = draw_text("Charging!", -1, -1); | 552 | y = draw_text("Charging!", -1, -1); |
553 | draw_text("?\?/100", -1, y + 25); | ||
488 | } | 554 | } |
555 | } | ||
489 | 556 | ||
490 | cap_string[0] = '\0'; | 557 | static void draw_battery(struct charger *charger) |
491 | if (charger->battery) { | 558 | { |
492 | ret = snprintf(cap_path, sizeof(cap_path), | 559 | struct animation *batt_anim = charger->batt_anim; |
493 | "/sys/class/power_supply/%s/capacity", | 560 | struct frame *frame = &batt_anim->frames[batt_anim->cur_frame]; |
494 | charger->battery->name); | 561 | |
495 | if (ret <= 0) | 562 | if (batt_anim->num_frames != 0) { |
496 | goto done; | 563 | draw_surface_centered(charger, frame->surface); |
497 | ret = read_file_int(cap_path, &batt_cap); | 564 | LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n", |
498 | if (ret >= 0) | 565 | batt_anim->cur_frame, frame->name, frame->min_capacity, |
499 | snprintf(cap_string, sizeof(cap_string), "%d/100", batt_cap); | 566 | frame->disp_time); |
500 | } | 567 | } |
568 | } | ||
501 | 569 | ||
502 | if (cap_string[0] == '\0') | 570 | static void redraw_screen(struct charger *charger) |
503 | snprintf(cap_string, sizeof(cap_string), "?\?/100"); | 571 | { |
572 | struct animation *batt_anim = charger->batt_anim; | ||
504 | 573 | ||
505 | y += 25; | 574 | clear_screen(); |
506 | android_green(); | ||
507 | draw_text(cap_string, -1, y); | ||
508 | 575 | ||
509 | done: | 576 | /* try to display *something* */ |
577 | if (batt_anim->capacity < 0 || batt_anim->num_frames == 0) | ||
578 | draw_unknown(charger); | ||
579 | else | ||
580 | draw_battery(charger); | ||
510 | gr_flip(); | 581 | gr_flip(); |
511 | } | 582 | } |
512 | 583 | ||
513 | static void update_screen_state(struct charger *charger, int64_t now, | 584 | static void kick_animation(struct animation *anim) |
514 | bool force) | 585 | { |
586 | anim->run = true; | ||
587 | } | ||
588 | |||
589 | static void reset_animation(struct animation *anim) | ||
590 | { | ||
591 | anim->cur_cycle = 0; | ||
592 | anim->cur_frame = 0; | ||
593 | anim->run = false; | ||
594 | } | ||
595 | |||
596 | static void update_screen_state(struct charger *charger, int64_t now) | ||
515 | { | 597 | { |
516 | if (!force && ((now < charger->next_screen_transition) || | 598 | struct animation *batt_anim = charger->batt_anim; |
517 | (charger->next_screen_transition == -1))) | 599 | int cur_frame; |
600 | int disp_time; | ||
601 | |||
602 | if (!batt_anim->run || now < charger->next_screen_transition) | ||
518 | return; | 603 | return; |
519 | 604 | ||
520 | if (!charger->screen_on) | 605 | /* animation is over, blank screen and leave */ |
521 | charger->next_screen_transition = now + SCREEN_ON_TIME; | 606 | if (batt_anim->cur_cycle == batt_anim->num_cycles) { |
522 | else | 607 | reset_animation(batt_anim); |
523 | charger->next_screen_transition = -1; | 608 | charger->next_screen_transition = -1; |
524 | charger->screen_on = !charger->screen_on; | 609 | gr_fb_blank(true); |
610 | LOGV("[%lld] animation done\n", now); | ||
611 | return; | ||
612 | } | ||
613 | |||
614 | disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time; | ||
615 | |||
616 | /* animation starting, set up the animation */ | ||
617 | if (batt_anim->cur_frame == 0) { | ||
618 | int batt_cap; | ||
619 | int ret; | ||
620 | |||
621 | LOGV("[%lld] animation starting\n", now); | ||
622 | ret = read_file_int(charger->battery->cap_path, &batt_cap); | ||
623 | if (ret < 0 || batt_cap > 100) { | ||
624 | batt_cap = -1; | ||
625 | } else if (batt_anim->num_frames != 0) { | ||
626 | int i; | ||
627 | |||
628 | /* find first frame given current capacity */ | ||
629 | for (i = 1; i < batt_anim->num_frames; i++) { | ||
630 | if (batt_cap < batt_anim->frames[i].min_capacity) | ||
631 | break; | ||
632 | } | ||
633 | batt_anim->cur_frame = i - 1; | ||
634 | |||
635 | /* show the first frame for twice as long */ | ||
636 | disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2; | ||
637 | } | ||
638 | |||
639 | batt_anim->capacity = batt_cap; | ||
640 | } | ||
641 | |||
642 | /* unblank the screen on first cycle */ | ||
643 | if (batt_anim->cur_cycle == 0) | ||
644 | gr_fb_blank(false); | ||
645 | |||
646 | /* draw the new frame (@ cur_frame) */ | ||
647 | redraw_screen(charger); | ||
648 | |||
649 | /* if we don't have anim frames, we only have one image, so just bump | ||
650 | * the cycle counter and exit | ||
651 | */ | ||
652 | if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) { | ||
653 | LOGV("[%lld] animation missing or unknown battery status\n", now); | ||
654 | charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME; | ||
655 | batt_anim->cur_cycle++; | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | /* schedule next screen transition */ | ||
660 | charger->next_screen_transition = now + disp_time; | ||
661 | |||
662 | /* advance frame cntr to the next valid frame | ||
663 | * if necessary, advance cycle cntr, and reset frame cntr | ||
664 | */ | ||
665 | batt_anim->cur_frame++; | ||
666 | if (batt_anim->cur_frame == batt_anim->num_frames) { | ||
667 | batt_anim->cur_cycle++; | ||
668 | batt_anim->cur_frame = 0; | ||
525 | 669 | ||
526 | gr_fb_blank(!charger->screen_on); | 670 | /* don't reset the cycle counter, since we use that as a signal |
527 | if (charger->screen_on) | 671 | * in a test above to check if animation is over |
528 | redraw_screen(charger); | 672 | */ |
529 | LOGV("[%lld] screen %s\n", now, charger->screen_on ? "on" : "off"); | 673 | } |
530 | } | 674 | } |
531 | 675 | ||
532 | static void update_input_state(struct charger *charger, | 676 | static void update_input_state(struct charger *charger, |
@@ -585,7 +729,7 @@ static void process_key(struct charger *charger, int code, int64_t now) | |||
585 | } else { | 729 | } else { |
586 | /* if the power key got released, force screen state cycle */ | 730 | /* if the power key got released, force screen state cycle */ |
587 | if (key->pending) | 731 | if (key->pending) |
588 | update_screen_state(charger, now, true); | 732 | kick_animation(charger->batt_anim); |
589 | } | 733 | } |
590 | } | 734 | } |
591 | 735 | ||
@@ -617,7 +761,7 @@ static void handle_power_supply_state(struct charger *charger, int64_t now) | |||
617 | /* online supply present, reset shutdown timer if set */ | 761 | /* online supply present, reset shutdown timer if set */ |
618 | if (charger->next_pwr_check != -1) { | 762 | if (charger->next_pwr_check != -1) { |
619 | LOGI("[%lld] device plugged in: shutdown cancelled\n", now); | 763 | LOGI("[%lld] device plugged in: shutdown cancelled\n", now); |
620 | update_screen_state(charger, now, true); | 764 | kick_animation(charger->batt_anim); |
621 | } | 765 | } |
622 | charger->next_pwr_check = -1; | 766 | charger->next_pwr_check = -1; |
623 | } | 767 | } |
@@ -634,8 +778,6 @@ static void wait_next_event(struct charger *charger, int64_t now) | |||
634 | charger->next_screen_transition, charger->next_key_check, | 778 | charger->next_screen_transition, charger->next_key_check, |
635 | charger->next_pwr_check); | 779 | charger->next_pwr_check); |
636 | 780 | ||
637 | /* TODO: right now it's just screen on/off and keys, but later I'm sure | ||
638 | * there will be animations */ | ||
639 | if (charger->next_screen_transition != -1) | 781 | if (charger->next_screen_transition != -1) |
640 | next_event = charger->next_screen_transition; | 782 | next_event = charger->next_screen_transition; |
641 | if (charger->next_key_check != -1 && charger->next_key_check < next_event) | 783 | if (charger->next_key_check != -1 && charger->next_key_check < next_event) |
@@ -675,9 +817,13 @@ static void event_loop(struct charger *charger) | |||
675 | 817 | ||
676 | LOGV("[%lld] event_loop()\n", now); | 818 | LOGV("[%lld] event_loop()\n", now); |
677 | handle_input_state(charger, now); | 819 | handle_input_state(charger, now); |
678 | update_screen_state(charger, now, false); | ||
679 | handle_power_supply_state(charger, now); | 820 | handle_power_supply_state(charger, now); |
680 | 821 | ||
822 | /* do screen update last in case any of the above want to start | ||
823 | * screen transitions (animations, etc) | ||
824 | */ | ||
825 | update_screen_state(charger, now); | ||
826 | |||
681 | wait_next_event(charger, now); | 827 | wait_next_event(charger, now); |
682 | } | 828 | } |
683 | } | 829 | } |
@@ -688,6 +834,7 @@ int main(int argc, char **argv) | |||
688 | struct charger *charger = &charger_state; | 834 | struct charger *charger = &charger_state; |
689 | int64_t now = curr_time_ms() - 1; | 835 | int64_t now = curr_time_ms() - 1; |
690 | int fd; | 836 | int fd; |
837 | int i; | ||
691 | 838 | ||
692 | list_init(&charger->supplies); | 839 | list_init(&charger->supplies); |
693 | 840 | ||
@@ -707,10 +854,23 @@ int main(int argc, char **argv) | |||
707 | charger->uevent_fd = fd; | 854 | charger->uevent_fd = fd; |
708 | coldboot(charger, "/sys/class/power_supply", "add"); | 855 | coldboot(charger, "/sys/class/power_supply", "add"); |
709 | 856 | ||
710 | ret = res_create_surface("charging", &charger->surf_charging); | 857 | ret = res_create_surface("charger/battery_fail", &charger->surf_unknown); |
711 | if (ret < 0) { | 858 | if (ret < 0) { |
712 | LOGE("Cannot load image\n"); | 859 | LOGE("Cannot load image\n"); |
713 | charger->surf_charging = NULL; | 860 | charger->surf_unknown = NULL; |
861 | } | ||
862 | |||
863 | for (i = 0; i < charger->batt_anim->num_frames; i++) { | ||
864 | struct frame *frame = &charger->batt_anim->frames[i]; | ||
865 | |||
866 | ret = res_create_surface(frame->name, &frame->surface); | ||
867 | if (ret < 0) { | ||
868 | LOGE("Cannot load image %s\n", frame->name); | ||
869 | /* TODO: free the already allocated surfaces... */ | ||
870 | charger->batt_anim->num_frames = 0; | ||
871 | charger->batt_anim->num_cycles = 1; | ||
872 | break; | ||
873 | } | ||
714 | } | 874 | } |
715 | 875 | ||
716 | gr_fb_blank(true); | 876 | gr_fb_blank(true); |
@@ -718,7 +878,8 @@ int main(int argc, char **argv) | |||
718 | charger->next_screen_transition = now - 1; | 878 | charger->next_screen_transition = now - 1; |
719 | charger->next_key_check = -1; | 879 | charger->next_key_check = -1; |
720 | charger->next_pwr_check = -1; | 880 | charger->next_pwr_check = -1; |
721 | charger->screen_on = false; | 881 | reset_animation(charger->batt_anim); |
882 | kick_animation(charger->batt_anim); | ||
722 | 883 | ||
723 | event_loop(charger); | 884 | event_loop(charger); |
724 | 885 | ||