Commit 8def78cc authored by spiiroin's avatar spiiroin

Merge branch 'jb38667_battery_low_notifications' into 'master'

Rewrite battery notification logic

See merge request !118
parents aab8dd3a 07798de0
......@@ -27,6 +27,7 @@ BuildRequires: pkgconfig(Qt5Sensors)
BuildRequires: pkgconfig(contentaction5)
BuildRequires: pkgconfig(mlite5) >= 0.2.19
BuildRequires: pkgconfig(mce) >= 1.22.0
BuildRequires: pkgconfig(mce-qt5) >= 1.2.0
BuildRequires: pkgconfig(keepalive)
BuildRequires: pkgconfig(dsme_dbus_if) >= 0.63.2
BuildRequires: pkgconfig(thermalmanager_dbus_if)
......@@ -35,7 +36,6 @@ BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(libresourceqt5)
BuildRequires: pkgconfig(ngf-qt5)
BuildRequires: pkgconfig(contextkit-statefs) >= 0.2.7
BuildRequires: pkgconfig(systemd)
BuildRequires: pkgconfig(wayland-server)
BuildRequires: pkgconfig(usb-moded-qt5) >= 1.8
......
This diff is collapsed.
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2012,2015 Jolla Ltd.
** Copyright (C) 2012-2019 Jolla Ltd.
** Copyright (c) 2019 Open Mobile Platform LLC.
**
** Contact: Robin Burchell <robin.burchell@jollamobile.com>
**
** This file is part of lipstick.
......@@ -18,12 +20,18 @@
#include <QObject>
#include <QTimer>
#include <QScopedPointer>
#include <QStringList>
#include <QElapsedTimer>
class LowBatteryNotifier;
class ContextProperty;
#include <qmcechargertype.h>
#include <qmcechargerstate.h>
#include <qmcebatterystatus.h>
#include <qmcebatterylevel.h>
#include <qmcepowersavemode.h>
#include <qmcedisplay.h>
#include <qmcetklock.h>
#include <qmcecallstate.h>
#include <qusbmoded.h>
class NotificationManager;
class BackgroundActivity;
/*!
* Implements the configuration and state for the battery, the power save mode.
......@@ -45,8 +53,23 @@ public:
*/
virtual ~BatteryNotifier();
private slots:
void onNotificationClosed(uint id, uint reason);
void onChargerTypeChanged();
void onChargerStateChanged();
void onBatteryStatusChanged();
void onBatteryLevelChanged();
void onPowerSaveModeChanged();
void onDisplayChanged();
void onTkLockChanged();
void onCallStateChanged();
void onTargetUsbModeChanged();
void onBatteryLowTimeout();
void onChargingFailureTimeout();
void onEvaluateStateTimeout();
enum NotificationID {
private:
enum NotificationType {
NotificationCharging,
NotificationChargingComplete,
NotificationRemoveCharger,
......@@ -55,65 +78,39 @@ public:
NotificationEnteringPSM,
NotificationExitingPSM,
NotificationLowBattery,
NotificationNoEnoughPower
};
enum PropertyID {
PropertyFirst_ = 0,
PropertyLevel = PropertyFirst_,
PropertyState,
PropertyCharger,
PropertyLast_ = PropertyCharger
NotificationNotEnoughPower,
NotificationFirst = NotificationCharging,
NotificationLast = NotificationNotEnoughPower,
};
enum BatteryLevel {
BatteryNormal,
BatteryLow,
BatteryEmpty,
BatteryUnknown
};
enum ChargingState {
StateCharging,
StateDischarging,
StateIdle,
StateUnknown
};
enum ChargerType {
ChargerUnknown,
ChargerUsb,
ChargerWall,
ChargerNo
struct QueuedNotification {
NotificationType m_type;
uint m_id;
};
enum Mode {
ModeNormal,
ModePSM
struct State {
QMceChargerType::Type m_chargerType = QMceChargerType::None;
bool m_chargerState = false;
QMceBatteryStatus::Status m_batteryStatus = QMceBatteryStatus::Ok;
int m_batteryLevel = 50;
int m_minimumBatteryLevel = 0;
bool m_powerSaveMode = false;
QMceDisplay::State m_displayState = QMceDisplay::DisplayOn;
bool m_tkLock = false;
QMceCallState::State m_callState = QMceCallState::None;
QMceCallState::Type m_callType = QMceCallState::Normal;
QString m_usbMode;
bool m_suppressCharging = false;
};
public slots:
//! Sends a low battery notification
void lowBatteryAlert();
typedef QSet<NotificationType> NotificationTypeSet;
typedef QList<NotificationType> NotificationTypeList;
/*!
* Sets the touch screen lock active state so notifications can be enabled/disabled based on that.
*
* \param active \c true if the touch screen lock is active, \c false otherwise
*/
void setTouchScreenLockActive(bool active);
private slots:
void initBattery();
void onPowerSaveModeChanged();
void onPropertyChanged();
void prepareNotification();
void checkIsChargingStarted();
private:
//! Sends a notification based on the notification ID
void sendNotification(BatteryNotifier::NotificationID id);
//! Sends a notification based on the notification type
void sendNotification(BatteryNotifier::NotificationType type);
//! Removes the current notification if its type is one listed in eventTypes
typedef QSet<NotificationID> NotificationList;
void removeNotification(const NotificationList &);
//! Removes any active notifications in the given type set
void removeNotifications(const NotificationTypeSet &toRemove);
//! Starts the low battery notifier if not already started
void startLowBatteryNotifier();
......@@ -121,71 +118,36 @@ private:
//! Stops the low battery notifier if not already stopped
void stopLowBatteryNotifier();
BatteryLevel getLevel() const;
ChargingState getState() const;
ChargerType getCharger() const;
//! Adjust delay for the next repeated low battery warning
void updateLowBatteryNotifier();
/*! Determines whether the current device is a USB device that will by
* handled by usb_moded.
*
* \returns true if the device will be handled by usb_moded, false o/w.
*/
bool isUsbDevice() const;
static bool notificationTriggeringEdge(NotificationType type);
static bool evaluateNotificationLevel(NotificationType type,
const State &state);
void evaluateNotificationTriggering(NotificationType type,
const State &previousState,
const State &currentState,
NotificationTypeSet &toRemove,
NotificationTypeList &toSend);
void updateDerivedProperties();
void scheduleStateEvaluation();
//! Low battery notifier for getting notifications about low battery state
LowBatteryNotifier *m_lowBatteryNotifier;
struct QueuedNotification {
uint number;
NotificationID id;
qint64 time;
};
/*! There can be several queued notifications (e.g. psm and
* charging one at the same time) and the only one should be
* cancelled
*/
QList<QueuedNotification> m_notifications;
//! Timer for checking whether the current notification can be removed or not
QElapsedTimer m_timeline;
//! Whether the touch screen lock is active or not
bool m_touchScreenLockActive;
ContextProperty *m_batteryLevel;
ContextProperty *m_chargingState;
ContextProperty *m_chargerType;
//! To get device mode
ContextProperty *m_psm;
struct State {
BatteryLevel level;
ChargingState state;
ChargerType charger;
};
State m_lastState;
Mode m_mode;
enum ChargingCompletion {
NeedsCharging,
FullyCharged
};
ChargingCompletion m_chargingCompletion;
/*! Notification is postponed by means of this timer to skip
* frequent state changes during energy management state
* changes
*/
QTimer m_preNotificationTimer;
/*! used if charging is not signaled as started immediately after
* charger is inserted to check is it finally started
*/
QScopedPointer<QTimer> m_checkChargingTimer;
#ifdef UNIT_TEST
friend class Ut_BatteryNotifier;
#endif
QTimer m_evaluateStateTimer;
QTimer m_chargingFailureTimer;
State m_currentState;
State m_previousState;
int m_lowBatteryRepeatLevel;
NotificationManager *m_notificationManager;
QMceChargerType *m_mceChargerType;
QMceChargerState *m_mceChargerState;
QMceBatteryStatus *m_mceBatteryStatus;;
QMceBatteryLevel *m_mceBatteryLevel;
QMcePowerSaveMode *m_mcePowerSaveMode;
QMceDisplay *m_mceDisplay;
QMceTkLock *m_mceTkLock;
QMceCallState *m_mceCallState;
QUsbModed *m_usbModed;
BackgroundActivity *m_lowBatteryRepeatActivity;
};
#endif
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of systemui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "lowbatterynotifier.h"
#include <QTimer>
static const int CALL_ACTIVE_NOTIFICATION_INTERVAL = 2 * 60 * 1000;
static const int DEVICE_ACTIVE_NOTIFICATION_INTERVAL = 5 * 60 * 1000;
static const int DEVICE_INACTIVE_NOTIFICATION_INTERVAL = 30 * 60 * 1000;
LowBatteryNotifier::LowBatteryNotifier(QObject *parent) :
QObject(parent),
m_displayState(new MeeGo::QmDisplayState(this)),
#ifdef HAVE_CONTEXTSUBSCRIBER
m_callContextItem("Phone.Call"),
#endif
m_notificationTimer(new QTimer(this)),
m_previousNotificationTime(QTime::currentTime()),
m_notificationInterval(DEVICE_ACTIVE_NOTIFICATION_INTERVAL),
m_deviceInactive(false),
m_touchScreenLockActive(false),
m_callActive(false)
{
connect(m_notificationTimer, SIGNAL(timeout()), this, SLOT(sendLowBatteryAlert()));
setNotificationInterval();
connect(m_displayState, SIGNAL(displayStateChanged(MeeGo::QmDisplayState::DisplayState)), this, SLOT(setNotificationInterval()));
#ifdef HAVE_CONTEXTSUBSCRIBER
connect(&m_callContextItem, SIGNAL(valueChanged()), this, SLOT(setNotificationInterval()));
m_callContextItem.subscribe();
#endif
}
LowBatteryNotifier::~LowBatteryNotifier()
{
}
void LowBatteryNotifier::sendLowBatteryAlert()
{
emit lowBatteryAlert();
m_previousNotificationTime.start();
m_notificationTimer->start(m_notificationInterval);
}
void LowBatteryNotifier::setNotificationInterval()
{
bool deviceCurrentlyInactive = m_touchScreenLockActive;
#ifdef HAVE_CONTEXTSUBSCRIBER
bool callCurrentlyActive = m_callContextItem.value().toString() == "active";
#else
bool callCurrentlyActive = false;
#endif
// Device can be considered inactive only if the touch screen lock is active AND the display is off
deviceCurrentlyInactive &= m_displayState->get() == MeeGo::QmDisplayState::Off;
if (deviceCurrentlyInactive != m_deviceInactive || callCurrentlyActive != m_callActive) {
// Device activity or call activity has changed
m_deviceInactive = deviceCurrentlyInactive;
m_callActive = callCurrentlyActive;
// Set the new notification interval based on the device and call state
if (m_callActive) {
m_notificationInterval = CALL_ACTIVE_NOTIFICATION_INTERVAL;
} else {
m_notificationInterval = m_deviceInactive ? DEVICE_INACTIVE_NOTIFICATION_INTERVAL : DEVICE_ACTIVE_NOTIFICATION_INTERVAL;
}
if (m_previousNotificationTime.elapsed() < m_notificationInterval) {
// Elapsed time has not reached the notification interval so just set the new interval
m_notificationTimer->setInterval(m_notificationInterval - m_previousNotificationTime.elapsed());
} else {
// Elapsed time has reached the notification interval, so send the notification immediately (which will also set the new interval)
sendLowBatteryAlert();
}
}
}
void LowBatteryNotifier::setTouchScreenLockActive(bool active)
{
m_touchScreenLockActive = active;
setNotificationInterval();
}
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary (-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of systemui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#ifndef LOWBATTERYNOTIFIER_H
#define LOWBATTERYNOTIFIER_H
#include <QObject>
#include <QTime>
#include <qmdisplaystate.h>
#ifdef HAVE_CONTEXTSUBSCRIBER
#include <contextproperty.h>
#endif
class QTimer;
/*!
* The LowBatteryNotifier will emit a lowBatteryAlert() when the user should
* be alerted about a low battery condition.
*/
class LowBatteryNotifier : public QObject
{
Q_OBJECT
public:
/*!
* Creates a low battery notifier.
*/
LowBatteryNotifier(QObject *parent = NULL);
/*!
* Destroys the low battery notifier.
*/
virtual ~LowBatteryNotifier();
/*!
* Sets the touch screen lock active state so notifications can be enabled/disabled based on that.
*
* \param active \c true if the touch screen lock is active, \c false otherwise
*/
void setTouchScreenLockActive(bool active);
public slots:
//! Requests a low battery notification to be shown
void sendLowBatteryAlert();
private slots:
//! Sets the notification interval based on the device activity state
void setNotificationInterval();
signals:
//! Sent when the user should be notified about a low battery state
void lowBatteryAlert();
private:
//! For getting the display state
MeeGo::QmDisplayState *m_displayState;
#ifdef HAVE_CONTEXTSUBSCRIBER
//! Call state context framework key
ContextProperty m_callContextItem;
#endif
//! Timer for sending low battery alerts
QTimer *m_notificationTimer;
//! Time of the previous notification
QTime m_previousNotificationTime;
//! Notification interval in milliseconds based on the device and call state
int m_notificationInterval;
//! Whether the device is currently inactive or not
bool m_deviceInactive;
//! Whether the touch screen lock is active or not
bool m_touchScreenLockActive;
//! Whether a call is in progress or not
bool m_callActive;
#ifdef UNIT_TEST
friend class Ut_LowBatteryNotifier;
#endif
};
#endif
/***************************************************************************
**
** Copyright (C) 2012 Jolla Ltd.
** Copyright (C) 2012-2019 Jolla Ltd.
** Copyright (c) 2019 Open Mobile Platform LLC.
**
** Contact: Robin Burchell <robin.burchell@jollamobile.com>
**
** This file is part of lipstick.
......@@ -498,19 +500,19 @@ QString NotificationManager::systemApplicationName() const
uint NotificationManager::nextAvailableNotificationID()
{
bool idIncreased = false;
// Try to find an unused ID. Increase the ID at least once but only up to 2^32-1 times.
for (uint i = 0; i < UINT32_MAX && (!idIncreased || m_notifications.contains(m_previousNotificationID)); i++, idIncreased = true) {
m_previousNotificationID++;
if (m_previousNotificationID == 0) {
// 0 is not a valid ID so skip it
m_previousNotificationID = 1;
}
/* Find an unused ID. It is assumed that we will never end up
* in a situation where even close to significant portion of
* all possible ID numbers would be in use. If that ever happens
* this will turn into forever loop.
*/
for (;;) {
uint id = ++m_previousNotificationID;
// 0 is not a valid ID so skip it
if (!id)
continue;
if (!m_notifications.contains(id))
return id;
}
return m_previousNotificationID;
}
void NotificationManager::removeNotificationsWithCategory(const QString &category)
......
......@@ -68,7 +68,6 @@ HEADERS += \
notifications/notificationmanageradaptor.h \
notifications/categorydefinitionstore.h \
notifications/batterynotifier.h \
notifications/lowbatterynotifier.h \
notifications/notificationfeedbackplayer.h \
notifications/androidprioritystore.h \
screenlock/screenlock.h \
......@@ -112,7 +111,6 @@ SOURCES += \
notifications/notificationlistmodel.cpp \
notifications/notificationpreviewpresenter.cpp \
notifications/batterynotifier.cpp \
notifications/lowbatterynotifier.cpp \
notifications/androidprioritystore.cpp \
screenlock/screenlock.cpp \
screenlock/screenlockadaptor.cpp \
......@@ -141,7 +139,6 @@ SOURCES += \
CONFIG += link_pkgconfig mobility qt warn_on depend_includepath qmake_cache target_qt
CONFIG -= link_prl
PKGCONFIG += \
contextkit-statefs \
dbus-1 \
dbus-glib-1 \
dsme_dbus_if \
......@@ -150,6 +147,7 @@ PKGCONFIG += \
libsystemd-daemon \
mlite5 \
mce \
mce-qt5 \
nemodevicelock \
ngf-qt5 \
Qt5SystemInfo \
......@@ -167,13 +165,6 @@ packagesExist(contentaction5) {
warning("contentaction doesn't exist; falling back to exec - this may not work so great")
}
packagesExist(contextkit-statefs) {
PKGCONFIG += contextkit-statefs
DEFINES += HAVE_CONTEXTSUBSCRIBER
} else {
warning("Contextsubscriber not found")
}
QT += dbus xml qml quick sql gui gui-private sensors
QMAKE_CXXFLAGS += \
......
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2012-2015 Jolla Ltd.
** Copyright (C) 2012-2019 Jolla Ltd.
** Copyright (c) 2019 Open Mobile Platform LLC.
**
** Contact: Robin Burchell <robin.burchell@jollamobile.com>
**
** This file is part of lipstick.
......@@ -17,7 +19,6 @@
#include <QQmlContext>
#include <QScreen>
#include <qusbmoded.h>
#include <contextproperty.h>
#include "homewindow.h"
#include "utilities/closeeventeater.h"
#include "notifications/notificationmanager.h"
......@@ -27,19 +28,12 @@
#include <nemo-devicelock/devicelock.h>
static inline QString propertyString(ContextProperty *p)
{
return p->value().toString().trimmed();
}
USBModeSelector::USBModeSelector(NemoDeviceLock::DeviceLock *deviceLock, QObject *parent) :
QObject(parent),
m_usbMode(new QUsbModed(this)),
m_deviceLock(deviceLock),
m_windowVisible(false),
m_preparingMode(),
m_chargingState(new ContextProperty("Battery.ChargingState", this)),
m_needsCharging(true)
m_preparingMode()
{
connect(m_usbMode, &QUsbModed::eventReceived, this, &USBModeSelector::handleUSBEvent);
connect(m_usbMode, &QUsbModed::currentModeChanged, this, &USBModeSelector::handleUSBState);
......@@ -47,11 +41,9 @@ USBModeSelector::USBModeSelector(NemoDeviceLock::DeviceLock *deviceLock, QObject
connect(m_usbMode, SIGNAL(usbStateError(QString)), this, SIGNAL(showError(QString)));
connect(m_usbMode, SIGNAL(supportedModesChanged()), this, SIGNAL(supportedModesChanged()));
connect(m_usbMode, &QUsbModed::availableModesChanged, this, &USBModeSelector::availableModesChanged);
connect(m_chargingState, &ContextProperty::valueChanged, this, &USBModeSelector::batteryStateChanged);
// Lazy initialize to improve startup time
QTimer::singleShot(500, this, &USBModeSelector::handleUSBState);
QTimer::singleShot(500, this, &USBModeSelector::batteryStateChanged);
}
void USBModeSelector::setWindowVisible(bool visible)
......@@ -103,10 +95,6 @@ void USBModeSelector::handleUSBEvent(const QString &event)
} else if (event == QUsbMode::Mode::ChargerConnected) {
// Hide the mode selection dialog and show a mode notification
setWindowVisible(false);
// Check and notification originally from batterynotifier.cpp
if (chargingAndNotFull()) {
emit showNotification(Notification::Charging);
}
}
}
......@@ -118,6 +106,7 @@ void USBModeSelector::handleUSBState()
// Diag, Adb, PCSuite, Charging, Charger, ChargingFallback, Busy
QString mode = m_usbMode->currentMode();
USBModeSelector::Notification type = Notification::Invalid;
updateModePreparing();
......@@ -125,22 +114,18 @@ void USBModeSelector::handleUSBState()
// This probably isn't necessary, as it'll be handled by ModeRequest
setWindowVisible(true);
} else if (mode == QUsbMode::Mode::ChargingFallback) {
// Check and notification originally from batterynotifier.cpp
if (chargingAndNotFull()) {
emit showNotification(Notification::Charging);
}
// Do nothing
} else if (mode == QUsbMode::Mode::Charging) {
// Hide the mode selection dialog and show a mode notification
setWindowVisible(false);
// Check and notification originally from batterynotifier.cpp
if (chargingAndNotFull()) {
emit showNotification(Notification::Charging);
}
} else if (QUsbMode::isFinalState(mode)) {
// Hide the mode selection dialog and show a mode notification
setWindowVisible(false);
emit showNotification(convertModeToNotification(mode));
type = convertModeToNotification(mode);
}
if (type != Notification::Invalid && type != Notification::Charging)
emit showNotification(type);
}
void USBModeSelector::setMode(const QString &mode)
......@@ -199,7 +184,7 @@ QUsbModed * USBModeSelector::getUsbModed()
USBModeSelector::Notification USBModeSelector::convertModeToNotification(const QString &mode) const
{
Notification type;
Notification type = Notification::Invalid;
if (mode == QUsbModed::Mode::Disconnected) {
type = Notification::Disconnected;
......@@ -219,31 +204,7 @@ USBModeSelector::Notification USBModeSelector::convertModeToNotification(const Q
type = Notification::Diag;
} else if (mode == QUsbModed::Mode::Host) {
type = Notification::Host;
} else if ((mode == QUsbMode::Mode::ChargingFallback) ||
(mode == QUsbMode::Mode::Charging) ||
(mode == QUsbMode::Mode::ChargerConnected)) {
type = Notification::Charging;
} else {
type = Notification::Invalid;
}
return type;
}
bool USBModeSelector::chargingAndNotFull()
{
QString name(propertyString(m_chargingState));
return (name == "charging") && m_needsCharging;
}
void USBModeSelector::batteryStateChanged()
{
QString name(propertyString(m_chargingState));
if (!(name == "charging" || name == "idle")) {
m_needsCharging = true;
} else if (name == "idle") {
m_needsCharging = false;
}
}
/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2012-2015 Jolla Ltd.
** Copyright (C) 2012-2019 Jolla Ltd.
** Copyright (c) 2019 Open Mobile Platform LLC.
**
** Contact: Robin Burchell <robin.burchell@jollamobile.com>
**
** This file is part of lipstick.
......@@ -22,7 +24,6 @@
class HomeWindow;
class QUsbModed;
class ContextProperty;
namespace NemoDeviceLock {
class DeviceLock;
......@@ -191,24 +192,6 @@ private:
*/
void updateModePreparing();
/*!
* Callback triggered by a change in state of the statefs
* "Battery.ChargingState" context property. This allows us to decide
* whether or not the battery needs charging, or is fully charged.
* The derived result is stored in \l m_needsCharging and accessed
* using \l chargingAndNotFull().
*/
void batteryStateChanged();
/*!
* Used to determine whether or not the charge is increasing in the
* battery. This is equivalent to the battery being in a charging state,
* and not yet fullly charged.
*
* \returns true if the battery is charging and not full, false o/w.
*/
bool chargingAndNotFull();
private:
//! For getting and setting the USB mode
QUsbModed *m_usbMode;
......@@ -222,12 +205,6 @@ private:
//! State indicating whether the device is preparing a USB mode or not
QString m_preparingMode;
//! Charging state obtained from statefs, used to derive \c m_needsCharging.
ContextProperty *m_chargingState;