| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 1 | /* | 
|  | 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 Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 24 | #define LOGW(x...) KLOG_WARNING("charger", x); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 25 | #define LOGV(x...) KLOG_DEBUG("charger", x); | 
|  | 26 |  | 
|  | 27 | HealthdDraw::HealthdDraw(animation* anim) | 
|  | 28 | : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN), | 
|  | 29 | kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 30 | int ret = gr_init(); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 31 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 32 | if (ret < 0) { | 
|  | 33 | LOGE("gr_init failed\n"); | 
|  | 34 | graphics_available = false; | 
|  | 35 | return; | 
|  | 36 | } | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 37 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 38 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 58 | } | 
|  | 59 |  | 
|  | 60 | HealthdDraw::~HealthdDraw() {} | 
|  | 61 |  | 
|  | 62 | void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 63 | if (!graphics_available) return; | 
|  | 64 | clear_screen(); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 65 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 66 | /* 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 72 | } | 
|  | 73 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 74 | void HealthdDraw::blank_screen(bool blank) { | 
|  | 75 | if (!graphics_available) return; | 
|  | 76 | gr_fb_blank(blank); | 
|  | 77 | } | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 78 |  | 
|  | 79 | void HealthdDraw::clear_screen(void) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 80 | if (!graphics_available) return; | 
|  | 81 | gr_color(0, 0, 0, 255); | 
|  | 82 | gr_clear(); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 83 | } | 
|  | 84 |  | 
|  | 85 | int HealthdDraw::draw_surface_centered(GRSurface* surface) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 86 | if (!graphics_available) return 0; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 87 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 88 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 93 | LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); | 
|  | 94 | gr_blit(surface, 0, 0, w, h, x, y); | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 95 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 100 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 101 | return y + h; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 102 | } | 
|  | 103 |  | 
|  | 104 | int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 105 | if (!graphics_available) return 0; | 
|  | 106 | int str_len_px = gr_measure(font, str); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 107 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 108 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 112 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 113 | return y + char_height_; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 114 | } | 
|  | 115 |  | 
|  | 116 | void 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 |  | 
|  | 140 | void HealthdDraw::draw_clock(const animation* anim) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 141 | static constexpr char CLOCK_FORMAT[] = "%H:%M"; | 
|  | 142 | static constexpr int CLOCK_LENGTH = 6; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 143 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 144 | const animation::text_field& field = anim->text_clock; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 145 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 146 | if (!graphics_available || field.font == nullptr || field.font->char_width == 0 || | 
|  | 147 | field.font->char_height == 0) | 
|  | 148 | return; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 149 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 150 | time_t rawtime; | 
|  | 151 | time(&rawtime); | 
|  | 152 | tm* time_info = localtime(&rawtime); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 153 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 154 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 160 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 161 | int x, y; | 
|  | 162 | determine_xy(field, length, &x, &y); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 163 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 164 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 167 | } | 
|  | 168 |  | 
|  | 169 | void HealthdDraw::draw_percent(const animation* anim) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 170 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 175 |  | 
| kentsou | ba61ea4 | 2018-07-17 17:49:34 +0800 | [diff] [blame] | 176 | if (cur_level < 0) return; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 177 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 178 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 182 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 183 | std::string str = base::StringPrintf("%d%%", cur_level); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 184 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 185 | int x, y; | 
|  | 186 | determine_xy(field, str.size(), &x, &y); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 187 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 188 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 191 | } | 
|  | 192 |  | 
|  | 193 | void HealthdDraw::draw_battery(const animation* anim) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 194 | if (!graphics_available) return; | 
|  | 195 | const animation::frame& frame = anim->frames[anim->cur_frame]; | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 196 |  | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 197 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 204 | } | 
|  | 205 |  | 
|  | 206 | void HealthdDraw::draw_unknown(GRSurface* surf_unknown) { | 
|  | 207 | int y; | 
|  | 208 | if (surf_unknown) { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 209 | 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 Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 214 | } else { | 
| Todd Poynor | e5d1b62 | 2018-06-01 11:09:58 -0700 | [diff] [blame] | 215 | LOGW("Charging, level unknown\n"); | 
| Luke Song | 7f386dc | 2017-07-13 15:10:35 -0700 | [diff] [blame] | 216 | } | 
|  | 217 | } |