1f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin/*
2fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor * Copyright (C) 2011-2013 The Android Open Source Project
3f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin *
4f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * Licensed under the Apache License, Version 2.0 (the "License");
5f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * you may not use this file except in compliance with the License.
6f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * You may obtain a copy of the License at
7f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin *
8f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin *      http://www.apache.org/licenses/LICENSE-2.0
9f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin *
10f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * Unless required by applicable law or agreed to in writing, software
11f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * distributed under the License is distributed on an "AS IS" BASIS,
12f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * See the License for the specific language governing permissions and
14f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * limitations under the License.
15f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin */
16f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
17f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <dirent.h>
18f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <errno.h>
19f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <fcntl.h>
20e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross#include <inttypes.h>
21f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <linux/input.h>
22f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdbool.h>
23f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdio.h>
24f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdlib.h>
25f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <string.h>
26fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor#include <sys/epoll.h>
27f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/stat.h>
28f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/types.h>
29f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/un.h>
30f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <time.h>
31f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <unistd.h>
32f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
3392c260159a6b69f0317d7b66dd11a52772494e48Tao Bao#include <functional>
3492c260159a6b69f0317d7b66dd11a52772494e48Tao Bao
35565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi#include <android-base/file.h>
36565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi#include <android-base/stringprintf.h>
37565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
38b77d3d724945f38b39f3116e3aead4edcbd08a36Elliott Hughes#include <sys/socket.h>
39b77d3d724945f38b39f3116e3aead4edcbd08a36Elliott Hughes#include <linux/netlink.h>
40b77d3d724945f38b39f3116e3aead4edcbd08a36Elliott Hughes
41fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor#include <batteryservice/BatteryService.h>
42f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/klog.h>
43823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin#include <cutils/misc.h>
44f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/uevent.h>
45e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews#include <cutils/properties.h>
4692c260159a6b69f0317d7b66dd11a52772494e48Tao Bao#include <minui/minui.h>
47c8183bb0711d74babaf5bc3bf77e9bd220621817Todd Poynor#include <sys/reboot.h>
48f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
4940156b8a91363da69675e7e4cb7947c371871654Iliyan Malchev#ifdef CHARGER_ENABLE_SUSPEND
509255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee#include <suspend/autosuspend.h>
5140156b8a91363da69675e7e4cb7947c371871654Iliyan Malchev#endif
529255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee
53565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi#include "animation.h"
54565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi#include "AnimationParser.h"
55f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
56e98e177a34eb3200b9f95be8379223271933b885Yabin Cui#include <healthd/healthd.h>
57fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
58565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchiusing namespace android;
59565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
60ca0e5044a390d2bffeef4dd652a4157b8998ef99Colin Crosschar *locale;
61ca0e5044a390d2bffeef4dd652a4157b8998ef99Colin Cross
62f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#ifndef max
63f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define max(a,b) ((a) > (b) ? (a) : (b))
64f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#endif
65f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
66f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#ifndef min
67f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define min(a,b) ((a) < (b) ? (a) : (b))
68f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#endif
69f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
70cdb2ca5d9f4fe4c3ac1d930394f088aed5d944acChih-Hung Hsieh#define ARRAY_SIZE(x)           (sizeof(x)/sizeof((x)[0]))
710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
72f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define MSEC_PER_SEC            (1000LL)
73f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define NSEC_PER_MSEC           (1000000LL)
74f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
750052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
7692312a515b0b877deed5dfdbf9d7613e8d66fee5Dima Zavin#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
77f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
78f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
79823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin#define LAST_KMSG_PATH          "/proc/last_kmsg"
80cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor#define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
81823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin#define LAST_KMSG_MAX_SZ        (32 * 1024)
82823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
83f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
84ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
85f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
86f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
87565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
88565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
89f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct key_state {
90f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    bool pending;
91f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    bool down;
92f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t timestamp;
93f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin};
94f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
95f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct charger {
96fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    bool have_battery_state;
97fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    bool charger_connected;
98f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t next_screen_transition;
99f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t next_key_check;
100f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t next_pwr_check;
101f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
102f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    struct key_state keys[KEY_MAX + 1];
103f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
1040052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    struct animation *batt_anim;
1059e85ea140362c1d12a002653e310405b5fc20edbElliott Hughes    GRSurface* surf_unknown;
106a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi    int boot_min_cap;
107f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin};
108f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
109565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic const struct animation BASE_ANIMATION = {
110565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .text_clock = {
111565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .pos_x = 0,
112565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .pos_y = 0,
113565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
114565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_r = 255,
115565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_g = 255,
116565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_b = 255,
117565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_a = 255,
118565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
119565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .font = nullptr,
120565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    },
121565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .text_percent = {
122565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .pos_x = 0,
123565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .pos_y = 0,
124565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
125565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_r = 255,
126565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_g = 255,
127565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_b = 255,
128565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .color_a = 255,
129565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    },
130565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
131565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .run = false,
132565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
133565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .frames = nullptr,
134565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .cur_frame = 0,
135565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .num_frames = 0,
136565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .first_frame_repeats = 2,
137565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
138565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .cur_cycle = 0,
139565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .num_cycles = 3,
140565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
141565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .cur_level = 0,
142565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    .cur_status = BATTERY_STATUS_UNKNOWN,
143565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi};
144565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
145565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
146565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic struct animation::frame default_animation_frames[] = {
1470052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    {
1480052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        .disp_time = 750,
149565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 0,
150565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 19,
151fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1520052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    },
1530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    {
1540052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        .disp_time = 750,
155565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 0,
156565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 39,
157fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1580052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    },
1590052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    {
1600052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        .disp_time = 750,
161565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 0,
162565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 59,
163fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1640052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    },
1650052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    {
1660052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        .disp_time = 750,
167565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 0,
168565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 79,
169fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1700052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    },
1710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    {
1720052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        .disp_time = 750,
173565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 80,
174565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 95,
175fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1760052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    },
1771a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin    {
1781a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin        .disp_time = 750,
179565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .min_level = 0,
180565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        .max_level = 100,
181fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        .surface = NULL,
1821a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin    },
1830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin};
1840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
185565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic struct animation battery_animation = BASE_ANIMATION;
1860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
187fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynorstatic struct charger charger_state;
188bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoistatic struct healthd_config *healthd_config;
189bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoistatic struct android::BatteryProperties *batt_prop;
190f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int char_width;
191f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int char_height;
192a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynorstatic bool minui_inited;
193f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
194f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin/* current time in milliseconds */
195f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int64_t curr_time_ms(void)
196f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
197f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    struct timespec tm;
198f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    clock_gettime(CLOCK_MONOTONIC, &tm);
199f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
200f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
201f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
202f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void clear_screen(void)
203f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
204f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    gr_color(0, 0, 0, 255);
205ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker    gr_clear();
206ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker}
207f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
208823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin#define MAX_KLOG_WRITE_BUF_SZ 256
209823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
210823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavinstatic void dump_last_kmsg(void)
211823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin{
212823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    char *buf;
213823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    char *ptr;
214823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    unsigned sz = 0;
215823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    int len;
216823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
217ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("\n");
218ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("*************** LAST KMSG ***************\n");
219ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("\n");
220cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor    buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
221cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor
222823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    if (!buf || !sz) {
223cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor        buf = (char *)load_file(LAST_KMSG_PATH, &sz);
224cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor        if (!buf || !sz) {
225ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor            LOGW("last_kmsg not found. Cold reset?\n");
226cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor            goto out;
227cd7c10438a3ea744a937a2100440e20a3960d745Todd Poynor        }
228823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    }
229823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
230823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    len = min(sz, LAST_KMSG_MAX_SZ);
231823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    ptr = buf + (sz - len);
232823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
233823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    while (len > 0) {
234823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
235823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        char yoink;
236823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        char *nl;
237823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
238fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        nl = (char *)memrchr(ptr, '\n', cnt - 1);
239823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        if (nl)
240823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin            cnt = nl - ptr + 1;
241823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
242823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        yoink = ptr[cnt];
243823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        ptr[cnt] = '\0';
244ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor        klog_write(6, "<4>%s", ptr);
245823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        ptr[cnt] = yoink;
246823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
247823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        len -= cnt;
248823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin        ptr += cnt;
249823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    }
250823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
251823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    free(buf);
252823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
253823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavinout:
254ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("\n");
255ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("************* END LAST KMSG *************\n");
256ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("\n");
257823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin}
258823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
2599255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee#ifdef CHARGER_ENABLE_SUSPEND
2609255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.leestatic int request_suspend(bool enable)
2619255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee{
2629255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee    if (enable)
2639255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee        return autosuspend_enable();
2649255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee    else
2659255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee        return autosuspend_disable();
2669255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee}
2679255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee#else
2686f5b47f9144960412b0fb6bc417f0c41bf53438aMark Salyzynstatic int request_suspend(bool /*enable*/)
2699255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee{
2709255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee    return 0;
2719255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee}
2729255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee#endif
2739255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee
274f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int draw_text(const char *str, int x, int y)
275f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
2760ee524de689e27379eaa3d0af0152183b844b0e8Damien Bargiacchi    int str_len_px = gr_measure(gr_sys_font(), str);
277f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
278f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (x < 0)
279f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        x = (gr_fb_width() - str_len_px) / 2;
280f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (y < 0)
281f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        y = (gr_fb_height() - char_height) / 2;
2820ee524de689e27379eaa3d0af0152183b844b0e8Damien Bargiacchi    gr_text(gr_sys_font(), x, y, str, 0);
283f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
284f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    return y + char_height;
285f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
286f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
287f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void android_green(void)
288f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
289f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    gr_color(0xa4, 0xc6, 0x39, 255);
290f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
291f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
292565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi// Negative x or y coordinates position the text away from the opposite edge that positive ones do.
293565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchivoid determine_xy(const animation::text_field& field, const int length, int* x, int* y)
294565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi{
295565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    *x = field.pos_x;
296565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    *y = field.pos_y;
297565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
298565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    int str_len_px = length * field.font->char_width;
299565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (field.pos_x == CENTER_VAL) {
300565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *x = (gr_fb_width() - str_len_px) / 2;
301565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else if (field.pos_x >= 0) {
302565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *x = field.pos_x;
303565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else {  // position from max edge
304565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *x = gr_fb_width() + field.pos_x - str_len_px;
305565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
306565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
307565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (field.pos_y == CENTER_VAL) {
308565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *y = (gr_fb_height() - field.font->char_height) / 2;
309565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else if (field.pos_y >= 0) {
310565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *y = field.pos_y;
311565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else {  // position from max edge
312565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        *y = gr_fb_height() + field.pos_y - field.font->char_height;
313565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
314565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi}
315565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
316565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic void draw_clock(const animation& anim)
317565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi{
318565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    static constexpr char CLOCK_FORMAT[] = "%H:%M";
319565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    static constexpr int CLOCK_LENGTH = 6;
320565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
321565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    const animation::text_field& field = anim.text_clock;
322565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
323565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
324565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
325565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    time_t rawtime;
326565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    time(&rawtime);
327565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    struct tm* time_info = localtime(&rawtime);
328565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
329565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    char clock_str[CLOCK_LENGTH];
330565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
331565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (length != CLOCK_LENGTH - 1) {
332565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGE("Could not format time\n");
333565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        return;
334565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
335565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
336565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    int x, y;
337565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    determine_xy(field, length, &x, &y);
338565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
339565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("drawing clock %s %d %d\n", clock_str, x, y);
340565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
341565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    gr_text(field.font, x, y, clock_str, false);
342565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi}
343565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
344565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic void draw_percent(const animation& anim)
345565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi{
3463f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi    int cur_level = anim.cur_level;
3473f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi    if (anim.cur_status == BATTERY_STATUS_FULL) {
3483f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi        cur_level = 100;
3493f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi    }
3503f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi
3513f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi    if (cur_level <= 0) return;
352565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
353565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    const animation::text_field& field = anim.text_percent;
354565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
355565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        return;
356565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
357565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
3583f0250c3cc84b2480ef70d51343204eecbe84532Damien Bargiacchi    std::string str = base::StringPrintf("%d%%", cur_level);
359565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
360565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    int x, y;
361565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    determine_xy(field, str.size(), &x, &y);
362565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
363565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
364565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
365565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    gr_text(field.font, x, y, str.c_str(), false);
366565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi}
367565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
3680052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin/* returns the last y-offset of where the surface ends */
369565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic int draw_surface_centered(GRSurface* surface)
370f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
3710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int w;
3720052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int h;
373f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int x;
3740052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int y;
375f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
3760052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    w = gr_get_width(surface);
3770052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    h = gr_get_height(surface);
3780052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    x = (gr_fb_width() - w) / 2 ;
3790052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    y = (gr_fb_height() - h) / 2 ;
380f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
3810052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
3820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    gr_blit(surface, 0, 0, w, h, x, y);
3830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    return y + h;
3840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}
385f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
3860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void draw_unknown(struct charger *charger)
3870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{
3880052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int y;
3890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    if (charger->surf_unknown) {
390565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        draw_surface_centered(charger->surf_unknown);
391f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    } else {
392f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        android_green();
393f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        y = draw_text("Charging!", -1, -1);
3940052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        draw_text("?\?/100", -1, y + 25);
395f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
3960052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}
397f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
398565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic void draw_battery(const struct charger* charger)
3990052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{
400565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    const struct animation& anim = *charger->batt_anim;
401565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    const struct animation::frame& frame = anim.frames[anim.cur_frame];
4020052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
403565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (anim.num_frames != 0) {
404565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        draw_surface_centered(frame.surface);
405ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker        LOGV("drawing frame #%d min_cap=%d time=%d\n",
406565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi             anim.cur_frame, frame.min_level,
407565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi             frame.disp_time);
408f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
409565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    draw_clock(anim);
410565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    draw_percent(anim);
4110052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}
412f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
4130052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void redraw_screen(struct charger *charger)
4140052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{
4150052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    struct animation *batt_anim = charger->batt_anim;
416f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
4170052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    clear_screen();
418f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
4190052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* try to display *something* */
420565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
4210052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        draw_unknown(charger);
4220052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    else
4230052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        draw_battery(charger);
424f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    gr_flip();
425f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
426f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
4270052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void kick_animation(struct animation *anim)
4280052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{
4290052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    anim->run = true;
4300052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}
4310052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
4320052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void reset_animation(struct animation *anim)
4330052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{
4340052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    anim->cur_cycle = 0;
4350052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    anim->cur_frame = 0;
4360052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    anim->run = false;
4370052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}
4380052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
439565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchistatic void init_status_display(struct animation* anim)
440565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi{
441565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    int res;
442565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
443565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (!anim->text_clock.font_file.empty()) {
444565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        if ((res =
445565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
446565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            LOGE("Could not load time font (%d)\n", res);
447565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        }
448565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
449565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
450565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (!anim->text_percent.font_file.empty()) {
451565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        if ((res =
452565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
453565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            LOGE("Could not load percent font (%d)\n", res);
454565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        }
455565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
456565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi}
457565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
4580052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void update_screen_state(struct charger *charger, int64_t now)
459f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
4600052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    struct animation *batt_anim = charger->batt_anim;
4610052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int disp_time;
4620052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
463565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (!batt_anim->run || now < charger->next_screen_transition) return;
464f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
465a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor    if (!minui_inited) {
466bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi        if (healthd_config && healthd_config->screen_on) {
467bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi            if (!healthd_config->screen_on(batt_prop)) {
468bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                LOGV("[%" PRId64 "] leave screen off\n", now);
469bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                batt_anim->run = false;
470bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                charger->next_screen_transition = -1;
471bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                if (charger->charger_connected)
472bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                    request_suspend(true);
473bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi                return;
474bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi            }
475a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor        }
476a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor
477a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor        gr_init();
4780ee524de689e27379eaa3d0af0152183b844b0e8Damien Bargiacchi        gr_font_size(gr_sys_font(), &char_width, &char_height);
479565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        init_status_display(batt_anim);
480a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor
481a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor#ifndef CHARGER_DISABLE_INIT_BLANK
482a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor        gr_fb_blank(true);
483a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor#endif
484a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor        minui_inited = true;
485a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor    }
486a7300274fdc5c92144471b1fe6dd19a8d18ae393Todd Poynor
4870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* animation is over, blank screen and leave */
488565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
4890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        reset_animation(batt_anim);
490f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        charger->next_screen_transition = -1;
4910052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        gr_fb_blank(true);
492e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross        LOGV("[%" PRId64 "] animation done\n", now);
493342a2264b96ab05dc8fdbfa8bbe354ce2f4b06caTodd Poynor        if (charger->charger_connected)
494fd8e6504e355d2c73a2aaad260475f72af0495bfDevin Kim            request_suspend(true);
4950052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        return;
4960052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    }
4970052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
4980052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
4990052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5000052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* animation starting, set up the animation */
5010052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    if (batt_anim->cur_frame == 0) {
5020052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
503e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross        LOGV("[%" PRId64 "] animation starting\n", now);
504565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        if (batt_prop) {
505565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            batt_anim->cur_level = batt_prop->batteryLevel;
506565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            batt_anim->cur_status = batt_prop->batteryStatus;
507565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
508565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                /* find first frame given current battery level */
509565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                for (int i = 0; i < batt_anim->num_frames; i++) {
510565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                    if (batt_anim->cur_level >= batt_anim->frames[i].min_level &&
511565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                        batt_anim->cur_level <= batt_anim->frames[i].max_level) {
512565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                        batt_anim->cur_frame = i;
513565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                        break;
514565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                    }
515565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                }
5160052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
517565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                // repeat the first frame first_frame_repeats times
518565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
519565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                    batt_anim->first_frame_repeats;
5200052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin            }
5210052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        }
5220052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    }
5230052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5240052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* unblank the screen  on first cycle */
5250052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    if (batt_anim->cur_cycle == 0)
5260052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        gr_fb_blank(false);
5270052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5280052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* draw the new frame (@ cur_frame) */
5290052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    redraw_screen(charger);
5300052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5310052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* if we don't have anim frames, we only have one image, so just bump
5320052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin     * the cycle counter and exit
5330052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin     */
534565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (batt_anim->num_frames == 0 || batt_anim->cur_level < 0) {
535565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
5360052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
5370052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        batt_anim->cur_cycle++;
5380052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        return;
5390052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    }
5400052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5410052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    /* schedule next screen transition */
5420052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    charger->next_screen_transition = now + disp_time;
5430052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
5449015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi    /* advance frame cntr to the next valid frame only if we are charging
5450052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin     * if necessary, advance cycle cntr, and reset frame cntr
5460052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin     */
5479015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi    if (charger->charger_connected) {
5489ec3f3e2e4ccb18ed85fa47015b0fa71985710c4Dima Zavin        batt_anim->cur_frame++;
549f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
5509015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        while (batt_anim->cur_frame < batt_anim->num_frames &&
551565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi               (batt_anim->cur_level < batt_anim->frames[batt_anim->cur_frame].min_level ||
552565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                batt_anim->cur_level > batt_anim->frames[batt_anim->cur_frame].max_level)) {
5539015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi            batt_anim->cur_frame++;
554565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        }
5559015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        if (batt_anim->cur_frame >= batt_anim->num_frames) {
5569015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi            batt_anim->cur_cycle++;
5579015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi            batt_anim->cur_frame = 0;
5589015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi
5599015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi            /* don't reset the cycle counter, since we use that as a signal
5609015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi             * in a test above to check if animation is over
5619015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi             */
5629015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        }
5639015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi    } else {
5649015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        /* Stop animating if we're not charging.
5659015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi         * If we stop it immediately instead of going through this loop, then
5669015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi         * the animation would stop somewhere in the middle.
5679015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi         */
5689015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        batt_anim->cur_frame = 0;
5699015eaa30fec3b5763e49124d7aa822862261842Ruchi Kandoi        batt_anim->cur_cycle++;
5700052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    }
571f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
572f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
57392c260159a6b69f0317d7b66dd11a52772494e48Tao Baostatic int set_key_callback(struct charger *charger, int code, int value)
574f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
5752471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    int64_t now = curr_time_ms();
5762471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    int down = !!value;
577f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
5782471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    if (code > KEY_MAX)
5792471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin        return -1;
580f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
5812d978c01ee71002b3c5999126c009ec07a773c30Dima Zavin    /* ignore events that don't modify our state */
5822d978c01ee71002b3c5999126c009ec07a773c30Dima Zavin    if (charger->keys[code].down == down)
583471157a393d052aece013d1f8b7701aaadca3b6cDima Zavin        return 0;
5842d978c01ee71002b3c5999126c009ec07a773c30Dima Zavin
585f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    /* only record the down even timestamp, as the amount
586f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin     * of time the key spent not being pressed is not useful */
587f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (down)
5882471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin        charger->keys[code].timestamp = now;
5892471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    charger->keys[code].down = down;
5902471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    charger->keys[code].pending = true;
591f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (down) {
592e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross        LOGV("[%" PRId64 "] key[%d] down\n", now, code);
593f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    } else {
5942471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin        int64_t duration = now - charger->keys[code].timestamp;
595f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        int64_t secs = duration / 1000;
596f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        int64_t msecs = duration - secs * 1000;
597e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross        LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
598e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross             now, code, secs, msecs);
599f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
6002471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin
6012471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    return 0;
6022471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin}
6032471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin
6042471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavinstatic void update_input_state(struct charger *charger,
6052471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin                               struct input_event *ev)
6062471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin{
6072471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    if (ev->type != EV_KEY)
6082471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin        return;
60992c260159a6b69f0317d7b66dd11a52772494e48Tao Bao    set_key_callback(charger, ev->code, ev->value);
610f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
611f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
612f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void set_next_key_check(struct charger *charger,
613f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                               struct key_state *key,
614f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                               int64_t timeout)
615f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
616f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t then = key->timestamp + timeout;
617f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
618f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (charger->next_key_check == -1 || then < charger->next_key_check)
619f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        charger->next_key_check = then;
620f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
621f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
622f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void process_key(struct charger *charger, int code, int64_t now)
623f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
624f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    struct key_state *key = &charger->keys[code];
625f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
626f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (code == KEY_POWER) {
627f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        if (key->down) {
628f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
629f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            if (now >= reboot_timeout) {
630e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                /* We do not currently support booting from charger mode on
631e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                   all devices. Check the property and continue booting or reboot
632e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                   accordingly. */
633e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
634ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor                    LOGW("[%" PRId64 "] booting from charger mode\n", now);
635e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                    property_set("sys.boot_from_charger_mode", "1");
636e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                } else {
637565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi                    if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
638a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi                        LOGW("[%" PRId64 "] rebooting\n", now);
639c8183bb0711d74babaf5bc3bf77e9bd220621817Todd Poynor                        reboot(RB_AUTOBOOT);
640a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi                    } else {
641c49ceca278af08224a33f6ff74a0f3c4656c9b5dChih-Hung Hsieh                        LOGV("[%" PRId64 "] ignore power-button press, battery level "
642a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi                            "less than minimum\n", now);
643a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi                    }
644e4b7b294f37d9b64d6b7c1931e2c9bfb1a500d68Riley Andrews                }
645f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            } else {
646f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                /* if the key is pressed but timeout hasn't expired,
647f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                 * make sure we wake up at the right-ish time to check
648f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                 */
649f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin                set_next_key_check(charger, key, POWER_ON_KEY_TIME);
6509a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi
6519a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi               /* Turn on the display and kick animation on power-key press
6529a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi                * rather than on key release
6539a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi                */
6549a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi                kick_animation(charger->batt_anim);
6559a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi                request_suspend(false);
656f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            }
657f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        } else {
658f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            /* if the power key got released, force screen state cycle */
6599255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee            if (key->pending) {
6600052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin                kick_animation(charger->batt_anim);
6619255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee            }
662f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        }
663f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
664f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
665f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    key->pending = false;
666f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
667f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
668f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void handle_input_state(struct charger *charger, int64_t now)
669f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
670f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    process_key(charger, KEY_POWER, now);
671f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
672f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (charger->next_key_check != -1 && now > charger->next_key_check)
673f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        charger->next_key_check = -1;
674f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
675f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
676f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void handle_power_supply_state(struct charger *charger, int64_t now)
677f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
678fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    if (!charger->have_battery_state)
679fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        return;
680fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
681fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    if (!charger->charger_connected) {
6829a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi
6839a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi        /* Last cycle would have stopped at the extreme top of battery-icon
6849a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi         * Need to show the correct level corresponding to capacity.
6859a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi         */
6869a11aaabf1ef8722c41d1057312be7a716badd66Ruchi Kandoi        kick_animation(charger->batt_anim);
6879255713bcf929e7cdd2817481f0dd08f838285c3choongryeol.lee        request_suspend(false);
688f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        if (charger->next_pwr_check == -1) {
689f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
690ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor            LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
691e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross                 now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
692f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        } else if (now >= charger->next_pwr_check) {
693ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor            LOGW("[%" PRId64 "] shutting down\n", now);
694c8183bb0711d74babaf5bc3bf77e9bd220621817Todd Poynor            reboot(RB_POWER_OFF);
695f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        } else {
696f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin            /* otherwise we already have a shutdown timer scheduled */
697f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        }
698f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    } else {
699f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        /* online supply present, reset shutdown timer if set */
700f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        if (charger->next_pwr_check != -1) {
701ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor            LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
7020052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin            kick_animation(charger->batt_anim);
703f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        }
704f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        charger->next_pwr_check = -1;
705f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
706f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
707f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
708fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynorvoid healthd_mode_charger_heartbeat()
709fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor{
710fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    struct charger *charger = &charger_state;
711fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    int64_t now = curr_time_ms();
712fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
713fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    handle_input_state(charger, now);
714fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    handle_power_supply_state(charger, now);
715fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
716fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    /* do screen update last in case any of the above want to start
717fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor     * screen transitions (animations, etc)
718fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor     */
719fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    update_screen_state(charger, now);
720fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor}
721fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
722fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynorvoid healthd_mode_charger_battery_update(
723fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    struct android::BatteryProperties *props)
724fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor{
725fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    struct charger *charger = &charger_state;
726fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
727fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    charger->charger_connected =
728fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        props->chargerAcOnline || props->chargerUsbOnline ||
729fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        props->chargerWirelessOnline;
730fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
731fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    if (!charger->have_battery_state) {
732fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        charger->have_battery_state = true;
733fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        charger->next_screen_transition = curr_time_ms() - 1;
734fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        reset_animation(charger->batt_anim);
735fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        kick_animation(charger->batt_anim);
736fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    }
737bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi    batt_prop = props;
738fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor}
739fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
740fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynorint healthd_mode_charger_preparetowait(void)
741f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
742fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    struct charger *charger = &charger_state;
743fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    int64_t now = curr_time_ms();
744f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t next_event = INT64_MAX;
745f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int64_t timeout;
746f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
747e1d5247e0090b57f1f5c63df7eba6754c502a449Colin Cross    LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
748f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin         charger->next_screen_transition, charger->next_key_check,
749f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin         charger->next_pwr_check);
750f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
751f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (charger->next_screen_transition != -1)
752f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        next_event = charger->next_screen_transition;
753f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (charger->next_key_check != -1 && charger->next_key_check < next_event)
754f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        next_event = charger->next_key_check;
755f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
756f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        next_event = charger->next_pwr_check;
757f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
758f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (next_event != -1 && next_event != INT64_MAX)
759f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        timeout = max(0, next_event - now);
760f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    else
761f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        timeout = -1;
762fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor
763fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor   return (int)timeout;
764f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
765f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
76692c260159a6b69f0317d7b66dd11a52772494e48Tao Baostatic int input_callback(struct charger *charger, int fd, unsigned int epevents)
767f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
768f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    struct input_event ev;
769f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int ret;
770f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
771fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    ret = ev_get_input(fd, epevents, &ev);
772f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (ret)
773f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin        return -1;
7742471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin    update_input_state(charger, &ev);
775f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    return 0;
776f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
777f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
7786f5b47f9144960412b0fb6bc417f0c41bf53438aMark Salyzynstatic void charger_event_handler(uint32_t /*epevents*/)
779f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
780f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int ret;
781f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
782fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    ret = ev_wait(-1);
783fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    if (!ret)
784fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        ev_dispatch();
785f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
786f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
787565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchianimation* init_animation()
788565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi{
789565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    bool parse_success;
790565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
791565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    std::string content;
792565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (base::ReadFileToString(animation_desc_path, &content)) {
793565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        parse_success = parse_animation_desc(content, &battery_animation);
794565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else {
795565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGW("Could not open animation description at %s\n", animation_desc_path);
796565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        parse_success = false;
797565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
798565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
799565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (!parse_success) {
800565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGW("Could not parse animation description. Using default animation.\n");
801565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation = BASE_ANIMATION;
802565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.animation_file.assign("charger/battery_scale");
803565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.frames = default_animation_frames;
804565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
805565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
806565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    if (battery_animation.fail_file.empty()) {
807565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.fail_file.assign("charger/battery_fail");
808565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
809565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
810565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("Animation Description:\n");
811565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("  animation: %d %d '%s' (%d)\n",
812565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.num_cycles, battery_animation.first_frame_repeats,
813565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.animation_file.c_str(), battery_animation.num_frames);
814565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("  fail_file: '%s'\n", battery_animation.fail_file.c_str());
815565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("  clock: %d %d %d %d %d %d '%s'\n",
816565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
817565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
818565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
819565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_clock.font_file.c_str());
820565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    LOGV("  percent: %d %d %d %d %d %d '%s'\n",
821565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
822565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
823565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
824565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        battery_animation.text_percent.font_file.c_str());
825565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    for (int i = 0; i < battery_animation.num_frames; i++) {
826565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGV("  frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
827565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
828565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    }
829565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
830565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    return &battery_animation;
831565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi}
832565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
833bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoivoid healthd_mode_charger_init(struct healthd_config* config)
834f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{
835f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    int ret;
836f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    struct charger *charger = &charger_state;
8370052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    int i;
838fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    int epollfd;
839f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
840823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin    dump_last_kmsg();
841823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
842ebeb0c0ea63af9fd8b2c8a7a20f919e48098ad9aTodd Poynor    LOGW("--------------- STARTING CHARGER MODE ---------------\n");
843823ebc4d824ea70e5ec7d376adf2fbce50eb9cb2Dima Zavin
84492c260159a6b69f0317d7b66dd11a52772494e48Tao Bao    ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
84592c260159a6b69f0317d7b66dd11a52772494e48Tao Bao                            std::placeholders::_2));
846fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    if (!ret) {
847fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor        epollfd = ev_get_epollfd();
848e89ea5eb85bae6b9257ac033996c8e64af432425Tim Murray        healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
849f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
850f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin
851565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    struct animation* anim = init_animation();
852565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    charger->batt_anim = anim;
853565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi
854565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
855f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    if (ret < 0) {
856565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        LOGE("Cannot load custom battery_fail image. Reverting to built in.\n");
857565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
858565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        if (ret < 0) {
859565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            LOGE("Cannot load built in battery_fail image\n");
860565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            charger->surf_unknown = NULL;
861565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        }
8620052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin    }
8630052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin
8649e85ea140362c1d12a002653e310405b5fc20edbElliott Hughes    GRSurface** scale_frames;
865ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker    int scale_count;
8660db80236f387aed9740f9765a65699827660059dTao Bao    int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
8670db80236f387aed9740f9765a65699827660059dTao Bao                    // chunk). We are using hard-coded frame.disp_time instead.
868565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    ret = res_create_multi_display_surface(anim->animation_file.c_str(),
869565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        &scale_count, &scale_fps, &scale_frames);
870ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker    if (ret < 0) {
871ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker        LOGE("Cannot load battery_scale image\n");
872565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        anim->num_frames = 0;
873565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        anim->num_cycles = 1;
874565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi    } else if (scale_count != anim->num_frames) {
875ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
876565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi             scale_count, anim->num_frames);
877565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        anim->num_frames = 0;
878565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        anim->num_cycles = 1;
879ee6ef15e677fd3168b4a0d221175fbf0ecd96ff5Doug Zongker    } else {
880565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi        for (i = 0; i < anim->num_frames; i++) {
881565ba02b89b64deb8bf7232ac2c2a38b01f63523Damien Bargiacchi            anim->frames[i].surface = scale_frames[i];
8820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin        }
883f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    }
88492c260159a6b69f0317d7b66dd11a52772494e48Tao Bao    ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
88592c260159a6b69f0317d7b66dd11a52772494e48Tao Bao                                std::placeholders::_2));
8862471a6a3956c591b3979b9b73a0d68f3b214da57Dima Zavin
887fea5b4d44b2f646a4befb6be92ddc3987b38bb36Todd Poynor    charger->next_screen_transition = -1;
888f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    charger->next_key_check = -1;
889f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin    charger->next_pwr_check = -1;
890bdf11c76a39d979abd105a4f27bc1973b88893adRuchi Kandoi    healthd_config = config;
891a84b1f64ccc5dda8e31854d4fc206b6c3d27ec39Ruchi Kandoi    charger->boot_min_cap = config->boot_min_cap;
892f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}
893