diff options
21 files changed, 566 insertions, 188 deletions
diff --git a/ckitcallnotification/ckitcallnotification.cpp b/ckitcallnotification/ckitcallnotification.cpp new file mode 100644 index 0000000..72a768e --- /dev/null +++ b/ckitcallnotification/ckitcallnotification.cpp @@ -0,0 +1,52 @@ +#include "ckitcallnotification.h" + +using namespace sowatch; + +CKitCallNotification::CKitCallNotification(const QString& displayName, QObject *parent) : + Notification(parent), + _dateTime(QDateTime::currentDateTime()), + _displayName(displayName) +{ +} + +Notification::Type CKitCallNotification::type() const +{ + return Notification::CallNotification; +} + +uint CKitCallNotification::count() const +{ + return 1; +} + +QDateTime CKitCallNotification::dateTime() const +{ + return _dateTime; +} + +QString CKitCallNotification::title() const +{ + return _displayName; +} + +QString CKitCallNotification::body() const +{ + return tr("Incoming call"); +} + +void CKitCallNotification::activate() +{ + // TODO Actually do something +} + +void CKitCallNotification::clear() +{ + // TODO Actually reject the call + emit cleared(); +} + +void CKitCallNotification::changeDisplayName(const QString &displayName) +{ + _displayName = displayName; + emit changed(); +} diff --git a/ckitcallnotification/ckitcallnotification.h b/ckitcallnotification/ckitcallnotification.h new file mode 100644 index 0000000..10453be --- /dev/null +++ b/ckitcallnotification/ckitcallnotification.h @@ -0,0 +1,40 @@ +#ifndef CKITCALLNOTIFICATION_H +#define CKITCALLNOTIFICATION_H + +#include <sowatch.h> + +namespace sowatch +{ + +class CKitCallProvider; + +class CKitCallNotification : public Notification +{ + Q_OBJECT +public: + explicit CKitCallNotification(const QString& displayName, QObject *parent = 0); + + Type type() const; + uint count() const; + QDateTime dateTime() const; + QString title() const; + QString body() const; + + void activate(); + void clear(); + +signals: + void changed(); + void cleared(); + +protected: + QDateTime _dateTime; + QString _displayName; + void changeDisplayName(const QString& displayName); + + friend class CKitCallProvider; +}; + +} + +#endif // CKITCALLNOTIFICATION_H diff --git a/ckitcallnotification/ckitcallnotification.pro b/ckitcallnotification/ckitcallnotification.pro index 17bdf8b..2cee7f8 100644 --- a/ckitcallnotification/ckitcallnotification.pro +++ b/ckitcallnotification/ckitcallnotification.pro @@ -10,10 +10,12 @@ TEMPLATE = lib QT += dbus SOURCES += ckitcallplugin.cpp \ - ckitcallprovider.cpp + ckitcallprovider.cpp \ + ckitcallnotification.cpp HEADERS += ckitcallplugin.h \ - ckitcallprovider.h + ckitcallprovider.h \ + ckitcallnotification.h CONFIG += link_pkgconfig PKGCONFIG += contextsubscriber-1.0 @@ -35,3 +37,5 @@ unix:!symbian { + + diff --git a/ckitcallnotification/ckitcallprovider.cpp b/ckitcallnotification/ckitcallprovider.cpp index 85f85b2..adcb6d5 100644 --- a/ckitcallnotification/ckitcallprovider.cpp +++ b/ckitcallnotification/ckitcallprovider.cpp @@ -1,16 +1,16 @@ #include <QtCore/QtDebug> #include <contextsubscriber/contextproperty.h> +#include "ckitcallnotification.h" #include "ckitcallprovider.h" using namespace sowatch; CKitCallProvider::CKitCallProvider(QObject *parent) : NotificationProvider(parent), - _inCall(false), - _activeCall(new ContextProperty("/com/nokia/CallUi/ActiveCall")) + _activeCall(new ContextProperty("/com/nokia/CallUi/ActiveCall")), + _notification(0) { connect(_activeCall, SIGNAL(valueChanged()), SLOT(activeCallChanged())); - qDebug() << _activeCall->value(); } CKitCallProvider::~CKitCallProvider() @@ -18,23 +18,25 @@ CKitCallProvider::~CKitCallProvider() } -int CKitCallProvider::getCount(Notification::Type type) -{ - Q_UNUSED(type); - return 0; -} - void CKitCallProvider::activeCallChanged() { QVariantMap info = _activeCall->value().toMap(); int state = info["state"].toInt(); if (state == 0) { - // Incoming call, or update to a incoming call - _inCall = true; - emit incomingCall(info["displayName"].toString()); - } else if (_inCall) { - // Call is no longer incoming - _inCall = false; - emit endIncomingCall(); + QString displayName = info["displayName"].toString(); + // "Incoming call" + if (_notification) { + _notification->changeDisplayName(displayName); + } else { + _notification = new CKitCallNotification(displayName, this); + emit incomingNotification(_notification); + } + } else { + // Call is either answered, dropped, missed, .. + if (_notification) { + _notification->clear(); + _notification->deleteLater(); + _notification = 0; + } } } diff --git a/ckitcallnotification/ckitcallprovider.h b/ckitcallnotification/ckitcallprovider.h index 49d83a3..1e1d289 100644 --- a/ckitcallnotification/ckitcallprovider.h +++ b/ckitcallnotification/ckitcallprovider.h @@ -8,6 +8,8 @@ class ContextProperty; namespace sowatch { +class CKitCallNotification; + class CKitCallProvider : public NotificationProvider { Q_OBJECT @@ -15,15 +17,12 @@ public: explicit CKitCallProvider(QObject *parent = 0); ~CKitCallProvider(); - int getCount(Notification::Type type); - signals: - void incomingCall(const QString &displayName); - void endIncomingCall(); + void incomingNotification(Notification *notification); protected: - bool _inCall; ContextProperty *_activeCall; + CKitCallNotification *_notification; protected slots: void activeCallChanged(); diff --git a/libsowatch/notification.cpp b/libsowatch/notification.cpp index 55f3e78..b4c97b2 100644 --- a/libsowatch/notification.cpp +++ b/libsowatch/notification.cpp @@ -2,12 +2,16 @@ using namespace sowatch; -Notification::Notification(Type type, const QDateTime& dateTime, QString title, QString body) - : _type(type), _dateTime(dateTime), _title(title), _body(body) +Notification::Notification(QObject *parent) + : QObject(parent) { } Notification::~Notification() { +} +QImage Notification::image() const +{ + return QImage(); } diff --git a/libsowatch/notification.h b/libsowatch/notification.h index 7a46ab7..8e58653 100644 --- a/libsowatch/notification.h +++ b/libsowatch/notification.h @@ -3,16 +3,21 @@ #include <QtCore/QString> #include <QtCore/QDateTime> +#include <QtGui/QImage> #include "sowatch_global.h" namespace sowatch { -class SOWATCH_EXPORT Notification +class SOWATCH_EXPORT Notification : public QObject { + Q_OBJECT + Q_ENUMS(Type) + public: enum Type { OtherNotification = 0, + CallNotification, MissedCallNotification, SmsNotification, MmsNotification, @@ -22,19 +27,23 @@ public: TypeCount }; - Notification(Type type, const QDateTime& dateTime, QString title, QString body); - ~Notification(); + explicit Notification(QObject *parent = 0); + virtual ~Notification(); + + virtual Type type() const = 0; + virtual uint count() const = 0; + virtual QDateTime dateTime() const = 0; + virtual QString title() const = 0; + virtual QString body() const = 0; + virtual QImage image() const; - inline Type type() const { return _type; } - inline QDateTime dateTime() const { return _dateTime; } - inline QString title() const { return _title; } - inline QString body() const { return _body; } +public slots: + virtual void activate() = 0; + virtual void clear() = 0; -protected: - Type _type; - QDateTime _dateTime; - QString _title; - QString _body; +signals: + void changed(); + void cleared(); }; } diff --git a/libsowatch/notificationprovider.h b/libsowatch/notificationprovider.h index fe835ef..31182f1 100644 --- a/libsowatch/notificationprovider.h +++ b/libsowatch/notificationprovider.h @@ -15,17 +15,8 @@ protected: explicit NotificationProvider(QObject *parent = 0); virtual ~NotificationProvider(); -public: - virtual int getCount(Notification::Type type) = 0; - signals: - void notification(const Notification& n); - void unreadCountChanged(Notification::Type type); - - void weatherUpdate(); - - void incomingCall(const QString& displayName); - void endIncomingCall(); + void incomingNotification(Notification* notification); }; } diff --git a/libsowatch/watch.h b/libsowatch/watch.h index 5552a8c..eabfa06 100644 --- a/libsowatch/watch.h +++ b/libsowatch/watch.h @@ -21,28 +21,38 @@ public: explicit Watch(QObject* parent = 0); ~Watch(); + /** Return a string identiyfying this watch's model. */ virtual QString model() const = 0; + /** Should return true if the watch is connected. */ virtual bool isConnected() const = 0; /** Indicates if watch is too busy atm and we should limit frame rate. */ virtual bool busy() const = 0; + /** Changes the current date/time on the watch. */ virtual QDateTime dateTime() = 0; virtual void setDateTime(const QDateTime& dateTime) = 0; + /** Tells the watch to update the unread notifications count, if visible. */ virtual void updateNotificationCount(Notification::Type type, int count) = 0; signals: + /** The watch has been found and linked to. */ void connected(); + /** The watch connection has been lost. */ void disconnected(); + /** The watch has returned to the idle screen by either inactivity or notification cleared/timeout. */ + void idling(); void buttonPressed(int button); void buttonReleased(int button); public slots: - virtual void vibrate(bool on) = 0; - virtual void showNotification(const Notification& n) = 0; - virtual void startRinging(const QString& text) = 0; - virtual void stopRinging() = 0; + /** Go back to the idle screen. */ + virtual void displayIdleScreen() = 0; + /** A standard notification; it's up to the watch when to stop showing it. */ + virtual void displayNotification(Notification* n) = 0; + /** Enter application mode. */ + virtual void displayApplication() = 0; }; } diff --git a/libsowatch/watchserver.cpp b/libsowatch/watchserver.cpp index 942131f..d95d4fb 100644 --- a/libsowatch/watchserver.cpp +++ b/libsowatch/watchserver.cpp @@ -13,6 +13,7 @@ WatchServer::WatchServer(Watch* watch, QObject* parent) : { connect(_watch, SIGNAL(connected()), SLOT(watchConnected())); connect(_watch, SIGNAL(disconnected()), SLOT(watchDisconnected())); + connect(_watch, SIGNAL(idling()), SLOT(watchIdling())); } Watch* WatchServer::watch() @@ -23,13 +24,8 @@ Watch* WatchServer::watch() void WatchServer::addProvider(NotificationProvider *provider) { provider->setParent(this); - - connect(provider, SIGNAL(notification(Notification)), SLOT(notificationEmitted(Notification))); - connect(provider, SIGNAL(unreadCountChanged(Notification::Type)), SLOT(unreadCountUpdated(Notification::Type))); - connect(provider, SIGNAL(incomingCall(QString)), SLOT(incomingCall(QString))); - connect(provider, SIGNAL(endIncomingCall()), SLOT(endIncomingCall())); - - _providers.append(provider); + connect(provider, SIGNAL(incomingNotification(Notification*)), SLOT(notificationReceived(Notification*))); + // And that's it, really. } void WatchServer::runWatchlet(const QString& id) @@ -39,7 +35,7 @@ void WatchServer::runWatchlet(const QString& id) } _currentWatchlet = _watchlets[id]; if (_watch->isConnected()) { - _currentWatchlet->activate(); + reactivateCurrentWatchlet(); } } @@ -58,10 +54,41 @@ void WatchServer::registerWatchlet(Watchlet *watchlet) _watchlets[watchlet->id()] = watchlet; } +void WatchServer::reactivateCurrentWatchlet() +{ + Q_ASSERT(_currentWatchlet != 0); + _watch->displayApplication(); + _currentWatchlet->activate(); +} + +void WatchServer::nextNotification() +{ + if (!_watch->isConnected()) return; + if (!_pendingNotifications.empty()) { + Notification *n = _pendingNotifications.head(); + _watch->displayNotification(n); + } else if (_currentWatchlet) { + reactivateCurrentWatchlet(); + } else { + _watch->displayIdleScreen(); + } +} + +uint WatchServer::getNotificationCount(Notification::Type type) +{ + uint count = 0; + foreach (Notification* n, _notifications[type]) { + count += n->count(); + } + return count; +} + void WatchServer::watchConnected() { - if (_currentWatchlet) { - _currentWatchlet->activate(); + if (!_pendingNotifications.isEmpty()) { + nextNotification(); + } else if (_currentWatchlet) { + reactivateCurrentWatchlet(); } } @@ -70,30 +97,73 @@ void WatchServer::watchDisconnected() if (_currentWatchlet) { _currentWatchlet->deactivate(); } + _pendingNotifications.clear(); } -void WatchServer::notificationEmitted(const Notification ¬ification) +void WatchServer::watchIdling() { - // TODO app loses button focus... - _watch->showNotification(notification); + qDebug() << "Watch idling"; + if (!_pendingNotifications.empty()) { + _pendingNotifications.dequeue(); + nextNotification(); + } } -void WatchServer::unreadCountUpdated(Notification::Type type) +void WatchServer::notificationReceived(Notification *notification) { - uint count = 0; - foreach(NotificationProvider* provider, _providers) - { - count += provider->getCount(type); + const Notification::Type type = notification->type(); + _notifications[type].append(notification); + + connect(notification, SIGNAL(changed()), SLOT(notificationChanged())); + connect(notification, SIGNAL(cleared()), SLOT(notificationCleared())); + + qDebug() << "notification received" << notification->title() << notification->count(); + + _watch->updateNotificationCount(type, getNotificationCount(type)); + if (_pendingNotifications.isEmpty()) { + _pendingNotifications.enqueue(notification); + nextNotification(); + } else if (type == Notification::CallNotification) { + // Oops, priority!!!! + _pendingNotifications.prepend(notification); + nextNotification(); + } else { + _pendingNotifications.enqueue(notification); } - _watch->updateNotificationCount(type, count); } -void WatchServer::incomingCall(const QString &displayText) +void WatchServer::notificationChanged() { - qDebug() << "Incoming call" << displayText; + QObject *obj = sender(); + if (obj) { + Notification* n = static_cast<Notification*>(obj); + const Notification::Type type = n->type(); + + qDebug() << "notification changed" << n->title() << n->count(); + + _watch->updateNotificationCount(type, getNotificationCount(type)); + if (!_pendingNotifications.isEmpty() && _pendingNotifications.head() == n) { + nextNotification(); + } + } } -void WatchServer::endIncomingCall() +void WatchServer::notificationCleared() { - qDebug() << "End incoming call"; + QObject *obj = sender(); + if (obj) { + Notification* n = static_cast<Notification*>(obj); + const Notification::Type type = n->type(); + _notifications[type].removeOne(n); + + qDebug() << "notification deleted" << n->title() << n->count(); + + _watch->updateNotificationCount(type, getNotificationCount(type)); + if (!_pendingNotifications.isEmpty() && _pendingNotifications.head() == n) { + _pendingNotifications.removeAll(n); + nextNotification(); + } else { + _pendingNotifications.removeAll(n); + } + } } diff --git a/libsowatch/watchserver.h b/libsowatch/watchserver.h index 27d29aa..1ece104 100644 --- a/libsowatch/watchserver.h +++ b/libsowatch/watchserver.h @@ -1,9 +1,9 @@ #ifndef SOWATCH_WATCHSERVER_H #define SOWATCH_WATCHSERVER_H -#include <QtCore/QObject> +#include <QtCore/QList> #include <QtCore/QMap> -#include <QtCore/QSignalMapper> +#include <QtCore/QQueue> #include "sowatch_global.h" #include "notification.h" @@ -32,20 +32,28 @@ public: protected: Watch* _watch; - Watchlet* _currentWatchlet; QMap<QString, Watchlet*> _watchlets; - QList<NotificationProvider*> _providers; + + /** Stores current notifications, classified by type. */ + QList<Notification*> _notifications[Notification::TypeCount]; + QQueue<Notification*> _pendingNotifications; + + Watchlet* _currentWatchlet; void registerWatchlet(Watchlet *watchlet); + void reactivateCurrentWatchlet(); + + void nextNotification(); + uint getNotificationCount(Notification::Type type); protected slots: void watchConnected(); void watchDisconnected(); - void notificationEmitted(const Notification& notification); - void unreadCountUpdated(Notification::Type type); - void incomingCall(const QString& displayText); - void endIncomingCall(); + void watchIdling(); + void notificationReceived(Notification* notification); + void notificationChanged(); + void notificationCleared(); friend class Watchlet; }; diff --git a/meegohandsetnotification/meegohandsetnotification.cpp b/meegohandsetnotification/meegohandsetnotification.cpp new file mode 100644 index 0000000..69e2bd5 --- /dev/null +++ b/meegohandsetnotification/meegohandsetnotification.cpp @@ -0,0 +1,61 @@ +#include "meegohandsetnotification.h" + +MeegoHandsetNotification::MeegoHandsetNotification(const ::Notification& n, QObject *parent) : + sowatch::Notification(parent), _n(n) +{ +} + +sowatch::Notification::Type MeegoHandsetNotification::type() const +{ + QString eventType = _n.parameters().value("eventType").toString(); + if (eventType == "email.arrived") + return sowatch::Notification::EmailNotification; + else if (eventType == "x-nokia.call.missed") + return sowatch::Notification::MissedCallNotification; + else if (eventType == "x-nokia.messaging.im") + return sowatch::Notification::ImNotification; + else if (eventType == "x-nokia.messaging.sms") + return sowatch::Notification::SmsNotification; + else if (eventType == "x-nokia.messaging.mms") + return sowatch::Notification::MmsNotification; + else + return sowatch::Notification::OtherNotification; +} + +uint MeegoHandsetNotification::count() const +{ + return _n.parameters().value("count").toUInt(); +} + +QDateTime MeegoHandsetNotification::dateTime() const +{ + const uint timestamp = _n.parameters().value("timestamp").toUInt(); + return QDateTime::fromTime_t(timestamp); +} + +QString MeegoHandsetNotification::title() const +{ + return _n.parameters().value("summary").toString(); +} + +QString MeegoHandsetNotification::body() const +{ + return _n.parameters().value("body").toString(); +} + +void MeegoHandsetNotification::activate() +{ + // TODO Actually do something +} + +void MeegoHandsetNotification::clear() +{ + // TODO Actually clear... + emit cleared(); +} + +void MeegoHandsetNotification::changeTo(const ::Notification ¬ification) +{ + _n = notification; + emit changed(); +} diff --git a/meegohandsetnotification/meegohandsetnotification.h b/meegohandsetnotification/meegohandsetnotification.h new file mode 100644 index 0000000..fc9d50f --- /dev/null +++ b/meegohandsetnotification/meegohandsetnotification.h @@ -0,0 +1,37 @@ +#ifndef MEEGOHANDSETNOTIFICATION_H +#define MEEGOHANDSETNOTIFICATION_H + +#include <sowatch.h> +#include <notificationsystem/notification.h> +#include <notificationsystem/notificationparameters.h> + +class WatchNotificationSink; + +class MeegoHandsetNotification : public sowatch::Notification +{ + Q_OBJECT +public: + explicit MeegoHandsetNotification(const ::Notification& n, QObject *parent = 0); + + Type type() const; + uint count() const; + QDateTime dateTime() const; + QString title() const; + QString body() const; + void activate(); + void clear(); + +signals: + void changed(); + void cleared(); + +protected: + void changeTo(const ::Notification& notification); + +protected: + ::Notification _n; + +friend class WatchNotificationSink; +}; + +#endif // MEEGOHANDSETNOTIFICATION_H diff --git a/meegohandsetnotification/meegohandsetnotification.pro b/meegohandsetnotification/meegohandsetnotification.pro index 424eb33..e553178 100644 --- a/meegohandsetnotification/meegohandsetnotification.pro +++ b/meegohandsetnotification/meegohandsetnotification.pro @@ -13,12 +13,14 @@ QT += dbus SOURCES += meegohandsetplugin.cpp \ meegohandsetnotificationprovider.cpp \ watchnotificationsink.cpp \ - mnotificationmanagerinterface.cpp + mnotificationmanagerinterface.cpp \ + meegohandsetnotification.cpp HEADERS += meegohandsetplugin.h \ meegohandsetnotificationprovider.h \ watchnotificationsink.h \ - mnotificationmanagerinterface.h + mnotificationmanagerinterface.h \ + meegohandsetnotification.h CONFIG += notificationsystem @@ -43,3 +45,5 @@ unix:!symbian { + + diff --git a/meegohandsetnotification/meegohandsetnotificationprovider.cpp b/meegohandsetnotification/meegohandsetnotificationprovider.cpp index fc84e46..0297ebb 100644 --- a/meegohandsetnotification/meegohandsetnotificationprovider.cpp +++ b/meegohandsetnotification/meegohandsetnotificationprovider.cpp @@ -22,10 +22,8 @@ MeegoHandsetNotificationProvider::MeegoHandsetNotificationProvider(QObject *pare QDBusConnection::sessionBus().registerService("com.javispedro.sowatch.MeegoHandsetNotificationSink"); QDBusConnection::sessionBus().registerObject("/meegohandsetnotificationsink", _sink); - connect(_sink, SIGNAL(incomingNotification(sowatch::Notification)), - SLOT(sinkNotification(sowatch::Notification))); - connect(_sink, SIGNAL(countsChanged(sowatch::Notification::Type)), - SLOT(sinkUnreadCountChanged(sowatch::Notification::Type))); + connect(_sink, SIGNAL(incomingNotification(sowatch::Notification*)), + SLOT(newNotification(sowatch::Notification*))); _manager->registerSink("com.javispedro.sowatch.MeegoHandsetNotificationSink", "/meegohandsetnotificationsink"); } @@ -35,17 +33,8 @@ MeegoHandsetNotificationProvider::~MeegoHandsetNotificationProvider() } -int MeegoHandsetNotificationProvider::getCount(sowatch::Notification::Type type) -{ - return _sink->getCount(type); -} - -void MeegoHandsetNotificationProvider::sinkNotification(const Notification &n) -{ - emit notification(n); -} -void MeegoHandsetNotificationProvider::sinkUnreadCountChanged(Notification::Type type) +void MeegoHandsetNotificationProvider::newNotification(Notification* n) { - emit unreadCountChanged(type); + emit incomingNotification(n); } diff --git a/meegohandsetnotification/meegohandsetnotificationprovider.h b/meegohandsetnotification/meegohandsetnotificationprovider.h index 3cf78d3..f98f226 100644 --- a/meegohandsetnotification/meegohandsetnotificationprovider.h +++ b/meegohandsetnotification/meegohandsetnotificationprovider.h @@ -16,14 +16,12 @@ public: explicit MeegoHandsetNotificationProvider(QObject *parent = 0); ~MeegoHandsetNotificationProvider(); - int getCount(Notification::Type type); protected: MNotificationManagerInterface* _manager; WatchNotificationSink* _sink; protected slots: - void sinkNotification(const sowatch::Notification &n); - void sinkUnreadCountChanged(sowatch::Notification::Type type); + void newNotification(sowatch::Notification *n); friend class WatchNoficationSink; }; diff --git a/meegohandsetnotification/watchnotificationsink.cpp b/meegohandsetnotification/watchnotificationsink.cpp index c80c4ae..cf03c30 100644 --- a/meegohandsetnotification/watchnotificationsink.cpp +++ b/meegohandsetnotification/watchnotificationsink.cpp @@ -2,50 +2,33 @@ #include "watchnotificationsink.h" WatchNotificationSink::WatchNotificationSink(sowatch::MeegoHandsetNotificationProvider *parent) : - NotificationSink(parent), _parent(parent) + NotificationSink(parent) { - for (uint i = 0; i < maxTypes; i++) { - _counts[i] = 0; - } + } void WatchNotificationSink::addNotification(const Notification ¬ification) { - const NotificationParameters& p = notification.parameters(); - sowatch::Notification::Type type = notificationTypeFromEventType(p.value("eventType").toString()); - const uint count = p.value("count").toUInt(); const uint notificationId = notification.notificationId(); if (_trackedNotifications.contains(notificationId)) { - const NotificationParameters& oldParams = _trackedNotifications[notificationId].parameters(); - _counts[type] -= oldParams.value("count").toUInt(); - } - - _counts[type] += count; - _trackedNotifications[notificationId] = notification; - - emit countsChanged(type); - - QDateTime dt = QDateTime::fromTime_t(p.value("timestamp").toUInt()); - QDateTime tenSecondsAgo = QDateTime::currentDateTimeUtc().addSecs(-10); - if (dt >= tenSecondsAgo) { - // If the notification happened recently, show it. - sowatch::Notification n(type, dt, p.value("summary").toString(), p.value("body").toString()); - emit incomingNotification(n); + MeegoHandsetNotification* n = _trackedNotifications[notificationId]; + n->changeTo(notification); + } else { + MeegoHandsetNotification* n = new MeegoHandsetNotification(notification, this); + _trackedNotifications[notificationId] = n; + emit incomingNotification(static_cast<sowatch::Notification*>(n)); } } void WatchNotificationSink::removeNotification(uint notificationId) { - Notification notification = _trackedNotifications[notificationId]; - const NotificationParameters& p = notification.parameters(); - sowatch::Notification::Type type = notificationTypeFromEventType(p.value("eventType").toString()); - uint count = p.value("count").toUInt(); - - _counts[type] -= count; - _trackedNotifications.remove(notificationId); - - emit countsChanged(type); + if (_trackedNotifications.contains(notificationId)) { + MeegoHandsetNotification* n = _trackedNotifications[notificationId]; + _trackedNotifications.remove(notificationId); + n->clear(); + n->deleteLater(); + } } void WatchNotificationSink::addGroup(uint groupId, const NotificationParameters ¶meters) @@ -59,25 +42,3 @@ void WatchNotificationSink::removeGroup(uint groupId) { Q_UNUSED(groupId); } - -int WatchNotificationSink::getCount(sowatch::Notification::Type type) -{ - return _counts[type]; -} - -sowatch::Notification::Type WatchNotificationSink::notificationTypeFromEventType(const QString& eventType) -{ - qDebug() << "incoming " << eventType; - if (eventType == "email.arrived") - return sowatch::Notification::EmailNotification; - else if (eventType == "x-nokia.call.missed") - return sowatch::Notification::MissedCallNotification; - else if (eventType == "x-nokia.messaging.im") - return sowatch::Notification::ImNotification; - else if (eventType == "x-nokia.messaging.sms") - return sowatch::Notification::SmsNotification; - else if (eventType == "x-nokia.messaging.mms") - return sowatch::Notification::MmsNotification; - else - return sowatch::Notification::OtherNotification; -} diff --git a/meegohandsetnotification/watchnotificationsink.h b/meegohandsetnotification/watchnotificationsink.h index dc586a2..9500994 100644 --- a/meegohandsetnotification/watchnotificationsink.h +++ b/meegohandsetnotification/watchnotificationsink.h @@ -3,9 +3,8 @@ #include <QtCore/QMap> #include <sowatch.h> -#include <notificationsystem/notification.h> +#include "meegohandsetnotification.h" #include <notificationsystem/notificationsink.h> -#include <notificationsystem/notificationparameters.h> namespace sowatch { class MeegoHandsetNotificationProvider; @@ -23,19 +22,11 @@ public: void addGroup(uint groupId, const NotificationParameters ¶meters); void removeGroup(uint groupId); - int getCount(sowatch::Notification::Type type); - signals: - void incomingNotification(const sowatch::Notification& notification); - void countsChanged(sowatch::Notification::Type type); + void incomingNotification(sowatch::Notification* notification); protected: - static const uint maxTypes = sowatch::Notification::TypeCount; - static sowatch::Notification::Type notificationTypeFromEventType(const QString& eventType); - - sowatch::MeegoHandsetNotificationProvider* _parent; - QMap<uint, Notification> _trackedNotifications; - uint _counts[maxTypes]; + QMap<uint, MeegoHandsetNotification*> _trackedNotifications; }; #endif // WATCHNOTIFICATIONSINK_H diff --git a/metawatch/metawatch.cpp b/metawatch/metawatch.cpp index 657548a..5e6a8fb 100644 --- a/metawatch/metawatch.cpp +++ b/metawatch/metawatch.cpp @@ -79,7 +79,7 @@ MetaWatch::MetaWatch(const QBluetoothAddress& address, QObject *parent) : _paintEngine(0), _address(address), _socket(0), - _24hMode(true), _dayMonthOrder(true), + _24hMode(true), _dayMonthOrder(true), _notificationTimeout(10), _connectRetries(0), _connected(false), _connectTimer(new QTimer(this)), @@ -87,7 +87,8 @@ MetaWatch::MetaWatch(const QBluetoothAddress& address, QObject *parent) : _sendTimer(new QTimer(this)), _currentMode(IdleMode), _paintMode(IdleMode), - _nMails(0), _nCalls(0), _nIms(0), _nSms(0), _nMms(0) + _nMails(0), _nCalls(0), _nIms(0), _nSms(0), _nMms(0), + _idleTimer(new QTimer(this)), _ringTimer(new QTimer(this)) { QImage baseImage(screenWidth, screenHeight, QImage::Format_MonoLSB); baseImage.setColor(0, QColor(Qt::white).rgb()); @@ -101,9 +102,16 @@ MetaWatch::MetaWatch(const QBluetoothAddress& address, QObject *parent) : connect(_connectTimer, SIGNAL(timeout()), SLOT(retryConnect())); connect(_connectAlignedTimer, SIGNAL(timeout()), SLOT(retryConnect())); - _sendTimer->setInterval(30); + _sendTimer->setInterval(10); connect(_sendTimer, SIGNAL(timeout()), SLOT(timedSend())); + _idleTimer->setInterval(_notificationTimeout * 1000); + _idleTimer->setSingleShot(true); + connect(_idleTimer, SIGNAL(timeout()), SIGNAL(idling())); + + _ringTimer->setInterval(2000); + connect(_ringTimer, SIGNAL(timeout()), SLOT(timedRing())); + retryConnect(); } @@ -217,24 +225,92 @@ void MetaWatch::updateNotificationCount(Notification::Type type, int count) renderIdleCounts(); } -void MetaWatch::vibrate(bool on) +void MetaWatch::displayIdleScreen() { - Q_UNUSED(on); // TODO -} + _currentMode = IdleMode; + _ringTimer->stop(); + _idleTimer->stop(); + setVibrateMode(false, 0, 0, 0); + updateDisplay(IdleMode); + // Usually, idle screen is kept updated, so we can show it already. + qDebug() << "displayIdle"; -void MetaWatch::showNotification(const Notification &n) -{ - qDebug() << "It's time for a notification" << n.title(); } -void MetaWatch::startRinging(const QString &text) +void MetaWatch::displayNotification(Notification *n) { + _currentMode = NotificationMode; + _paintMode = NotificationMode; + const bool shouldRing = n->type() == Notification::CallNotification; + configureWatchMode(NotificationMode, shouldRing ? 60 : 10); + QPainter p; + QFont lf("MetaWatch Large 16pt", 14); + QFont mf("MetaWatch Large 16pt", 10); + QImage icon = iconForNotification(n); + const int x = 4; + const int iconY = 4; + const int titleY = 8 + icon.height(); + int textFlags; + QString text; + + qDebug() << "displayNotification" << n->title() << n->body(); + + p.begin(this); + + p.fillRect(0, 0, screenWidth, screenHeight, Qt::white); + p.drawImage(x, iconY, icon); + + p.setPen(Qt::black); + p.setFont(lf); + textFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere; + text = n->title(); + + QRect titleMaxRect(x, titleY, screenWidth - x*2, screenHeight - titleY); + QRect titleRect = p.boundingRect(titleMaxRect, textFlags, text); + if (titleRect.width() > titleMaxRect.width()) { + textFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere; + titleRect = p.boundingRect(titleMaxRect, textFlags, text); + } + + qDebug() << titleMaxRect << titleRect; + p.drawText(titleMaxRect, textFlags, text); + + p.setFont(mf); + textFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap; + text = n->body(); + + int bodyY = titleRect.y() + titleRect.height(); + if (bodyY >= screenHeight) return; + QRect bodyMaxRect(x, bodyY, titleMaxRect.width(), screenHeight - bodyY); + QRect bodyRect = p.boundingRect(bodyMaxRect, textFlags, text); + if (bodyRect.width() > bodyMaxRect.width()) { + textFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere; + } + qDebug() << bodyMaxRect << bodyRect; + p.drawText(bodyMaxRect, textFlags, text); + + p.end(); + + if (n->type() == Notification::CallNotification) { + timedRing(); + _ringTimer->start(); + _idleTimer->stop(); + } else { + _ringTimer->stop(); + setVibrateMode(true, 500, 500, 2); + _idleTimer->start(); + } } -void MetaWatch::stopRinging() +void MetaWatch::displayApplication() { - + _currentMode = ApplicationMode; + _paintMode = ApplicationMode; + _ringTimer->stop(); + _idleTimer->stop(); + configureWatchMode(ApplicationMode, 250); + qDebug() << "displayApplication"; } MetaWatch::Mode MetaWatch::currentMode() const @@ -307,11 +383,11 @@ void MetaWatch::renderIdleScreen() void MetaWatch::renderIdleWeather() { _paintMode = IdleMode; - QFont smallFont("MetaWatch Small caps 8pt", 6); + QFont f("MetaWatch Small caps 8pt", 6); QImage rain(QString(":/metawatch/graphics/weather_rain.bmp")); QPainter p(this); - p.setFont(smallFont); + p.setFont(f); p.drawText(30, systemAreaHeight + 14, "No data!"); p.drawImage(screenWidth - 26, systemAreaHeight + 6, rain); @@ -341,6 +417,41 @@ void MetaWatch::renderIdleCounts() p.drawText(QRect((32 * 0) + 4, y, w, h), s.sprintf("%d", calls), opt); p.drawText(QRect((32 * 1) + 4, y, w, h), s.sprintf("%d", sms), opt); p.drawText(QRect((32 * 2) + 4, y, w, h), s.sprintf("%d", mails), opt); + + _paintMode = _currentMode; +} + +void MetaWatch::renderNotificationScreen() +{ + _paintMode = NotificationMode; + QPainter p(this); + + p.fillRect(0, 0, screenWidth, screenHeight, Qt::white); + + _paintMode = _currentMode; +} + +QImage MetaWatch::iconForNotification(const Notification *n) +{ + switch (n->type()) { + case Notification::CallNotification: + case Notification::MissedCallNotification: + return QImage(QString(":/metawatch/graphics/phone.bmp")); + break; + case Notification::SmsNotification: + case Notification::MmsNotification: + case Notification::ImNotification: + return QImage(QString(":/metawatch/graphics/message.bmp")); + break; + case Notification::EmailNotification: + return QImage(QString(":/metawatch/graphics/email.bmp")); + break; + case Notification::CalendarNotification: + return QImage(QString(":/metawatch/graphics/timer.bmp")); + break; + default: + return QImage(); + } } quint16 MetaWatch::calcCrc(const QByteArray &data, int size) @@ -394,6 +505,20 @@ void MetaWatch::handleMessage(const Message &msg) } } +void MetaWatch::setVibrateMode(bool enable, uint on, uint off, uint cycles) +{ + Message msg(SetVibrateMode, QByteArray(6, 0)); + + msg.data[0] = enable ? 1 : 0; + msg.data[1] = on & 0xFF; + msg.data[2] = on >> 8; + msg.data[3] = off & 0xFF; + msg.data[4] = off >> 8; + msg.data[5] = cycles; + + send(msg); +} + void MetaWatch::updateLine(Mode mode, const QImage& image, int line) { Message msg(WriteBuffer, QByteArray(13, 0), (1 << 4) | (mode & 0xF)); @@ -479,7 +604,7 @@ void MetaWatch::loadTemplate(Mode mode, int templ) void MetaWatch::handleStatusChange(const Message &msg) { - qDebug() << "watch status changed" << msg.data.size(); + qDebug() << "watch status changed" << msg.options << msg.data.at(0); } void MetaWatch::handleButtonEvent(const Message &msg) @@ -487,6 +612,8 @@ void MetaWatch::handleButtonEvent(const Message &msg) if (msg.data.size() < 1) return; quint8 button = msg.data[0]; + qDebug() << "button event" << msg.data.size() << msg.options << msg.data.at(0); + emit buttonPressed(button); // TODO This is completely broken } @@ -505,10 +632,9 @@ void MetaWatch::socketConnected() setDateTime(QDateTime::currentDateTime()); configureIdleSystemArea(false); - configureWatchMode(ApplicationMode, 240); - configureWatchMode(NotificationMode, 30); renderIdleScreen(); + renderNotificationScreen(); emit connected(); } @@ -624,6 +750,11 @@ void MetaWatch::timedSend() } } +void MetaWatch::timedRing() +{ + setVibrateMode(true, 200, 200, 3); +} + void MetaWatch::realSend(const Message &msg) { const int msgSize = msg.data.size(); diff --git a/metawatch/metawatch.h b/metawatch/metawatch.h index 48b7be6..da0f323 100644 --- a/metawatch/metawatch.h +++ b/metawatch/metawatch.h @@ -78,10 +78,10 @@ public: void updateNotificationCount(Notification::Type type, int count); - void vibrate(bool on); - void showNotification(const Notification& n); - void startRinging(const QString &text); - void stopRinging(); + void displayIdleScreen(); + void displayNotification(Notification *n); + void displayApplication(); + Mode currentMode() const; Mode paintTargetMode() const; @@ -92,6 +92,9 @@ public: void renderIdleScreen(); void renderIdleWeather(); void renderIdleCounts(); + void renderNotificationScreen(); + + QImage iconForNotification(const Notification *n); protected: mutable MetaWatchPaintEngine* _paintEngine; @@ -100,9 +103,12 @@ protected: QBluetoothAddress _address; QBluetoothSocket* _socket; + /* Some configurable stuff. */ bool _24hMode : 1; bool _dayMonthOrder : 1; + short _notificationTimeout; + static const int connectRetryTimesSize = 6; static const int connectRetryTimes[connectRetryTimesSize]; short _connectRetries; @@ -130,6 +136,10 @@ protected: // Notifications: Unread count uint _nMails, _nCalls, _nIms, _nSms, _nMms; + // Notifications: timers + QTimer* _idleTimer; + QTimer* _ringTimer; + static const quint8 bitRevTable[16]; static const quint16 crcTable[256]; quint16 calcCrc(const QByteArray& data, int size); @@ -138,6 +148,7 @@ protected: void send(const Message& msg); void handleMessage(const Message& msg); + void setVibrateMode(bool enable, uint on, uint off, uint cycles); void updateLine(Mode mode, const QImage& image, int line); void updateLines(Mode mode, const QImage& image, int lineA, int lineB); void updateLines(Mode mode, const QImage& image, const QVector<bool>& lines); @@ -157,6 +168,7 @@ protected slots: void socketState(QBluetoothSocket::SocketState error); void retryConnect(); void timedSend(); + void timedRing(); private: void realSend(const Message& msg); diff --git a/metawatch/uires.qrc b/metawatch/uires.qrc index 24d70fb..821a3dc 100644 --- a/metawatch/uires.qrc +++ b/metawatch/uires.qrc @@ -9,6 +9,11 @@ <file>weather_sunny.bmp</file> <file>weather_thunderstorm.bmp</file> <file>weather_wind.bmp</file> + <file>email.bmp</file> + <file>message.bmp</file> + <file>phone.bmp</file> + <file>play.bmp</file> + <file>timer.bmp</file> </qresource> <qresource prefix="/metawatch/fonts"> <file>metawatch_8pt_5pxl_CAPS.ttf</file> |