1/*
2 *  Copyright (C) 2012 Samsung Electronics
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Library General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *  Library General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Library General Public License
15 *  along with this library; see the file COPYING.LIB.  If not, write to
16 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 *  Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "BatteryProviderEfl.h"
22
23#if ENABLE(BATTERY_STATUS)
24
25#include "BatteryProviderEflClient.h"
26#include "EventNames.h"
27#include <E_Ukit.h>
28#include <limits>
29
30namespace WebCore {
31
32BatteryProviderEfl::BatteryProviderEfl(BatteryProviderEflClient* client)
33    : m_client(client)
34    , m_timer(this, &BatteryProviderEfl::timerFired)
35    , m_batteryStatusRefreshInterval(1.0)
36{
37}
38
39BatteryStatus* BatteryProviderEfl::batteryStatus() const
40{
41    return m_batteryStatus.get();
42}
43
44void BatteryProviderEfl::startUpdating()
45{
46    if (m_timer.isActive())
47        return;
48
49    if (!e_dbus_init())
50        return;
51
52    if (!e_ukit_init()) {
53        e_dbus_shutdown();
54        return;
55    }
56
57    m_timer.startRepeating(m_batteryStatusRefreshInterval);
58}
59
60void BatteryProviderEfl::stopUpdating()
61{
62    if (!m_timer.isActive())
63        return;
64
65    m_timer.stop();
66    e_ukit_shutdown();
67    e_dbus_shutdown();
68}
69
70void BatteryProviderEfl::setBatteryStatus(const AtomicString& eventType, PassRefPtr<BatteryStatus> batteryStatus)
71{
72    m_batteryStatus = batteryStatus;
73    m_client->didChangeBatteryStatus(eventType, m_batteryStatus);
74}
75
76void BatteryProviderEfl::timerFired(Timer<BatteryProviderEfl>* timer)
77{
78    ASSERT_UNUSED(timer, timer == &m_timer);
79    E_DBus_Connection* edbusConnection = e_dbus_bus_get(DBUS_BUS_SYSTEM);
80    if (edbusConnection)
81        e_upower_get_all_devices(edbusConnection, getBatteryStatus, static_cast<void*>(this));
82}
83
84void BatteryProviderEfl::getBatteryStatus(void* data, void* replyData, DBusError* dBusError)
85{
86    E_Ukit_Get_All_Devices_Return* eukitDeviceNames = static_cast<E_Ukit_Get_All_Devices_Return*>(replyData);
87    if (!eukitDeviceNames || !eukitDeviceNames->strings || dbus_error_is_set(dBusError)) {
88         dbus_error_free(dBusError);
89         return;
90    }
91
92    E_DBus_Connection* edbusConnection = e_dbus_bus_get(DBUS_BUS_SYSTEM);
93    Eina_List* list;
94    void* deviceName;
95    EINA_LIST_FOREACH(eukitDeviceNames->strings, list, deviceName)
96        e_upower_get_all_properties(edbusConnection, static_cast<char*>(deviceName), setBatteryClient, data);
97}
98
99void BatteryProviderEfl::setBatteryClient(void* data, void* replyData, DBusError* dBusError)
100{
101    E_Ukit_Get_All_Properties_Return* eukitPropertyNames = static_cast<E_Ukit_Get_All_Properties_Return*>(replyData);
102
103    if (!eukitPropertyNames || dbus_error_is_set(dBusError)) {
104        dbus_error_free(dBusError);
105        return;
106    }
107
108    if (!eukitPropertyNames->properties)
109        return;
110
111    E_Ukit_Property* property = static_cast<E_Ukit_Property*>(eina_hash_find(eukitPropertyNames->properties, "Type"));
112    if (!property || property->val.u != E_UPOWER_SOURCE_BATTERY)
113        return;
114
115    BatteryProviderEfl* client = static_cast<BatteryProviderEfl*>(data);
116    BatteryStatus* clientBatteryStatus = client->batteryStatus();
117    bool charging = false;
118    bool chargingChanged = false;
119    static unsigned chargingState = 0;
120
121    property = static_cast<E_Ukit_Property*>(eina_hash_find(eukitPropertyNames->properties, "State"));
122    if (!property)
123        return;
124    if (!clientBatteryStatus || chargingState != property->val.u) {
125        chargingChanged = true;
126        chargingState = property->val.u;
127        (chargingState == E_UPOWER_STATE_FULL || chargingState == E_UPOWER_STATE_CHARGING) ? charging = true : charging = false;
128    } else
129        charging = clientBatteryStatus->charging();
130
131    bool chargingTimeChanged = false;
132    bool dischargingTimeChanged = false;
133    double chargingTime = std::numeric_limits<double>::infinity();
134    double dischargingTime = std::numeric_limits<double>::infinity();
135
136    if (charging) {
137        if (!clientBatteryStatus || clientBatteryStatus->dischargingTime() != std::numeric_limits<double>::infinity())
138            dischargingTimeChanged = true;
139        dischargingTime = std::numeric_limits<double>::infinity();
140        property = static_cast<E_Ukit_Property*>(eina_hash_find(eukitPropertyNames->properties, "TimeToFull"));
141        if (!property)
142            return;
143        if (!clientBatteryStatus || clientBatteryStatus->chargingTime() != property->val.x)
144            chargingTimeChanged = true;
145        chargingTime = property->val.x;
146    } else {
147        if (!clientBatteryStatus || clientBatteryStatus->chargingTime() != std::numeric_limits<double>::infinity())
148            chargingTimeChanged = true;
149        chargingTime = std::numeric_limits<double>::infinity();
150        property = static_cast<E_Ukit_Property*>(eina_hash_find(eukitPropertyNames->properties, "TimeToEmpty"));
151        if (!property)
152            return;
153        if (!clientBatteryStatus || clientBatteryStatus->dischargingTime() != property->val.x)
154            dischargingTimeChanged = true;
155        dischargingTime = property->val.x;
156    }
157
158    bool levelChanged = false;
159    property = static_cast<E_Ukit_Property*>(eina_hash_find(eukitPropertyNames->properties, "Percentage"));
160    if (!property)
161        return;
162
163    double level = property->val.d / 100;
164    if (!clientBatteryStatus || clientBatteryStatus->level() != level)
165        levelChanged = true;
166
167    WTF::RefPtr<BatteryStatus> batteryStatus = BatteryStatus::create(charging, chargingTime, dischargingTime, level);
168    if (chargingChanged)
169        client->setBatteryStatus(eventNames().chargingchangeEvent, batteryStatus);
170    if (chargingTimeChanged)
171        client->setBatteryStatus(eventNames().chargingtimechangeEvent, batteryStatus);
172    if (dischargingTimeChanged)
173        client->setBatteryStatus(eventNames().dischargingtimechangeEvent, batteryStatus);
174    if (levelChanged)
175        client->setBatteryStatus(eventNames().levelchangeEvent, batteryStatus);
176}
177
178}
179
180#endif // BATTERY_STATUS
181
182