blob: 706dc80ba72b459803726dd4a70d34af8515f8a8 [file] [log] [blame]
Luke Song7f386dc2017-07-13 15:10:35 -07001/*
2 * Copyright (C) 2017 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
17#include <android-base/stringprintf.h>
18#include <batteryservice/BatteryService.h>
19#include <cutils/klog.h>
20
21#include "healthd_draw.h"
22
23#define LOGE(x...) KLOG_ERROR("charger", x);
Todd Poynore5d1b622018-06-01 11:09:58 -070024#define LOGW(x...) KLOG_WARNING("charger", x);
Luke Song7f386dc2017-07-13 15:10:35 -070025#define LOGV(x...) KLOG_DEBUG("charger", x);
26
27HealthdDraw::HealthdDraw(animation* anim)
28 : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN),
29 kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) {
Todd Poynore5d1b622018-06-01 11:09:58 -070030 int ret = gr_init();
Luke Song7f386dc2017-07-13 15:10:35 -070031
Todd Poynore5d1b622018-06-01 11:09:58 -070032 if (ret < 0) {
33 LOGE("gr_init failed\n");
34 graphics_available = false;
35 return;
36 }
Luke Song7f386dc2017-07-13 15:10:35 -070037
Todd Poynore5d1b622018-06-01 11:09:58 -070038 graphics_available = true;
39 sys_font = gr_sys_font();
40 if (sys_font == nullptr) {
41 LOGW("No system font, screen fallback text not available\n");
42 } else {
43 gr_font_size(sys_font, &char_width_, &char_height_);
44 }
45
46 screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
47 screen_height_ = gr_fb_height();
48
49 int res;
50 if (!anim->text_clock.font_file.empty() &&
51 (res = gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
52 LOGE("Could not load time font (%d)\n", res);
53 }
54 if (!anim->text_percent.font_file.empty() &&
55 (res = gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
56 LOGE("Could not load percent font (%d)\n", res);
57 }
Luke Song7f386dc2017-07-13 15:10:35 -070058}
59
60HealthdDraw::~HealthdDraw() {}
61
62void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) {
Todd Poynore5d1b622018-06-01 11:09:58 -070063 if (!graphics_available) return;
64 clear_screen();
Luke Song7f386dc2017-07-13 15:10:35 -070065
Todd Poynore5d1b622018-06-01 11:09:58 -070066 /* try to display *something* */
67 if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
68 draw_unknown(surf_unknown);
69 else
70 draw_battery(batt_anim);
71 gr_flip();
Luke Song7f386dc2017-07-13 15:10:35 -070072}
73
Todd Poynore5d1b622018-06-01 11:09:58 -070074void HealthdDraw::blank_screen(bool blank) {
75 if (!graphics_available) return;
76 gr_fb_blank(blank);
77}
Luke Song7f386dc2017-07-13 15:10:35 -070078
79void HealthdDraw::clear_screen(void) {
Todd Poynore5d1b622018-06-01 11:09:58 -070080 if (!graphics_available) return;
81 gr_color(0, 0, 0, 255);
82 gr_clear();
Luke Song7f386dc2017-07-13 15:10:35 -070083}
84
85int HealthdDraw::draw_surface_centered(GRSurface* surface) {
Todd Poynore5d1b622018-06-01 11:09:58 -070086 if (!graphics_available) return 0;
Luke Song7f386dc2017-07-13 15:10:35 -070087
Todd Poynore5d1b622018-06-01 11:09:58 -070088 int w = gr_get_width(surface);
89 int h = gr_get_height(surface);
90 int x = (screen_width_ - w) / 2 + kSplitOffset;
91 int y = (screen_height_ - h) / 2;
92
Luke Song7f386dc2017-07-13 15:10:35 -070093 LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
94 gr_blit(surface, 0, 0, w, h, x, y);
Todd Poynore5d1b622018-06-01 11:09:58 -070095 if (kSplitScreen) {
96 x += screen_width_ - 2 * kSplitOffset;
97 LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
98 gr_blit(surface, 0, 0, w, h, x, y);
99 }
Luke Song7f386dc2017-07-13 15:10:35 -0700100
Todd Poynore5d1b622018-06-01 11:09:58 -0700101 return y + h;
Luke Song7f386dc2017-07-13 15:10:35 -0700102}
103
104int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
Todd Poynore5d1b622018-06-01 11:09:58 -0700105 if (!graphics_available) return 0;
106 int str_len_px = gr_measure(font, str);
Luke Song7f386dc2017-07-13 15:10:35 -0700107
Todd Poynore5d1b622018-06-01 11:09:58 -0700108 if (x < 0) x = (screen_width_ - str_len_px) / 2;
109 if (y < 0) y = (screen_height_ - char_height_) / 2;
110 gr_text(font, x + kSplitOffset, y, str, false /* bold */);
111 if (kSplitScreen) gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */);
Luke Song7f386dc2017-07-13 15:10:35 -0700112
Todd Poynore5d1b622018-06-01 11:09:58 -0700113 return y + char_height_;
Luke Song7f386dc2017-07-13 15:10:35 -0700114}
115
116void HealthdDraw::determine_xy(const animation::text_field& field,
117 const int length, int* x, int* y) {
118 *x = field.pos_x;
119
120 int str_len_px = length * field.font->char_width;
121 if (field.pos_x == CENTER_VAL) {
122 *x = (screen_width_ - str_len_px) / 2;
123 } else if (field.pos_x >= 0) {
124 *x = field.pos_x;
125 } else { // position from max edge
126 *x = screen_width_ + field.pos_x - str_len_px - kSplitOffset;
127 }
128
129 *y = field.pos_y;
130
131 if (field.pos_y == CENTER_VAL) {
132 *y = (screen_height_ - field.font->char_height) / 2;
133 } else if (field.pos_y >= 0) {
134 *y = field.pos_y;
135 } else { // position from max edge
136 *y = screen_height_ + field.pos_y - field.font->char_height;
137 }
138}
139
140void HealthdDraw::draw_clock(const animation* anim) {
Todd Poynore5d1b622018-06-01 11:09:58 -0700141 static constexpr char CLOCK_FORMAT[] = "%H:%M";
142 static constexpr int CLOCK_LENGTH = 6;
Luke Song7f386dc2017-07-13 15:10:35 -0700143
Todd Poynore5d1b622018-06-01 11:09:58 -0700144 const animation::text_field& field = anim->text_clock;
Luke Song7f386dc2017-07-13 15:10:35 -0700145
Todd Poynore5d1b622018-06-01 11:09:58 -0700146 if (!graphics_available || field.font == nullptr || field.font->char_width == 0 ||
147 field.font->char_height == 0)
148 return;
Luke Song7f386dc2017-07-13 15:10:35 -0700149
Todd Poynore5d1b622018-06-01 11:09:58 -0700150 time_t rawtime;
151 time(&rawtime);
152 tm* time_info = localtime(&rawtime);
Luke Song7f386dc2017-07-13 15:10:35 -0700153
Todd Poynore5d1b622018-06-01 11:09:58 -0700154 char clock_str[CLOCK_LENGTH];
155 size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
156 if (length != CLOCK_LENGTH - 1) {
157 LOGE("Could not format time\n");
158 return;
159 }
Luke Song7f386dc2017-07-13 15:10:35 -0700160
Todd Poynore5d1b622018-06-01 11:09:58 -0700161 int x, y;
162 determine_xy(field, length, &x, &y);
Luke Song7f386dc2017-07-13 15:10:35 -0700163
Todd Poynore5d1b622018-06-01 11:09:58 -0700164 LOGV("drawing clock %s %d %d\n", clock_str, x, y);
165 gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
166 draw_text(field.font, x, y, clock_str);
Luke Song7f386dc2017-07-13 15:10:35 -0700167}
168
169void HealthdDraw::draw_percent(const animation* anim) {
Todd Poynore5d1b622018-06-01 11:09:58 -0700170 if (!graphics_available) return;
171 int cur_level = anim->cur_level;
172 if (anim->cur_status == BATTERY_STATUS_FULL) {
173 cur_level = 100;
174 }
Luke Song7f386dc2017-07-13 15:10:35 -0700175
kentsouba61ea42018-07-17 17:49:34 +0800176 if (cur_level < 0) return;
Luke Song7f386dc2017-07-13 15:10:35 -0700177
Todd Poynore5d1b622018-06-01 11:09:58 -0700178 const animation::text_field& field = anim->text_percent;
179 if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
180 return;
181 }
Luke Song7f386dc2017-07-13 15:10:35 -0700182
Todd Poynore5d1b622018-06-01 11:09:58 -0700183 std::string str = base::StringPrintf("%d%%", cur_level);
Luke Song7f386dc2017-07-13 15:10:35 -0700184
Todd Poynore5d1b622018-06-01 11:09:58 -0700185 int x, y;
186 determine_xy(field, str.size(), &x, &y);
Luke Song7f386dc2017-07-13 15:10:35 -0700187
Todd Poynore5d1b622018-06-01 11:09:58 -0700188 LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
189 gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
190 draw_text(field.font, x, y, str.c_str());
Luke Song7f386dc2017-07-13 15:10:35 -0700191}
192
193void HealthdDraw::draw_battery(const animation* anim) {
Todd Poynore5d1b622018-06-01 11:09:58 -0700194 if (!graphics_available) return;
195 const animation::frame& frame = anim->frames[anim->cur_frame];
Luke Song7f386dc2017-07-13 15:10:35 -0700196
Todd Poynore5d1b622018-06-01 11:09:58 -0700197 if (anim->num_frames != 0) {
198 draw_surface_centered(frame.surface);
199 LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame, frame.min_level,
200 frame.disp_time);
201 }
202 draw_clock(anim);
203 draw_percent(anim);
Luke Song7f386dc2017-07-13 15:10:35 -0700204}
205
206void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
207 int y;
208 if (surf_unknown) {
Todd Poynore5d1b622018-06-01 11:09:58 -0700209 draw_surface_centered(surf_unknown);
210 } else if (sys_font) {
211 gr_color(0xa4, 0xc6, 0x39, 255);
212 y = draw_text(sys_font, -1, -1, "Charging!");
213 draw_text(sys_font, -1, y + 25, "?\?/100");
Luke Song7f386dc2017-07-13 15:10:35 -0700214 } else {
Todd Poynore5d1b622018-06-01 11:09:58 -0700215 LOGW("Charging, level unknown\n");
Luke Song7f386dc2017-07-13 15:10:35 -0700216 }
217}