4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 #include <libsyscommon/libgdbus.h>
23 #include <libsyscommon/resource-manager.h>
24 #include <system/syscommon-plugin-deviced-common-interface.h>
25 #include <system/syscommon-plugin-deviced-display-interface.h>
29 #include "battery-parser.h"
30 #include "power-supply.h"
31 #include "lowbat-handler.h"
32 #include "battery-ops.h"
34 #include "display-lock.h"
35 #include "display-ops.h"
36 #include "display-state-transition.h"
38 #include "shared/eventsystem.h"
39 #include "shared/plugin.h"
40 #include "shared/device-notifier.h"
41 #include "shared/apps.h"
44 #define METHOD_LOW_NOTI_ON "BatteryLowNotiOn"
45 #define METHOD_LOW_NOTI_UPDATE "BatteryLowNotiUpdate"
46 #define METHOD_LOW_NOTI_OFF "BatteryLowNotiOff"
47 #define METHOD_CRITICAL_NOTI_ON "BatteryCriticalNotiOn"
48 #define METHOD_CRITICAL_NOTI_UPDATE "BatteryCriticalNotiUpdate"
49 #define METHOD_CRITICAL_NOTI_OFF "BatteryCriticalNotiOff"
51 #define REMOVE_POPUP "remove_battery_popups"
52 #define DISCONNECT_POPUP "battdisconnect"
54 enum event_noti_type {
59 static struct display_plugin *disp_plgn;
60 static struct battery_status *battery;
61 static guint abnormal_timer;
63 static int noti_low = NOTI_NONE;
64 static int noti_crit = NOTI_NONE;
66 static bool check_remove_condition(const char *prev, const char *cur)
72 prev_len = strlen(prev);
73 cur_len = strlen(cur);
75 if (!prev_len || !cur_len)
78 if (!strncmp(prev, EVT_VAL_BATTERY_LEVEL_CRITICAL,prev_len)) {
79 if (!strncmp(cur, EVT_VAL_BATTERY_LEVEL_LOW, cur_len)
80 || !strncmp(cur, EVT_VAL_BATTERY_LEVEL_HIGH, cur_len)
81 || !strncmp(cur, EVT_VAL_BATTERY_LEVEL_FULL, cur_len))
83 } else if (!strncmp(prev, EVT_VAL_BATTERY_LEVEL_LOW, prev_len)) {
84 if (!strncmp(cur, EVT_VAL_BATTERY_LEVEL_HIGH, cur_len)
85 || !strncmp(cur, EVT_VAL_BATTERY_LEVEL_FULL, cur_len))
92 static void low_noti_cb(GVariant *var, void *user_data, GError *err)
96 _E("Invalid parameter.");
100 if (!g_variant_get_safe(var, "(i)", ¬i_low)) {
101 _E("Failed to notify low: no message(%s)", g_variant_get_type_string(var));
105 _D("Inserted battery low noti : %d", noti_low);
108 g_variant_unref(var);
111 static void critical_noti_cb(GVariant *var, void *user_data, GError *err)
118 if (!g_variant_get_safe(var, "(i)", &id)) {
119 _E("Failed to notify critical: no message(%s)", g_variant_get_type_string(var));
124 _D("Inserted battery critical noti : %d", noti_crit);
127 g_variant_unref(var);
130 static int launch_lowbat_noti(int capacity, int option)
133 char batcap[10] = {0,};
134 char notiid[10] = {0,};
138 char *noti_type = NULL;
139 static int prev_level = BATTERY_NORMAL;
141 snprintf(batcap, sizeof(batcap), "%d", capacity);
144 if (option == BAT_OPT_WARNING) {
146 /* remove waring notiid*/
148 for (retry = RETRY_MAX; retry > 0; retry--) {
149 ret = gdbus_call_async(POPUP_BUS_NAME,
151 POPUP_INTERFACE_BATTERY,
153 g_variant_new("(i)", noti_id));
155 _D("Deleted battery critical noti.");
158 _E("Failed to call dbus method (err: %d)", ret);
161 memset(notiid, 0x0, sizeof(notiid));
162 snprintf(notiid, sizeof(notiid), "%d", noti_low);
164 if (prev_level == battery_info.critical || noti_low == NOTI_UPDATE)
165 noti_type = METHOD_LOW_NOTI_UPDATE;
167 noti_type = METHOD_LOW_NOTI_ON;
168 syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
169 DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
170 DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_BATTERY_CAPACITY_LOW);
172 prev_level = battery_info.warning;
173 if (battery->charge_now)
174 ret = gdbus_call_async(POPUP_BUS_NAME,
176 POPUP_INTERFACE_BATTERY,
178 g_variant_new("(ss)", pa[0], pa[1]));
180 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
182 POPUP_INTERFACE_BATTERY,
184 g_variant_new("(ss)", pa[0], pa[1]),
185 low_noti_cb, -1, NULL);
186 } else if (option == BAT_OPT_CRITICAL) {
188 /* remove waring notiid*/
190 for (retry = RETRY_MAX; retry > 0; retry--) {
191 ret = gdbus_call_async(POPUP_BUS_NAME,
193 POPUP_INTERFACE_BATTERY,
194 METHOD_CRITICAL_NOTI_OFF,
195 g_variant_new("(i)", noti_id));
197 _D("Deleted battery low noti");
200 _E("Failed to call dbus method (err: %d)", ret);
203 memset(notiid, 0x0, sizeof(notiid));
204 snprintf(notiid, sizeof(notiid), "%d", noti_crit);
206 if (noti_crit == NOTI_UPDATE)
207 noti_type = METHOD_CRITICAL_NOTI_UPDATE;
209 noti_type = METHOD_CRITICAL_NOTI_ON;
210 syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
211 DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
212 DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_BATTERY_CAPACITY_LOW);
214 prev_level = battery_info.critical;
215 if (battery->charge_now)
216 ret = gdbus_call_async(POPUP_BUS_NAME,
218 POPUP_INTERFACE_BATTERY,
220 g_variant_new("(ss)", pa[0], pa[1]));
222 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
224 POPUP_INTERFACE_BATTERY,
226 g_variant_new("(ss)", pa[0], pa[1]),
227 critical_noti_cb, -1, NULL);
230 prev_level = battery_info.normal;
232 _D("Requested type(%s) id(%s)", noti_type, notiid);
236 static void clean_lowbat_noti(const char *prev, const char *str)
244 _E("There is no data.");
248 if (prev == str && !battery->charge_now)
251 condition = check_remove_condition(prev, str);
252 _D("Condition: %d", condition);
254 if (condition || battery->charge_now) {
256 /* remove critical notiid */
258 for (retry = RETRY_MAX; retry > 0; retry--) {
259 ret = gdbus_call_async(POPUP_BUS_NAME,
261 POPUP_INTERFACE_BATTERY,
262 METHOD_CRITICAL_NOTI_OFF,
263 g_variant_new("(i)", noti_id));
265 _D("Deleted battery critical noti.");
266 noti_crit = NOTI_NONE;
269 _E("Failed to call dbus method: %d", ret);
274 /* remove waring notiid*/
276 for (retry = RETRY_MAX; retry > 0; retry--) {
277 ret = gdbus_call_async(POPUP_BUS_NAME,
279 POPUP_INTERFACE_BATTERY,
281 g_variant_new("(i)", noti_id));
283 _D("Deleted battery low noti.");
284 noti_low = NOTI_NONE;
287 _E("Failed to call dbus method: %d", ret);
291 _D("Noti_crit(%d) noti_low(%d).", noti_crit, noti_low);
294 static int changed_battery_cf(int status)
296 if (status == PRESENT_ABNORMAL)
297 return launch_system_app(APP_ABNORMAL, 2, APP_KEY_TYPE, DISCONNECT_POPUP);
298 return launch_system_app(APP_REMOVE, 2, APP_KEY_TYPE, REMOVE_POPUP);
301 static void remove_health_popup(void)
305 ret = launch_system_app(APP_REMOVE, 2, APP_KEY_TYPE, REMOVE_POPUP);
307 _E("Failed to launch remove battery popup(%d)", ret);
310 static int check_power_supply_noti(void)
315 static void update_ovp(enum battery_noti_status status)
317 if (status == DEVICE_NOTI_ON)
318 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_DIM);
320 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
323 static void health_timer_reset(void)
328 static gboolean health_timer_cb(void *data)
330 health_timer_reset();
332 if (battery->health != HEALTH_LOW && battery->health != HEALTH_HIGH)
333 return G_SOURCE_REMOVE;
335 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery->health_s);
336 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery->health);
337 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_DIM);
338 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
339 display_lock_request_lock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
340 if (battery->health == HEALTH_LOW)
341 battery_charge_err_low_act(NULL);
342 else if (battery->health == HEALTH_HIGH)
343 battery_charge_err_high_act(NULL);
344 return G_SOURCE_REMOVE;
347 static void abnormal_popup_dbus_signal_handler(GDBusConnection *conn,
356 if (battery->health == HEALTH_GOOD)
359 _I("Restart health timer.");
360 abnormal_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL,
361 health_timer_cb, NULL);
362 if (abnormal_timer == 0)
363 _E("Failed to add abnormal check timer.");
366 static void battery_notification_init(void *data)
368 struct battery_plugin *plugin = (struct battery_plugin *)data;
374 _D("Add plugins for battery notification.");
375 plugin->lowbat_noti_launch = launch_lowbat_noti;
376 plugin->lowbat_noti_clean = clean_lowbat_noti;
378 plugin->changed_battery_cf = changed_battery_cf;
379 plugin->remove_health_popup = remove_health_popup;
380 plugin->check_power_supply_noti = check_power_supply_noti;
381 plugin->update_ovp = update_ovp;
383 ret = gdbus_signal_subscribe(NULL, DEVICED_PATH_SYSNOTI,
384 DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE, abnormal_popup_dbus_signal_handler, NULL, NULL);
386 _E("Failed to init dbus signal: %d", ret);
389 static const struct battery_ops battery_notification_ops = {
390 .name = "battery_notification",
391 .init = battery_notification_init,
394 BATTERY_OPS_REGISTER(&battery_notification_ops)
396 static void __CONSTRUCTOR__ initialize(void)
398 disp_plgn = get_var_display_plugin();
400 _E("Failed to get display plugin variable.");
402 battery = get_var_battery_status();
404 _E("Failed to get battery status structure.");