• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
24 #define LOGW(x...) KLOG_WARNING("charger", x);
25 #define LOGV(x...) KLOG_DEBUG("charger", x);
26 
HealthdDraw(animation * anim)27 HealthdDraw::HealthdDraw(animation* anim)
28   : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN),
29     kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) {
30     int ret = gr_init();
31 
32     if (ret < 0) {
33         LOGE("gr_init failed\n");
34         graphics_available = false;
35         return;
36     }
37 
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     }
58 }
59 
~HealthdDraw()60 HealthdDraw::~HealthdDraw() {}
61 
redraw_screen(const animation * batt_anim,GRSurface * surf_unknown)62 void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) {
63     if (!graphics_available) return;
64     clear_screen();
65 
66     /* try to display *something* */
67     if (batt_anim->cur_status == BATTERY_STATUS_UNKNOWN || batt_anim->cur_level < 0 ||
68         batt_anim->num_frames == 0)
69         draw_unknown(surf_unknown);
70     else
71         draw_battery(batt_anim);
72     gr_flip();
73 }
74 
blank_screen(bool blank)75 void HealthdDraw::blank_screen(bool blank) {
76     if (!graphics_available) return;
77     gr_fb_blank(blank);
78 }
79 
clear_screen(void)80 void HealthdDraw::clear_screen(void) {
81     if (!graphics_available) return;
82     gr_color(0, 0, 0, 255);
83     gr_clear();
84 }
85 
draw_surface_centered(GRSurface * surface)86 int HealthdDraw::draw_surface_centered(GRSurface* surface) {
87     if (!graphics_available) return 0;
88 
89     int w = gr_get_width(surface);
90     int h = gr_get_height(surface);
91     int x = (screen_width_ - w) / 2 + kSplitOffset;
92     int y = (screen_height_ - h) / 2;
93 
94     LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
95     gr_blit(surface, 0, 0, w, h, x, y);
96     if (kSplitScreen) {
97         x += screen_width_ - 2 * kSplitOffset;
98         LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
99         gr_blit(surface, 0, 0, w, h, x, y);
100     }
101 
102     return y + h;
103 }
104 
draw_text(const GRFont * font,int x,int y,const char * str)105 int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
106     if (!graphics_available) return 0;
107     int str_len_px = gr_measure(font, str);
108 
109     if (x < 0) x = (screen_width_ - str_len_px) / 2;
110     if (y < 0) y = (screen_height_ - char_height_) / 2;
111     gr_text(font, x + kSplitOffset, y, str, false /* bold */);
112     if (kSplitScreen) gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */);
113 
114     return y + char_height_;
115 }
116 
determine_xy(const animation::text_field & field,const int length,int * x,int * y)117 void HealthdDraw::determine_xy(const animation::text_field& field,
118                                const int length, int* x, int* y) {
119   *x = field.pos_x;
120 
121   int str_len_px = length * field.font->char_width;
122   if (field.pos_x == CENTER_VAL) {
123     *x = (screen_width_ - str_len_px) / 2;
124   } else if (field.pos_x >= 0) {
125     *x = field.pos_x;
126   } else {  // position from max edge
127     *x = screen_width_ + field.pos_x - str_len_px - kSplitOffset;
128   }
129 
130   *y = field.pos_y;
131 
132   if (field.pos_y == CENTER_VAL) {
133     *y = (screen_height_ - field.font->char_height) / 2;
134   } else if (field.pos_y >= 0) {
135     *y = field.pos_y;
136   } else {  // position from max edge
137     *y = screen_height_ + field.pos_y - field.font->char_height;
138   }
139 }
140 
draw_clock(const animation * anim)141 void HealthdDraw::draw_clock(const animation* anim) {
142     static constexpr char CLOCK_FORMAT[] = "%H:%M";
143     static constexpr int CLOCK_LENGTH = 6;
144 
145     const animation::text_field& field = anim->text_clock;
146 
147     if (!graphics_available || field.font == nullptr || field.font->char_width == 0 ||
148         field.font->char_height == 0)
149         return;
150 
151     time_t rawtime;
152     time(&rawtime);
153     tm* time_info = localtime(&rawtime);
154 
155     char clock_str[CLOCK_LENGTH];
156     size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
157     if (length != CLOCK_LENGTH - 1) {
158         LOGE("Could not format time\n");
159         return;
160     }
161 
162     int x, y;
163     determine_xy(field, length, &x, &y);
164 
165     LOGV("drawing clock %s %d %d\n", clock_str, x, y);
166     gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
167     draw_text(field.font, x, y, clock_str);
168 }
169 
draw_percent(const animation * anim)170 void HealthdDraw::draw_percent(const animation* anim) {
171     if (!graphics_available) return;
172     int cur_level = anim->cur_level;
173     if (anim->cur_status == BATTERY_STATUS_FULL) {
174         cur_level = 100;
175     }
176 
177     if (cur_level < 0) return;
178 
179     const animation::text_field& field = anim->text_percent;
180     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
181         return;
182     }
183 
184     std::string str = base::StringPrintf("%d%%", cur_level);
185 
186     int x, y;
187     determine_xy(field, str.size(), &x, &y);
188 
189     LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
190     gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
191     draw_text(field.font, x, y, str.c_str());
192 }
193 
draw_battery(const animation * anim)194 void HealthdDraw::draw_battery(const animation* anim) {
195     if (!graphics_available) return;
196     const animation::frame& frame = anim->frames[anim->cur_frame];
197 
198     if (anim->num_frames != 0) {
199         draw_surface_centered(frame.surface);
200         LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame, frame.min_level,
201              frame.disp_time);
202     }
203     draw_clock(anim);
204     draw_percent(anim);
205 }
206 
draw_unknown(GRSurface * surf_unknown)207 void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
208   int y;
209   if (surf_unknown) {
210       draw_surface_centered(surf_unknown);
211   } else if (sys_font) {
212       gr_color(0xa4, 0xc6, 0x39, 255);
213       y = draw_text(sys_font, -1, -1, "Charging!");
214       draw_text(sys_font, -1, y + 25, "?\?/100");
215   } else {
216       LOGW("Charging, level unknown\n");
217   }
218 }
219