Renames & Add new properties to QBatteryInfo
[qt:qtsystems.git] / src / systeminfo / linux / qbatteryinfo_linux.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
5 ** Contact: http://www.qt-project.org/legal
6 **
7 ** This file is part of the QtSystems module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Digia.  For licensing terms and
15 ** conditions see http://qt.digia.com/licensing.  For further information
16 ** use the contact form at http://qt.digia.com/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 2.1 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL included in the
22 ** packaging of this file.  Please review the following information to
23 ** ensure the GNU Lesser General Public License version 2.1 requirements
24 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** In addition, as a special exception, Digia gives you certain additional
27 ** rights.  These rights are described in the Digia Qt LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qbatteryinfo_linux_p.h"
44
45 #include <QtCore/qdir.h>
46 #include <QtCore/qfile.h>
47 #include <QtCore/qmetaobject.h>
48 #include <QtCore/qtimer.h>
49 #include <QtCore/qnumeric.h>
50
51 #if !defined(QT_NO_UDEV)
52 #include "qudevwrapper_p.h"
53 #endif // QT_NO_UDEV
54
55 QT_BEGIN_NAMESPACE
56
57 Q_GLOBAL_STATIC_WITH_ARGS(const QString, AC_ONLINE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/AC/online")))
58 Q_GLOBAL_STATIC_WITH_ARGS(const QString, BATTERY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/BAT%1/")))
59 Q_GLOBAL_STATIC_WITH_ARGS(const QString, POWER_SUPPLY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/")))
60 Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/present")))
61 Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/usb/type")))
62 Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_PRESENT_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/present")))
63 Q_GLOBAL_STATIC_WITH_ARGS(const QString, USB0_TYPE_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/USB0/type")))
64
65 QBatteryInfoPrivate::QBatteryInfoPrivate(QBatteryInfo *parent)
66     : QObject(parent)
67     , q_ptr(parent)
68     , watchIsValid(false)
69     , forceWatchBatteryCount(false)
70     , watchBatteryCount(false)
71     , watchChargerType(false)
72     , watchChargingState(false)
73     , watchCurrentFlow(false)
74     , watchRemainingCapacity(false)
75     , watchRemainingChargingTime(false)
76     , watchVoltage(false)
77     , watchLevelStatus(false)
78     , batteryCounts(-1)
79     , index(0)
80     , currentChargerType(QBatteryInfo::UnknownCharger)
81 #if !defined(QT_NO_UDEV)
82     , uDevWrapper(0)
83 #else
84     , timer(0)
85 #endif // QT_NO_UDEV
86 {
87 }
88
89 QBatteryInfoPrivate::QBatteryInfoPrivate(int batteryIndex, QBatteryInfo *parent)
90     : QObject(parent)
91     , q_ptr(parent)
92     , watchIsValid(false)
93     , forceWatchBatteryCount(false)
94     , watchBatteryCount(false)
95     , watchChargerType(false)
96     , watchChargingState(false)
97     , watchCurrentFlow(false)
98     , watchRemainingCapacity(false)
99     , watchRemainingChargingTime(false)
100     , watchVoltage(false)
101     , watchLevelStatus(false)
102     , batteryCounts(-1)
103     , index(batteryIndex)
104     , currentChargerType(QBatteryInfo::UnknownCharger)
105 #if !defined(QT_NO_UDEV)
106     , uDevWrapper(0)
107 #else
108     , timer(0)
109 #endif // QT_NO_UDEV
110 {
111 }
112
113 QBatteryInfoPrivate::~QBatteryInfoPrivate()
114 {
115 #if defined(QT_NO_UDEV)
116     delete timer;
117 #endif // QT_NO_UDEV
118 }
119
120 int QBatteryInfoPrivate::batteryCount()
121 {
122     if (!watchBatteryCount)
123         return getBatteryCount();
124
125     return batteryCounts;
126 }
127
128 int QBatteryInfoPrivate::batteryIndex() const
129 {
130     return index;
131 }
132
133 bool QBatteryInfoPrivate::isValid()
134 {
135     // valid if the index < total count.
136     return (index >= 0) && (index < batteryCount());
137 }
138
139 void QBatteryInfoPrivate::setBatteryIndex(int batteryIndex)
140 {
141     if (index != batteryIndex) {
142         bool validBefore = isValid();
143         int oldIndex = index;
144         index = batteryIndex;
145         bool validNow = isValid();
146         if (validBefore != validNow)
147             Q_EMIT validChanged(validNow);
148
149         if (validNow) {
150             if (validBefore) {
151                 // valid now, valid before so we have to check individual values
152
153                 // ignore chargerType - it won't change based on battery index
154                 //emit chargerTypeChanged(newChargerType);
155
156                 QBatteryInfo::ChargingState newChargingState = chargingState();
157                 if (newChargingState != chargingState(oldIndex))
158                     emit chargingStateChanged(newChargingState);
159
160                 int newValue = level();
161                 if (newValue != level(oldIndex))
162                     emit levelChanged(newValue);
163
164                 newValue = currentFlow();
165                 if (newValue != currentFlow(oldIndex))
166                     emit currentFlowChanged(newValue);
167
168                 newValue = cycleCount();
169                 if (newValue != cycleCount(oldIndex))
170                     emit cycleCountChanged(newValue);
171
172                 newValue = remainingCapacity();
173                 if (newValue != remainingCapacity(oldIndex))
174                     emit remainingCapacityChanged(newValue);
175
176                 newValue = remainingChargingTime();
177                 if (newValue != remainingChargingTime(oldIndex))
178                     emit remainingChargingTimeChanged(newValue);
179
180                 newValue = voltage();
181                 if (newValue != voltage(oldIndex))
182                     emit voltageChanged(newValue);
183
184                 QBatteryInfo::LevelStatus newLevelStatus = levelStatus();
185                 if (newLevelStatus != levelStatus(oldIndex))
186                     emit levelStatusChanged(newLevelStatus);
187
188                 QBatteryInfo::Health newHealth = health();
189                 if (newHealth != health(oldIndex))
190                     emit healthChanged(newHealth);
191
192                 float newTemperature = temperature();
193                 if (!qFuzzyCompare(newTemperature, temperature(oldIndex)))
194                     emit temperatureChanged(newTemperature);
195             } else {
196                 // it wasn't valid before so everything is changed
197
198                 // ignore chargerType - it won't change based on battery index
199                 //emit chargerTypeChanged(newChargerType);
200
201                 emit chargingStateChanged(chargingState());
202                 emit levelChanged(level());
203                 emit currentFlowChanged(currentFlow());
204                 emit cycleCountChanged(cycleCount());
205                 emit remainingCapacityChanged(remainingCapacity());
206                 emit remainingChargingTimeChanged(remainingChargingTime());
207                 emit voltageChanged(voltage());
208                 emit levelStatusChanged(levelStatus());
209                 emit healthChanged(health());
210                 emit temperatureChanged(temperature());
211             }
212         }
213
214         emit batteryIndexChanged(index);
215     }
216 }
217
218 int QBatteryInfoPrivate::level(int battery)
219 {
220     int maxCapacity = maximumCapacity(battery);
221     int remCapacity = remainingCapacity(battery);
222
223     if (maxCapacity == 0)
224         return -1;
225
226     return remCapacity * 100 / maxCapacity;
227 }
228
229 int QBatteryInfoPrivate::level()
230 {
231     return level(index);
232 }
233
234 int QBatteryInfoPrivate::currentFlow(int battery)
235 {
236     if (!watchCurrentFlow)
237         return getCurrentFlow(battery);
238
239     return currentFlows.value(battery);
240 }
241
242 int QBatteryInfoPrivate::currentFlow()
243 {
244     return currentFlow(index);
245 }
246
247 int QBatteryInfoPrivate::cycleCount(int battery)
248 {
249     Q_UNUSED(battery)
250
251     return -1;
252 }
253
254 int QBatteryInfoPrivate::cycleCount()
255 {
256     return cycleCount(index);
257 }
258
259 int QBatteryInfoPrivate::maximumCapacity(int battery)
260 {
261     if (maximumCapacities[battery] == 0) {
262         QFile maximum(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("charge_full"));
263         if (maximum.open(QIODevice::ReadOnly)) {
264             bool ok = false;
265             int capacity = maximum.readAll().simplified().toInt(&ok);
266             if (ok)
267                 maximumCapacities[battery] = capacity / 1000;
268             else
269                 maximumCapacities[battery] = -1;
270         } else {
271             maximumCapacities[battery] = -1;
272         }
273     }
274
275     return maximumCapacities[battery];
276 }
277
278 int QBatteryInfoPrivate::maximumCapacity()
279 {
280     return maximumCapacity(index);
281 }
282
283 int QBatteryInfoPrivate::remainingCapacity(int battery)
284 {
285     if (!watchRemainingCapacity)
286         return getRemainingCapacity(battery);
287
288     return remainingCapacities.value(battery);
289 }
290
291 int QBatteryInfoPrivate::remainingCapacity()
292 {
293     return remainingCapacity(index);
294 }
295
296 int QBatteryInfoPrivate::remainingChargingTime(int battery)
297 {
298     if (!watchRemainingChargingTime)
299         return getRemainingChargingTime(battery);
300
301     return remainingChargingTimes.value(battery);
302 }
303
304 int QBatteryInfoPrivate::remainingChargingTime()
305 {
306     return remainingChargingTime(index);
307 }
308
309 int QBatteryInfoPrivate::voltage(int battery)
310 {
311     if (!watchVoltage)
312         return getVoltage(battery);
313
314     return voltages.value(battery);
315 }
316
317 int QBatteryInfoPrivate::voltage()
318 {
319     return voltage(index);
320 }
321
322 QBatteryInfo::ChargerType QBatteryInfoPrivate::chargerType()
323 {
324     if (!watchChargerType)
325         return getChargerType();
326
327     return currentChargerType;
328 }
329
330 QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState(int battery)
331 {
332     if (!watchChargingState)
333         return getChargingState(battery);
334
335     return chargingStates.value(battery);
336 }
337
338 QBatteryInfo::ChargingState QBatteryInfoPrivate::chargingState()
339 {
340     return chargingState(index);
341 }
342
343 QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus(int battery)
344 {
345     if (!watchLevelStatus)
346         return getLevelStatus(battery);
347
348     return levelStatuss.value(battery);
349 }
350
351 QBatteryInfo::LevelStatus QBatteryInfoPrivate::levelStatus()
352 {
353     return levelStatus(index);
354 }
355
356 QBatteryInfo::Health QBatteryInfoPrivate::health(int battery)
357 {
358     Q_UNUSED(battery)
359
360     return QBatteryInfo::HealthUnknown;
361 }
362
363 QBatteryInfo::Health QBatteryInfoPrivate::health()
364 {
365     return health(index);
366 }
367
368 float QBatteryInfoPrivate::temperature(int battery)
369 {
370     Q_UNUSED(battery)
371
372     return qQNaN();
373 }
374
375 float QBatteryInfoPrivate::temperature()
376 {
377     return temperature(index);
378 }
379
380 void QBatteryInfoPrivate::connectNotify(const QMetaMethod &signal)
381 {
382     static const QMetaMethod batteryCountChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::batteryCountChanged);
383     static const QMetaMethod validChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::validChanged);
384     static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::chargerTypeChanged);
385     static const QMetaMethod chargingStateChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::chargingStateChanged);
386     static const QMetaMethod currentFlowChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::currentFlowChanged);
387     static const QMetaMethod remainingCapacityChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::remainingCapacityChanged);
388     static const QMetaMethod remainingChargingTimeChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::remainingChargingTimeChanged);
389     static const QMetaMethod voltageChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::voltageChanged);
390     static const QMetaMethod levelStatusChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::levelStatusChanged);
391
392 #if !defined(QT_NO_UDEV)
393     if (!uDevWrapper)
394         uDevWrapper = new QUDevWrapper(this);
395     if (!watchChargerType && signal == chargerTypeChangedSignal) {
396         connect(uDevWrapper, SIGNAL(chargerTypeChanged(QByteArray,bool)), this, SLOT(onChargerTypeChanged(QByteArray,bool)));
397     } else if (!watchIsValid && !watchCurrentFlow && !watchVoltage && !watchChargingState && !watchRemainingCapacity
398                && !watchRemainingChargingTime && !watchBatteryCount && !watchLevelStatus) {
399         connect(uDevWrapper, SIGNAL(batteryDataChanged(int,QByteArray,QByteArray)), this, SLOT(onBatteryDataChanged(int,QByteArray,QByteArray)));
400     }
401 #else
402     if (timer == 0) {
403        timer = new QTimer;
404        timer->setInterval(2000);
405        connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
406     }
407
408     if (!timer->isActive())
409        timer->start();
410 #endif // QT_NO_UDEV
411
412     if (signal == validChangedSignal) {
413         if (!watchIsValid && !watchBatteryCount)
414             forceWatchBatteryCount = true;
415
416         watchIsValid = true;
417
418         // we have to watch battery count if someone is watching validChanged.
419         watchBatteryCount = true;
420         batteryCounts = getBatteryCount();
421     } else if (signal == batteryCountChangedSignal) {
422         watchBatteryCount = true;
423         forceWatchBatteryCount = false;
424         batteryCounts = getBatteryCount();
425     } else if (signal == currentFlowChangedSignal) {
426         watchCurrentFlow = true;
427         int count = batteryCount();
428         for (int i = 0; i < count; ++i)
429             currentFlows[i] = getCurrentFlow(i);
430     } else if (signal == voltageChangedSignal) {
431         watchVoltage = true;
432         int count = batteryCount();
433         for (int i = 0; i < count; ++i)
434             voltages[i] = getVoltage(i);
435     } else if (signal == remainingCapacityChangedSignal) {
436         watchRemainingCapacity = true;
437         int count = batteryCount();
438         for (int i = 0; i < count; ++i)
439             remainingCapacities[i] = getRemainingCapacity(i);
440     } else if (signal == remainingChargingTimeChangedSignal) {
441         watchRemainingChargingTime = true;
442         int count = batteryCount();
443         for (int i = 0; i < count; ++i)
444             remainingChargingTimes[i] = getRemainingChargingTime(i);
445     } else if (signal == chargerTypeChangedSignal) {
446         watchChargerType = true;
447         currentChargerType = getChargerType();
448     } else if (signal == chargingStateChangedSignal) {
449         watchChargingState = true;
450         int count = batteryCount();
451         for (int i = 0; i < count; ++i)
452             chargingStates[i] = getChargingState(i);
453     } else if (signal == levelStatusChangedSignal) {
454         watchLevelStatus = true;
455         int count = batteryCount();
456         for (int i = 0; i < count; i++)
457             levelStatuss[i] = getLevelStatus(i);
458     }
459 }
460
461 void QBatteryInfoPrivate::disconnectNotify(const QMetaMethod &signal)
462 {
463     static const QMetaMethod batteryCountChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::batteryCountChanged);
464     static const QMetaMethod validChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::validChanged);
465     static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::chargerTypeChanged);
466     static const QMetaMethod chargingStateChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::chargingStateChanged);
467     static const QMetaMethod currentFlowChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::currentFlowChanged);
468     static const QMetaMethod remainingCapacityChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::remainingCapacityChanged);
469     static const QMetaMethod remainingChargingTimeChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::remainingChargingTimeChanged);
470     static const QMetaMethod voltageChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::voltageChanged);
471     static const QMetaMethod levelStatusChangedSignal = QMetaMethod::fromSignal(&QBatteryInfoPrivate::levelStatusChanged);
472
473     if (signal == validChangedSignal) {
474         watchIsValid = false;
475         if (forceWatchBatteryCount) {
476             watchBatteryCount = false;
477             batteryCounts = -1;
478         }
479     } else if (signal == batteryCountChangedSignal) {
480         if (!watchIsValid) {
481             watchBatteryCount = false;
482             batteryCounts = -1;
483         } else {
484             forceWatchBatteryCount = true;
485         }
486     } else if (signal == currentFlowChangedSignal) {
487         watchCurrentFlow = false;
488         currentFlows.clear();
489     } else if (signal == voltageChangedSignal) {
490         watchVoltage = false;
491         voltages.clear();
492     } else if (signal == remainingCapacityChangedSignal) {
493         watchRemainingCapacity = false;
494         remainingCapacities.clear();
495     } else if (signal == remainingChargingTimeChangedSignal) {
496         watchRemainingChargingTime = false;
497         remainingChargingTimes.clear();
498     } else if (signal == chargerTypeChangedSignal) {
499         watchChargerType = false;
500         currentChargerType = QBatteryInfo::UnknownCharger;
501     } else if (signal == chargingStateChangedSignal) {
502         watchChargingState = false;
503         chargingStates.clear();
504     } else if (signal == levelStatusChangedSignal) {
505         watchLevelStatus = false;
506         levelStatuss.clear();
507     }
508
509 #if !defined(QT_NO_UDEV)
510     if (uDevWrapper && !watchChargerType && signal == chargerTypeChangedSignal) {
511         disconnect(uDevWrapper, SIGNAL(chargerTypeChanged(QByteArray,bool)),
512                    this, SLOT(onChargerTypeChanged(QByteArray,bool)));
513     } else if (uDevWrapper && !watchCurrentFlow && !watchVoltage && !watchChargingState && !watchRemainingCapacity
514                && !watchRemainingChargingTime && !watchBatteryCount && !watchLevelStatus) {
515         disconnect(uDevWrapper, SIGNAL(batteryDataChanged(int,QByteArray,QByteArray)),
516                    this, SLOT(onBatteryDataChanged(int,QByteArray,QByteArray)));
517     }
518 #endif
519
520     if (!watchBatteryCount && !watchChargerType && !watchChargingState
521             && !watchCurrentFlow && !watchRemainingCapacity
522             && !watchRemainingChargingTime && !watchVoltage && !watchLevelStatus) {
523 #if !defined(QT_NO_UDEV)
524         if (uDevWrapper) {
525             delete uDevWrapper;
526             uDevWrapper = 0;
527         }
528 #else
529         timer->stop();
530 #endif // QT_NO_UDEV
531     }
532 }
533
534 #if !defined(QT_NO_UDEV)
535
536 void QBatteryInfoPrivate::onBatteryDataChanged(int battery, const QByteArray &attribute, const QByteArray &value)
537 {
538     if (watchBatteryCount) {
539         int count = getBatteryCount();
540         if (batteryCounts != count) {
541             bool validBefore = isValid();
542             batteryCounts = count;
543             bool validNow = isValid();
544             if (validBefore != validNow)
545                 Q_EMIT validChanged(validNow);
546
547             // We do not have to worry about firing all changed signals here.
548             // Each individual value will receive an onBatteryDataChanged() call
549             // and will fire a signal at that time.
550
551             emit batteryCountChanged(count);
552         }
553     }
554
555     if (watchChargingState && attribute.contains("status")) {
556         QBatteryInfo::ChargingState state = QBatteryInfo::UnknownChargingState;
557         if (qstrcmp(value, "Charging") == 0)
558             state = QBatteryInfo::Charging;
559         else if (qstrcmp(value, "Not charging") == 0)
560             state = QBatteryInfo::IdleChargingState;
561         else if (qstrcmp(value, "Discharging") == 0)
562             state = QBatteryInfo::Discharging;
563         else if (qstrcmp(value, "Full") == 0)
564             state = QBatteryInfo::IdleChargingState;
565         if (chargingStates.value(battery) != state) {
566             chargingStates[battery] = state;
567             if (battery == index)
568                 emit chargingStateChanged(state);
569         }
570     }
571
572     if (watchRemainingCapacity && attribute.contains("charge_now")) {
573         if (!value.isEmpty()) {
574             int remainingCapacity = value.toInt() / 1000;
575             if (remainingCapacities.value(battery) != remainingCapacity) {
576                 remainingCapacities[battery] = remainingCapacity;
577                 if (battery == index)
578                     emit remainingCapacityChanged(remainingCapacity);
579             }
580         }
581     }
582
583     if (watchRemainingChargingTime && attribute.contains("time_to_full_avg")) {
584         if (!value.isEmpty()) {
585             int remainingChargingTime = value.toInt();
586             if (remainingChargingTimes.value(battery) != remainingChargingTime) {
587                 remainingChargingTimes[battery] = remainingChargingTime;
588                 if (battery == index)
589                     emit remainingChargingTimeChanged(remainingChargingTime);
590             }
591         }
592     }
593
594     if (watchVoltage && attribute.contains("voltage_now")) {
595         if (!value.isEmpty()) {
596             int voltage = value.toInt() / 1000;
597             if (voltages.value(battery) != voltage) {
598                 voltages[battery] = voltage;
599                 if (battery == index)
600                     emit voltageChanged(voltage);
601             }
602         }
603     }
604
605     if (watchCurrentFlow && attribute.contains("current_now")) {
606         if (!value.isEmpty()) {
607             int currentFlow = value.toInt() / -1000;
608             if (chargingStates.value(battery) == QBatteryInfo::Discharging && currentFlow < 0)
609                 currentFlow = -currentFlow;
610
611             if (currentFlows.value(battery) != currentFlow) {
612                 currentFlows[battery] = currentFlow;
613                 if (battery == index)
614                     emit currentFlowChanged(currentFlow);
615             }
616         }
617     }
618
619     if (watchLevelStatus && attribute.contains("capacity_level")) {
620         QBatteryInfo::LevelStatus levelStatus = QBatteryInfo::LevelUnknown;
621         if (qstrcmp(value, "Critical") == 0)
622             levelStatus = QBatteryInfo::LevelEmpty;
623         else if (qstrcmp(value, "Low") == 0)
624             levelStatus = QBatteryInfo::LevelLow;
625         else if (qstrcmp(value, "Normal") == 0)
626             levelStatus = QBatteryInfo::LevelOk;
627         else if (qstrcmp(value, "Full") == 0)
628             levelStatus = QBatteryInfo::LevelFull;
629         if (levelStatuss.value(battery) != levelStatus) {
630             levelStatuss[battery] = levelStatus;
631             if (battery == index)
632                 emit levelStatusChanged(levelStatus);
633         }
634     }
635 }
636
637 void QBatteryInfoPrivate::onChargerTypeChanged(const QByteArray &value, bool enabled)
638 {
639     if (watchChargerType) {
640         QBatteryInfo::ChargerType charger = QBatteryInfo::UnknownCharger;
641         if (enabled) {
642             if ((qstrcmp(value, "AC") == 0) || qstrcmp(value, "USB_DCP") == 0)
643                 charger = QBatteryInfo::WallCharger;
644             else if (qstrcmp(value, "USB") == 0)
645                 charger = QBatteryInfo::USBCharger;
646             else if (qstrcmp(value, "USB_CDP") == 0 || qstrcmp(value, "USB_SDP") == 0)
647                 charger = QBatteryInfo::VariableCurrentCharger;
648         }
649         if (currentChargerType != charger) {
650             currentChargerType = charger;
651             emit chargerTypeChanged(charger);
652         }
653     }
654 }
655
656 #else
657
658 void QBatteryInfoPrivate::onTimeout()
659 {
660     int count = getBatteryCount();
661     int value;
662     if (watchBatteryCount) {
663         value = getBatteryCount();
664         if (batteryCounts != value) {
665             bool validBefore = isValid();
666             batteryCounts = value;
667             bool validNow = isValid();
668             if (validBefore != validNow)
669                 Q_EMIT validChanged(validNow);
670
671             // We do not have to worry about firing all changed signals here.
672             // Each individual value will (possibly) be updated below
673             // and will fire a signal at that time if it has changed.
674
675             emit batteryCountChanged(value);
676         }
677     }
678
679     for (int i = 0; i < count; ++i) {
680         if (watchCurrentFlow) {
681             value = getCurrentFlow(i);
682             if (currentFlows.value(i) != value) {
683                 currentFlows[i] = value;
684                 if (i == index)
685                     emit currentFlowChanged(value);
686             }
687         }
688
689         if (watchVoltage) {
690             value = getVoltage(i);
691             if (voltages.value(i) != value) {
692                 voltages[i] = value;
693                 if (i == index)
694                     emit voltageChanged(value);
695             }
696         }
697
698         if (watchRemainingCapacity) {
699             value = getRemainingCapacity(i);
700             if (remainingCapacities.value(i) != value) {
701                 remainingCapacities[i] = value;
702                 if (i == index)
703                     emit remainingCapacityChanged(value);
704             }
705         }
706
707         if (watchRemainingChargingTime) {
708             value = getRemainingChargingTime(i);
709             if (remainingChargingTimes.value(i) != value) {
710                 remainingChargingTimes[i] = value;
711                 if (i == index)
712                     emit remainingChargingTimeChanged(value);
713             }
714         }
715
716         if (watchChargerType) {
717             QBatteryInfo::ChargerType charger = getChargerType();
718             if (currentChargerType != charger) {
719                 currentChargerType = charger;
720                 emit chargerTypeChanged(charger);
721             }
722         }
723
724         if (watchChargingState) {
725             QBatteryInfo::ChargingState state = getChargingState(i);
726             if (chargingStates.value(i) != state) {
727                 chargingStates[i] = state;
728                 if (i == index)
729                     emit chargingStateChanged(state);
730             }
731         }
732
733         if (watchLevelStatus) {
734             QBatteryInfo::LevelStatus levelStatus = getLevelStatus(i);
735             if (levelStatuss.value(i) != levelStatus) {
736                 levelStatuss[i] = levelStatus;
737                 if (i == index)
738                     emit levelStatusChanged(levelStatus);
739             }
740         }
741     }
742 }
743
744 #endif // QT_NO_UDEV
745
746 int QBatteryInfoPrivate::getBatteryCount()
747 {
748     return QDir(*POWER_SUPPLY_SYSFS_PATH()).entryList(QStringList() << QStringLiteral("BAT*")).size();
749 }
750
751 int QBatteryInfoPrivate::getCurrentFlow(int battery)
752 {
753     QBatteryInfo::ChargingState state = chargingState(battery);
754     if (state == QBatteryInfo::UnknownChargingState)
755         return 0;
756
757     QFile current(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("current_now"));
758     if (!current.open(QIODevice::ReadOnly))
759         return 0;
760
761     bool ok = false;
762     int flow = current.readAll().simplified().toInt(&ok);
763     if (ok) {
764         // We want discharging current to be positive and charging current to be negative.
765         if (state == QBatteryInfo::Charging) {
766           // In case some drivers make charging current negative already and others are opposite
767           return flow < 0 ? flow / 1000 : flow / -1000;
768         } else if (state == QBatteryInfo::Discharging) {
769           // In case some drivers make discharging current positive already and others are opposite
770           return flow > 0 ? flow / 1000 : flow / -1000;
771         }
772     }
773
774     return 0;
775 }
776
777 int QBatteryInfoPrivate::getRemainingCapacity(int battery)
778 {
779     QFile remaining(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("charge_now"));
780     if (!remaining.open(QIODevice::ReadOnly))
781         return -1;
782
783     bool ok = false;
784     int capacity = remaining.readAll().simplified().toInt(&ok);
785     if (ok)
786         return capacity / 1000;
787     return -1;
788 }
789
790 int QBatteryInfoPrivate::getRemainingChargingTime(int battery)
791 {
792     QBatteryInfo::ChargingState state = chargingState(battery);
793     if (state == QBatteryInfo::UnknownChargingState)
794         return -1;
795     else if (state == QBatteryInfo::IdleChargingState || state == QBatteryInfo::Discharging)
796         return 0;
797
798     int remaining = 0;
799     QFile timeToFull(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("time_to_full_avg"));
800     if (timeToFull.open(QIODevice::ReadOnly)) {
801         bool ok = false;
802         remaining = timeToFull.readAll().simplified().toInt(&ok);
803         if (ok)
804             return remaining;
805         return -1;
806     }
807
808     int max = 0;
809     int current = 0;
810     if ((max = maximumCapacity(battery)) == -1
811         || (remaining = remainingCapacity(battery)) == -1
812         || (current = currentFlow(battery)) == 0) {
813         return -1;
814     }
815     return (max - remaining) * -3600 / current;
816 }
817
818 int QBatteryInfoPrivate::getVoltage(int battery)
819 {
820     QFile current(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("voltage_now"));
821     if (!current.open(QIODevice::ReadOnly))
822         return -1;
823
824     bool ok = false;
825     int voltage = current.readAll().simplified().toInt(&ok);
826     if (ok)
827         return voltage / 1000;
828     return -1;
829 }
830
831 QBatteryInfo::ChargerType QBatteryInfoPrivate::getChargerType()
832 {
833     QFile charger(*AC_ONLINE_SYSFS_PATH());
834     if (charger.open(QIODevice::ReadOnly)) {
835         char online;
836         if (charger.read(&online, 1) == 1 && online == '1')
837             return QBatteryInfo::WallCharger;
838         charger.close();
839     }
840
841     QMap<QString, QString> chargerMap;
842     chargerMap.insert(*USB0_PRESENT_SYSFS_PATH(), *USB0_TYPE_SYSFS_PATH());
843     chargerMap.insert(*USB_PRESENT_SYSFS_PATH(), *USB_TYPE_SYSFS_PATH());
844
845     QList<QString> presentPaths = chargerMap.keys();
846     foreach (const QString &presentPath, presentPaths) {
847         charger.setFileName(presentPath);
848         if (charger.open(QIODevice::ReadOnly)) {
849             char present;
850             if (charger.read(&present, 1) == 1 && present == '1') {
851                 charger.close();
852
853                 charger.setFileName(chargerMap.value(presentPath));
854                 if (charger.open(QIODevice::ReadOnly)) {
855                     if (charger.readAll().simplified() == "USB_DCP")
856                         return QBatteryInfo::WallCharger;
857                     return QBatteryInfo::USBCharger;
858                 }
859             }
860             charger.close();
861         }
862     }
863
864     return QBatteryInfo::UnknownCharger;
865 }
866
867 QBatteryInfo::ChargingState QBatteryInfoPrivate::getChargingState(int battery)
868 {
869     QFile state(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("status"));
870     if (!state.open(QIODevice::ReadOnly))
871         return QBatteryInfo::UnknownChargingState;
872
873     QByteArray status = state.readAll().simplified();
874     if (status == "Charging")
875         return QBatteryInfo::Charging;
876     else if (status == "Not charging")
877         return QBatteryInfo::IdleChargingState;
878     else if (status == "Discharging")
879         return QBatteryInfo::Discharging;
880     else if (status == "Full")
881         return QBatteryInfo::IdleChargingState;
882
883     return QBatteryInfo::UnknownChargingState;
884 }
885
886 QBatteryInfo::LevelStatus QBatteryInfoPrivate::getLevelStatus(int battery)
887 {
888     QFile levelStatusFile(BATTERY_SYSFS_PATH()->arg(battery) + QStringLiteral("capacity_level"));
889     if (!levelStatusFile.open(QIODevice::ReadOnly))
890         return QBatteryInfo::LevelUnknown;
891
892     QByteArray levelStatus = levelStatusFile.readAll().simplified();
893     if (qstrcmp(levelStatus, "Critical") == 0)
894         return QBatteryInfo::LevelEmpty;
895     else if (qstrcmp(levelStatus, "Low") == 0)
896         return QBatteryInfo::LevelLow;
897     else if (qstrcmp(levelStatus, "Normal") == 0)
898         return QBatteryInfo::LevelOk;
899     else if (qstrcmp(levelStatus, "Full") == 0)
900         return QBatteryInfo::LevelFull;
901
902     return QBatteryInfo::LevelUnknown;
903 }
904
905 QT_END_NAMESPACE