diff options
31 files changed, 810 insertions, 240 deletions
diff --git a/libsowatch/declarativewatchlet.cpp b/libsowatch/declarativewatchlet.cpp index ca60fb0..dbd4759 100644 --- a/libsowatch/declarativewatchlet.cpp +++ b/libsowatch/declarativewatchlet.cpp @@ -29,6 +29,11 @@ DeclarativeWatchlet::DeclarativeWatchlet(WatchServer* server, const QString& id) _engine->rootContext()->setContextProperty("watch", _wrapper); } +DeclarativeWatchlet::~DeclarativeWatchlet() +{ + +} + void DeclarativeWatchlet::setSource(const QUrl &url) { if (_item) { @@ -64,6 +69,11 @@ QDeclarativeContext* DeclarativeWatchlet::rootContext() return _engine->rootContext(); } +QDeclarativeItem* DeclarativeWatchlet::rootObject() +{ + return _item; +} + void DeclarativeWatchlet::activate() { GraphicsWatchlet::activate(); @@ -76,6 +86,19 @@ void DeclarativeWatchlet::deactivate() GraphicsWatchlet::deactivate(); } +void DeclarativeWatchlet::setRootObject(QDeclarativeItem *item) +{ + Q_ASSERT(_item == 0); /* This function should not be called with a current object. */ + if (!item) { + qWarning() << "QML root object is not a declarative item?"; + return; + } + + _item = item; + // TODO Resize _item + scene()->addItem(_item); +} + void DeclarativeWatchlet::handleComponentStatus(QDeclarativeComponent::Status status) { QObject *obj; @@ -93,9 +116,7 @@ void DeclarativeWatchlet::handleComponentStatus(QDeclarativeComponent::Status st qWarning() << _component->errors(); return; } - Q_ASSERT(_item == 0); - _item = qobject_cast<QDeclarativeItem*>(obj); - scene()->addItem(_item); + setRootObject(qobject_cast<QDeclarativeItem*>(obj)); break; case QDeclarativeComponent::Error: qWarning() << "QML has errors found while loading:"; diff --git a/libsowatch/declarativewatchlet.h b/libsowatch/declarativewatchlet.h index 0dd7e23..087387a 100644 --- a/libsowatch/declarativewatchlet.h +++ b/libsowatch/declarativewatchlet.h @@ -18,25 +18,29 @@ class SOWATCH_EXPORT DeclarativeWatchlet : public GraphicsWatchlet Q_OBJECT public: explicit DeclarativeWatchlet(WatchServer* server, const QString& id); + ~DeclarativeWatchlet(); void setSource(const QUrl& url); QDeclarativeEngine* engine(); QDeclarativeContext* rootContext(); - -protected slots: - void handleComponentStatus(QDeclarativeComponent::Status status); + QDeclarativeItem* rootObject(); protected: void activate(); void deactivate(); +private: + void setRootObject(QDeclarativeItem* item); + static bool _registered; QDeclarativeEngine* _engine; QDeclarativeComponent* _component; QDeclarativeItem* _item; DeclarativeWatchWrapper* _wrapper; +private slots: + void handleComponentStatus(QDeclarativeComponent::Status status); }; } diff --git a/libsowatch/declarativewatchwrapper.cpp b/libsowatch/declarativewatchwrapper.cpp index 384a29d..f7914f8 100644 --- a/libsowatch/declarativewatchwrapper.cpp +++ b/libsowatch/declarativewatchwrapper.cpp @@ -20,6 +20,13 @@ bool DeclarativeWatchWrapper::active() const return _active; } +void DeclarativeWatchWrapper::vibrate(int msecs) +{ + if (_active) { + _watch->vibrate(msecs); + } +} + void DeclarativeWatchWrapper::activate() { if (!_active) { @@ -33,8 +40,7 @@ void DeclarativeWatchWrapper::activate() void DeclarativeWatchWrapper::deactivate() { if (_active) { - disconnect(this, SIGNAL(buttonPressed(int))); - disconnect(this, SIGNAL(buttonReleased(int))); + disconnect(_watch, 0, this, 0); _active = false; emit activeChanged(); } diff --git a/libsowatch/declarativewatchwrapper.h b/libsowatch/declarativewatchwrapper.h index 42746ec..583b2d2 100644 --- a/libsowatch/declarativewatchwrapper.h +++ b/libsowatch/declarativewatchwrapper.h @@ -21,6 +21,9 @@ public: Q_INVOKABLE QString model() const; Q_INVOKABLE bool active() const; +public slots: + void vibrate(int msecs); + signals: void buttonPressed(int button); void buttonReleased(int button); diff --git a/libsowatch/graphicswatchlet.cpp b/libsowatch/graphicswatchlet.cpp index 195d11b..e11d5cc 100644 --- a/libsowatch/graphicswatchlet.cpp +++ b/libsowatch/graphicswatchlet.cpp @@ -8,8 +8,15 @@ using namespace sowatch; GraphicsWatchlet::GraphicsWatchlet(WatchServer* server, const QString& id) : - Watchlet(server, id), _scene(0), _damaged() + Watchlet(server, id), _scene(0), _frameTimer(), _damaged() { + _frameTimer.setSingleShot(true); + connect(&_frameTimer, SIGNAL(timeout()), SLOT(frameTimeout())); +} + +GraphicsWatchlet::~GraphicsWatchlet() +{ + } QGraphicsScene* GraphicsWatchlet::scene() @@ -20,7 +27,7 @@ QGraphicsScene* GraphicsWatchlet::scene() void GraphicsWatchlet::setScene(QGraphicsScene *scene) { if (_scene) { - disconnect(this, SLOT(sceneChanged(QList<QRectF>))); + disconnect(_scene, 0, this, 0); } _scene = scene; if (_scene) { @@ -34,15 +41,26 @@ void GraphicsWatchlet::sceneChanged(const QList<QRectF> ®ion) foreach(const QRectF& r, region) { _damaged += r.toRect(); } - if (!_damaged.isEmpty() && _active && !watch()->busy()) { - const QVector<QRect> rects = _damaged.rects(); - QPainter p(watch()); - - foreach(const QRect& r, rects) { - _scene->render(&p, r, r, Qt::IgnoreAspectRatio); - } - _damaged = QRegion(); + if (!_damaged.isEmpty()) { + _frameTimer.start(frameDelay); + } +} + +void GraphicsWatchlet::frameTimeout() +{ + if (!_active) return; // Watchlet was ejected, do not draw. + if (watch()->busy()) { + _frameTimer.start(busyFrameDelay); + return; + } + + const QVector<QRect> rects = _damaged.rects(); + QPainter p(watch()); + + foreach(const QRect& r, rects) { + _scene->render(&p, r, r, Qt::IgnoreAspectRatio); } + _damaged = QRegion(); } void GraphicsWatchlet::activate() @@ -53,3 +71,9 @@ void GraphicsWatchlet::activate() _damaged += area; _scene->update(area); } + +void GraphicsWatchlet::deactivate() +{ + _frameTimer.stop(); + Watchlet::deactivate(); +} diff --git a/libsowatch/graphicswatchlet.h b/libsowatch/graphicswatchlet.h index 3202631..61b68bf 100644 --- a/libsowatch/graphicswatchlet.h +++ b/libsowatch/graphicswatchlet.h @@ -1,6 +1,7 @@ #ifndef SOWATCH_GRAPHICSWATCHLET_H #define SOWATCH_GRAPHICSWATCHLET_H +#include <QtCore/QTimer> #include <QtGui/QGraphicsScene> #include <QtGui/QRegion> #include "watchlet.h" @@ -14,17 +15,27 @@ class SOWATCH_EXPORT GraphicsWatchlet : public Watchlet Q_OBJECT public: explicit GraphicsWatchlet(WatchServer* server, const QString& id); + ~GraphicsWatchlet(); QGraphicsScene* scene(); void setScene(QGraphicsScene* scene); -protected slots: - void sceneChanged(const QList<QRectF>& region); + static const int frameDelay = 20; + static const int busyFrameDelay = 40; protected: void activate(); + void deactivate(); QGraphicsScene* _scene; + QTimer _frameTimer; + +private slots: + void sceneChanged(const QList<QRectF>& region); + void frameTimeout(); + +private: + QRegion _damaged; }; diff --git a/libsowatch/libsowatch.pro b/libsowatch/libsowatch.pro index 5ab1f3b..4c0d7dc 100644 --- a/libsowatch/libsowatch.pro +++ b/libsowatch/libsowatch.pro @@ -19,7 +19,6 @@ SOURCES += \ watchpaintengine.cpp \ watchlet.cpp \ watch.cpp \ - testwatchlet.cpp \ graphicswatchlet.cpp \ declarativewatchwrapper.cpp \ declarativewatchlet.cpp \ @@ -35,7 +34,6 @@ HEADERS +=\ watchpaintengine.h \ watchlet.h \ watch.h \ - testwatchlet.h \ sowatch.h \ graphicswatchlet.h \ declarativewatchwrapper.h \ @@ -93,3 +91,5 @@ unix:!symbian { + + diff --git a/libsowatch/testwatchlet.cpp b/libsowatch/testwatchlet.cpp deleted file mode 100644 index ffc4097..0000000 --- a/libsowatch/testwatchlet.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include <QtCore/QDebug> -#include <QtGui/QPainter> - -#include "testwatchlet.h" -#include "watch.h" - -using namespace sowatch; - -TestWatchlet::TestWatchlet(WatchServer* server) : - Watchlet(server, "com.javispedro.sowatch.testwatchlet"), _timer(new QTimer(this)), _y(0) -{ - _timer->setInterval(50); - connect(_timer, SIGNAL(timeout()), SLOT(interv())); - connect(this, SIGNAL(activated()), SLOT(handleActivated())); - connect(this, SIGNAL(deactivated()), SLOT(handleDeactivated())); -} - -void TestWatchlet::interv() -{ - QPainter p(watch()); - //p.fillRect(8, _y, 8, 1, Qt::black); - _y = (_y + 1) % watch()->height(); - p.fillRect(0, _y, _y, 2, Qt::black); - //p.fillRect(0, 0, watch()->width(), watch()->height(), Qt::black); -} - - -void TestWatchlet::handleActivated() -{ - qDebug() << "test watchlet activated"; - QPainter p(watch()); - p.fillRect(0, 0, watch()->width(), watch()->height(), Qt::white); - _timer->start(); -} - -void TestWatchlet::handleDeactivated() -{ - _timer->stop(); - qDebug() << "test watchlet deactivated"; -} diff --git a/libsowatch/testwatchlet.h b/libsowatch/testwatchlet.h deleted file mode 100644 index 6556724..0000000 --- a/libsowatch/testwatchlet.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SOWATCH_TESTWATCHLET_H -#define SOWATCH_TESTWATCHLET_H - -#include <QtCore/QTimer> -#include "watchlet.h" - -namespace sowatch -{ - -class TestWatchlet : public Watchlet -{ - Q_OBJECT -public: - explicit TestWatchlet(WatchServer* server); - -protected slots: - void interv(); - void handleActivated(); - void handleDeactivated(); - -private: - QTimer *_timer; - int _y; - -}; - -} - -#endif // SOWATCH_TESTWATCHLET_H diff --git a/libsowatch/watch.cpp b/libsowatch/watch.cpp index 7792693..e62c6c4 100644 --- a/libsowatch/watch.cpp +++ b/libsowatch/watch.cpp @@ -13,3 +13,8 @@ Watch::~Watch() { } + +void Watch::vibrate(int msecs) +{ + /* The default implementation does nothing. */ +} diff --git a/libsowatch/watch.h b/libsowatch/watch.h index ee9bde7..bb4376c 100644 --- a/libsowatch/watch.h +++ b/libsowatch/watch.h @@ -14,7 +14,7 @@ namespace sowatch class Watch : public QObject, public QPaintDevice { Q_OBJECT - Q_PROPERTY(QString model READ model) + Q_PROPERTY(QString model READ model CONSTANT) Q_PROPERTY(bool connected READ isConnected) Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime) @@ -38,13 +38,6 @@ public: /** Sets the current date/time on the watch. */ virtual void setDateTime(const QDateTime& dateTime) = 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; - /** Grabs a button from whatever is default function is for the current mode. */ virtual void grabButton(int button) = 0; /** Restores a button to its default function. */ @@ -53,6 +46,17 @@ public: /** Tells the watch to update the unread notifications count, if visible. */ virtual void updateNotificationCount(Notification::Type type, int count) = 0; +public slots: + /** 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* notification) = 0; + /** Enter application mode. */ + virtual void displayApplication() = 0; + + /** Vibrate for a while. The default implementation does nothing. */ + virtual void vibrate(int msecs); + signals: /** The watch has been found and linked to. */ void connected(); diff --git a/libsowatch/watchlet.cpp b/libsowatch/watchlet.cpp index 6d7fe68..15e0b6c 100644 --- a/libsowatch/watchlet.cpp +++ b/libsowatch/watchlet.cpp @@ -9,6 +9,11 @@ Watchlet::Watchlet(WatchServer *server, const QString& id) : _server->registerWatchlet(this); } +Watchlet::~Watchlet() +{ + +} + WatchServer* Watchlet::server() { return _server; diff --git a/libsowatch/watchlet.h b/libsowatch/watchlet.h index 7f3413d..dad1ddc 100644 --- a/libsowatch/watchlet.h +++ b/libsowatch/watchlet.h @@ -18,12 +18,13 @@ class SOWATCH_EXPORT Watchlet : public QObject public: explicit Watchlet(WatchServer *server, const QString& id); + virtual ~Watchlet(); WatchServer* server(); Watch* watch(); Q_INVOKABLE QString id() const; - Q_INVOKABLE bool isActive() const; + bool isActive() const; signals: void activeChanged(); diff --git a/libsowatch/watchserver.cpp b/libsowatch/watchserver.cpp index c81d937..9f11795 100644 --- a/libsowatch/watchserver.cpp +++ b/libsowatch/watchserver.cpp @@ -49,7 +49,7 @@ void WatchServer::setNextWatchletButton(const QString& value) void WatchServer::addProvider(NotificationProvider *provider) { provider->setParent(this); - connect(provider, SIGNAL(incomingNotification(Notification*)), SLOT(notificationReceived(Notification*))); + connect(provider, SIGNAL(incomingNotification(Notification*)), SLOT(postNotification(Notification*))); // And that's it, really. } @@ -80,7 +80,9 @@ void WatchServer::closeWatchlet() void WatchServer::registerWatchlet(Watchlet *watchlet) { Q_ASSERT(watchlet->_server == this); - _watchlets[watchlet->id()] = watchlet; + QString id = watchlet->id(); + _watchlets[id] = watchlet; + _watchletIds.append(id); } void WatchServer::reactivateCurrentWatchlet() @@ -92,13 +94,13 @@ void WatchServer::reactivateCurrentWatchlet() void WatchServer::nextWatchlet() { - QStringList watchlets = _watchlets.keys(); + qDebug() << "current watchlet index" << _currentWatchletIndex; _currentWatchletIndex++; - if (_currentWatchletIndex >= watchlets.size()) { + if (_currentWatchletIndex >= _watchletIds.size() || _currentWatchletIndex < 0) { _currentWatchletIndex = -1; closeWatchlet(); } else { - QString watchlet = watchlets.at(_currentWatchletIndex); + QString watchlet = _watchletIds.at(_currentWatchletIndex); runWatchlet(watchlet); } } @@ -176,7 +178,7 @@ void WatchServer::watchButtonPress(int button) } } -void WatchServer::notificationReceived(Notification *notification) +void WatchServer::postNotification(Notification *notification) { const Notification::Type type = notification->type(); _notifications[type].append(notification); diff --git a/libsowatch/watchserver.h b/libsowatch/watchserver.h index a3e0593..66c941a 100644 --- a/libsowatch/watchserver.h +++ b/libsowatch/watchserver.h @@ -2,6 +2,7 @@ #define SOWATCH_WATCHSERVER_H #include <QtCore/QList> +#include <QtCore/QStringList> #include <QtCore/QMap> #include <QtCore/QQueue> @@ -31,39 +32,49 @@ public: void addProvider(NotificationProvider* provider); +public slots: + void postNotification(Notification *notification); void runWatchlet(const QString& id); void closeWatchlet(); + void nextWatchlet(); -protected: +private: Watch* _watch; + /** The watch button that causes next watchlet to be run. */ int _nextWatchletButton; + /** The amount of seconds that have to pass for a notification to be considered "outdated" and not shown. */ int _oldNotificationThreshold; + /** A list of watchlets in order, for use by nextWatchlet() */ + QStringList _watchletIds; + /** Actual Watchlet child objects by id. */ QMap<QString, Watchlet*> _watchlets; - /** Stores current notifications, classified by type. */ + /** Stores current live notifications, classified by type. */ QList<Notification*> _notifications[Notification::TypeCount]; + /** A list of notifications that are yet to be shown to the user. */ QQueue<Notification*> _pendingNotifications; + /** Current watchlet. */ Watchlet* _currentWatchlet; - unsigned char _currentWatchletIndex; + /** The current watchlet index if any, for use by nextWatchlet() */ + int _currentWatchletIndex; void registerWatchlet(Watchlet *watchlet); void reactivateCurrentWatchlet(); - void nextWatchlet(); void nextNotification(); uint getNotificationCount(Notification::Type type); void goToIdle(); -protected slots: +private slots: void watchConnected(); void watchDisconnected(); void watchIdling(); void watchButtonPress(int button); - void notificationReceived(Notification* notification); + void notificationChanged(); void notificationCleared(); diff --git a/meegohandsetnotification/meegohandsetnotification.pro b/meegohandsetnotification/meegohandsetnotification.pro index e553178..4921d03 100644 --- a/meegohandsetnotification/meegohandsetnotification.pro +++ b/meegohandsetnotification/meegohandsetnotification.pro @@ -1,13 +1,7 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2011-09-18T18:48:13 -# -#------------------------------------------------- - TARGET = meegohandsetnotification TEMPLATE = lib -# CONFIG += plugin # Stupid Qt creator doesn't want to deploy plugins +# CONFIG += plugin QT += dbus SOURCES += meegohandsetplugin.cpp \ @@ -25,7 +19,6 @@ HEADERS += meegohandsetplugin.h \ CONFIG += notificationsystem unix: LIBS += -L$$OUT_PWD/../libsowatch/ -lsowatch - INCLUDEPATH += $$PWD/../libsowatch DEPENDPATH += $$PWD/../libsowatch diff --git a/metawatch/metawatch.cpp b/metawatch/metawatch.cpp index e1d9780..e9a8af1 100644 --- a/metawatch/metawatch.cpp +++ b/metawatch/metawatch.cpp @@ -9,9 +9,6 @@ QTM_USE_NAMESPACE #define SINGLE_LINE_UPDATE 0 -const char MetaWatch::watchToBtn[8] = { - 0, 1, 2, 3, -1, 4, 5, -1 -}; const char MetaWatch::btnToWatch[8] = { 0, 1, 2, 3, 5, 6, -1, -1 }; @@ -106,6 +103,9 @@ MetaWatch::MetaWatch(const QBluetoothAddress& address, QSettings* settings, QObj _24hMode = settings->value("24hMode", false).toBool(); _dayMonthOrder = settings->value("DayMonthOrder", false).toBool(); _notificationTimeout = settings->value("NotificationTimeout", 10).toInt(); + _invertedIdle = settings->value("InvertedIdleScreen", false).toBool(); + _invertedNotifications = settings->value("InvertedNotifications", false).toBool(); + _invertedApplications = settings->value("InvertedApplications", false).toBool(); } _idleTimer->setInterval(_notificationTimeout * 1000); @@ -215,6 +215,45 @@ void MetaWatch::setDateTime(const QDateTime &dateTime) send(msg); } +void MetaWatch::grabButton(int button) +{ + grabButton(_currentMode, (Button) button); +} + +void MetaWatch::ungrabButton(int button) +{ + ungrabButton(_currentMode, (Button) button); +} + +void MetaWatch::updateNotificationCount(Notification::Type type, int count) +{ + switch (type) { + case Notification::MissedCallNotification: + _nCalls = count; + break; + case Notification::EmailNotification: + _nMails = count; + break; + case Notification::ImNotification: + _nIms = count; + break; + case Notification::SmsNotification: + _nSms = count; + break; + case Notification::MmsNotification: + _nMms = count; + break; + default: + // Ignore + return; + break; + } + + if (isConnected()) { + renderIdleCounts(); + } +} + void MetaWatch::displayIdleScreen() { _currentMode = IdleMode; @@ -231,7 +270,7 @@ void MetaWatch::displayNotification(Notification *n) const bool shouldRing = n->type() == Notification::CallNotification; _currentMode = NotificationMode; _paintMode = NotificationMode; - configureWatchMode(NotificationMode, shouldRing ? 60 : 10); + configureWatchMode(NotificationMode, shouldRing ? 120 : 10, _invertedNotifications); QPainter p; QFont sf("MetaWatch Small caps 8pt"); @@ -314,47 +353,13 @@ void MetaWatch::displayApplication() _paintMode = ApplicationMode; _ringTimer->stop(); _idleTimer->stop(); - configureWatchMode(ApplicationMode, 250); + configureWatchMode(ApplicationMode, 250, _invertedApplications); qDebug() << "displayApplication"; } -void MetaWatch::grabButton(int button) -{ - grabButton(_currentMode, (Button) button); -} - -void MetaWatch::ungrabButton(int button) +void MetaWatch::vibrate(int msecs) { - ungrabButton(_currentMode, (Button) button); -} - -void MetaWatch::updateNotificationCount(Notification::Type type, int count) -{ - switch (type) { - case Notification::MissedCallNotification: - _nCalls = count; - break; - case Notification::EmailNotification: - _nMails = count; - break; - case Notification::ImNotification: - _nIms = count; - break; - case Notification::SmsNotification: - _nSms = count; - break; - case Notification::MmsNotification: - _nMms = count; - break; - default: - // Ignore - return; - break; - } - - if (isConnected()) { - renderIdleCounts(); - } + setVibrateMode(true, msecs, 0, 1); } MetaWatch::Mode MetaWatch::currentMode() const @@ -703,19 +708,15 @@ void MetaWatch::handleButtonEvent(const Message &msg) return; } - quint8 watchBtn = msg.options & 0xF; ButtonPress press = static_cast<ButtonPress>((msg.options & 0x30) >> 4); - int button = -1; + int button = msg.options & 0xF; - if (watchBtn < 8) { - button = watchToBtn[watchBtn]; - } - if (button == -1) { - qWarning() << "Unknown watch button" << watchBtn; + if (button >= 6) { + qWarning() << "Unknown watch button" << button; return; } - qDebug() << "button event" << button << press; + qDebug() << "button event" << button << " (" << press << ")"; if (press == PressOnly) { emit buttonPressed(button); @@ -736,9 +737,14 @@ void MetaWatch::socketConnected() _currentMode = IdleMode; _paintMode = IdleMode; + // Sync watch date & time setDateTime(QDateTime::currentDateTime()); + // Configure to show watch-rendered clock in idle screen configureIdleSystemArea(false); + // Follow inverted screen user preference + configureWatchMode(IdleMode, 0, _invertedIdle); + // Grab all buttons in both notification and application modes grabButton(ApplicationMode, BtnA); grabButton(ApplicationMode, BtnB); grabButton(ApplicationMode, BtnC); @@ -752,6 +758,7 @@ void MetaWatch::socketConnected() grabButton(NotificationMode, BtnE); grabButton(NotificationMode, BtnF); + // Render the idle screen from zero renderIdleScreen(); renderNotificationScreen(); @@ -789,58 +796,7 @@ void MetaWatch::socketDisconnected() void MetaWatch::socketData() { - do { - qint64 dataRead; - - qDebug() << "received" << _socket->bytesAvailable() << "bytes"; - - if (_partialReceived.type == 0) { - /* Still not received even the packet type */ - /* Receive the full header, 4 bytes. */ - if (_socket->bytesAvailable() < 4) return; /* Wait for more. */ - char header[4]; - - dataRead = _socket->read(header, 4); - if (dataRead < 4 || header[0] != 0x01) { - qWarning() << "TODO: Resync to start of frame"; - return; - } - - _partialReceived.type = static_cast<MessageType>(header[2]); - _partialReceived.data.resize(header[1] - 6); - _partialReceived.options = header[3]; - qDebug() << "got header"; - } - - /* We have the header; now, try to get the complete packet. */ - if (_socket->bytesAvailable() < _partialReceived.data.size() + 2) { - return; /* Wait for more. */ - } - dataRead = _socket->read(_partialReceived.data.data(), _partialReceived.data.size()); - if (dataRead < _partialReceived.data.size()) { - qWarning() << "Short read"; - return; - } - - char tail[2]; - dataRead = _socket->read(tail, 2); - if (dataRead < 2) { - qWarning() << "Short read"; - return; - } - - quint16 realCrc = calcCrc(_partialReceived); - quint16 expectedCrc = tail[1] << 8 | (tail[0] & 0xFFU); - if (realCrc == expectedCrc) { - handleMessage(_partialReceived); - } else { - qWarning() << "CRC error?"; - } - - // Prepare for the next packet - _partialReceived.data.clear(); - _partialReceived.type = NoMessage; - } while (_socket->bytesAvailable() > 0); + realReceive(false); } void MetaWatch::socketError(QBluetoothSocket::SocketError error) @@ -906,3 +862,64 @@ void MetaWatch::realSend(const Message &msg) _socket->write(data); } + +void MetaWatch::realReceive(bool block) +{ + do { + qint64 dataRead; + + qDebug() << "received" << _socket->bytesAvailable() << "bytes"; + + if (_partialReceived.type == 0) { + /* Still not received even the packet type */ + /* Receive the full header, 4 bytes. */ + if (_socket->bytesAvailable() < 4 && !block) { + /* Still not enough data available. */ + return; /* Wait for more, if non blocking. */ + } + char header[4]; + + dataRead = _socket->read(header, 4); + if (dataRead < 4 || header[0] != 0x01) { + qWarning() << "TODO: Resync to start of frame"; + return; + } + + _partialReceived.type = static_cast<MessageType>(header[2]); + _partialReceived.data.resize(header[1] - 6); + _partialReceived.options = header[3]; + qDebug() << "got header"; + } + + /* We have the header; now, try to get the complete packet. */ + if (_socket->bytesAvailable() < (_partialReceived.data.size() + 2) && + !block) { + return; /* Wait for more. */ + } + dataRead = _socket->read(_partialReceived.data.data(), _partialReceived.data.size()); + if (dataRead < _partialReceived.data.size()) { + qWarning() << "Short read"; + return; + } + + char tail[2]; + dataRead = _socket->read(tail, 2); + if (dataRead < 2) { + qWarning() << "Short read"; + return; + } + + quint16 realCrc = calcCrc(_partialReceived); + quint16 expectedCrc = tail[1] << 8 | (tail[0] & 0xFFU); + if (realCrc == expectedCrc) { + handleMessage(_partialReceived); + } else { + qWarning() << "CRC error?"; + } + + // Prepare for the next packet + _partialReceived.data.clear(); + _partialReceived.type = NoMessage; + } while (_socket->bytesAvailable() > 0 && !block); + // Loop until there are no more messages, or we are blocking and have received one. +} diff --git a/metawatch/metawatch.h b/metawatch/metawatch.h index 0a9123a..9a25134 100644 --- a/metawatch/metawatch.h +++ b/metawatch/metawatch.h @@ -93,15 +93,17 @@ public: QDateTime dateTime(); void setDateTime(const QDateTime& dateTime); - void displayIdleScreen(); - void displayNotification(Notification *n); - void displayApplication(); - void grabButton(int button); void ungrabButton(int button); void updateNotificationCount(Notification::Type type, int count); + void displayIdleScreen(); + void displayNotification(Notification *notification); + void displayApplication(); + + void vibrate(int msecs); + Mode currentMode() const; Mode paintTargetMode() const; QImage* imageFor(Mode mode); @@ -121,6 +123,9 @@ protected: // Some configurable stuff. bool _24hMode : 1; bool _dayMonthOrder : 1; + bool _invertedIdle : 1; + bool _invertedNotifications : 1; + bool _invertedApplications : 1; short _notificationTimeout; // Notifications: Unread count @@ -131,7 +136,6 @@ protected: QTimer* _ringTimer; // Buttons - static const char watchToBtn[8]; static const char btnToWatch[8]; QStringList _buttonNames; @@ -181,7 +185,7 @@ protected: 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); - void configureWatchMode(Mode mode, int timeout, bool invert = false); + void configureWatchMode(Mode mode, int timeout, bool invert); void configureIdleSystemArea(bool entireScreen); void updateDisplay(Mode mode, bool copy = true); void loadTemplate(Mode mode, int templ); @@ -203,6 +207,7 @@ protected slots: private: void realSend(const Message& msg); + void realReceive(bool block); }; } diff --git a/metawatch/metawatchplugin.h b/metawatch/metawatchplugin.h index 6834247..4ea0e5f 100644 --- a/metawatch/metawatchplugin.h +++ b/metawatch/metawatchplugin.h @@ -17,7 +17,7 @@ public: virtual QStringList drivers(); virtual Watch* getWatch(const QString& driver, QSettings& settings, QObject* parent = 0); -protected: +private: static bool fontsLoaded; }; diff --git a/qmafwwatchlet/metawatch-digital.qml b/qmafwwatchlet/metawatch-digital.qml new file mode 100644 index 0000000..0ec07cd --- /dev/null +++ b/qmafwwatchlet/metawatch-digital.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 + +Rectangle { + width: 96 + height: 96 + + color: "white" + + Image { + anchors.fill: parent + fillMode: Image.PreserveAspectFit + smooth: true + source: player.imageUrl + } + + Rectangle { + x: 0 + width: parent.width + height: 14 + anchors.bottom: parent.bottom + color: "white" + + Text { + anchors.fill: parent + text: player.title + color: "black" + } + } + + Connections { + target: watch + onButtonPressed : { + switch(button) { + case 1: + player.volumeUp(); + break; + case 2: + player.volumeDown(); + break; + case 3: + player.playPause(); + break; + case 4: + player.next(); + break; + case 5: + player.previous(); + break; + } + } + } +} diff --git a/qmafwwatchlet/qmafwwatchlet.cpp b/qmafwwatchlet/qmafwwatchlet.cpp new file mode 100644 index 0000000..e2f41a2 --- /dev/null +++ b/qmafwwatchlet/qmafwwatchlet.cpp @@ -0,0 +1,45 @@ +#include <MafwShared.h> + +#include "qmafwwatchletplayer.h" +#include "qmafwwatchlet.h" + +using namespace sowatch; + +class WatchletPlayer : public QObject +{ + Q_OBJECT +}; + + +QMafwWatchlet::QMafwWatchlet(WatchServer* server) : + DeclarativeWatchlet(server, "com.javispedro.sowatch.qmafw"), + _registry(MafwRegistry::instance()), + _player(new QMafwWatchletPlayer(this)) +{ + MafwShared* shared = MafwShared::instance(); + + connect(_registry, SIGNAL(rendererAdded(QString, QString)), SLOT(handleRendererAdded(QString))); + connect(_registry, SIGNAL(rendererRemoved(QString, QString)), SLOT(handleRendererRemoved(QString))); + + shared->initTracking(_registry); + + connect(this, SIGNAL(activated()), _player, SLOT(activate())); + connect(this, SIGNAL(deactivated()), _player, SLOT(deactivate())); + + rootContext()->setContextProperty("player", _player); + setSource(QUrl("qrc:/qmafwwatchlet/" + server->watch()->model() + ".qml")); +} + +void QMafwWatchlet::handleRendererAdded(const QString &uuid) +{ + if (uuid == "mafw_gst_renderer") { + _player->setRenderer(_registry->renderer(uuid)); + } +} + +void QMafwWatchlet::handleRendererRemoved(const QString &uuid) +{ + if (uuid == "mafw_gst_renderer") { + _player->setRenderer(0); + } +} diff --git a/qmafwwatchlet/qmafwwatchlet.h b/qmafwwatchlet/qmafwwatchlet.h new file mode 100644 index 0000000..d3c2bd2 --- /dev/null +++ b/qmafwwatchlet/qmafwwatchlet.h @@ -0,0 +1,30 @@ +#ifndef QMAFWWATCHLET_H +#define QMAFWWATCHLET_H + +#include <sowatch.h> + +#include <MafwRegistry.h> + +namespace sowatch +{ + +class QMafwWatchletPlayer; + +class QMafwWatchlet : public DeclarativeWatchlet +{ + Q_OBJECT +public: + explicit QMafwWatchlet(WatchServer* server); + +private: + MafwRegistry* _registry; + QMafwWatchletPlayer* _player; + +private slots: + void handleRendererAdded(const QString & uuid); + void handleRendererRemoved(const QString & uuid); +}; + +} + +#endif // QMAFWWATCHLET_H diff --git a/qmafwwatchlet/qmafwwatchlet.pro b/qmafwwatchlet/qmafwwatchlet.pro new file mode 100644 index 0000000..2f8db66 --- /dev/null +++ b/qmafwwatchlet/qmafwwatchlet.pro @@ -0,0 +1,39 @@ + +TARGET = qmafwwatchlet +TEMPLATE = lib +# CONFIG += plugin +QT += dbus +CONFIG += link_pkgconfig +unix: PKGCONFIG += qmafw qmafw-shared + +SOURCES += qmafwwatchlet.cpp \ + qmafwwatchletplugin.cpp \ + qmafwwatchletplayer.cpp +HEADERS += qmafwwatchlet.h \ + qmafwwatchletplugin.h \ + qmafwwatchletplayer.h + +unix: LIBS += -L$$OUT_PWD/../libsowatch/ -lsowatch +INCLUDEPATH += $$PWD/../libsowatch +DEPENDPATH += $$PWD/../libsowatch + +unix:!symbian { + maemo5 { + target.path = /opt/sowatch/watchlets + } else { + target.path = /usr/lib/sowatch/watchlets + } + INSTALLS += target +} + +OTHER_FILES += \ + metawatch-digital.qml + +RESOURCES += \ + qmafwwatchlet.qrc + + + + + + diff --git a/qmafwwatchlet/qmafwwatchlet.qrc b/qmafwwatchlet/qmafwwatchlet.qrc new file mode 100644 index 0000000..6b228a2 --- /dev/null +++ b/qmafwwatchlet/qmafwwatchlet.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/qmafwwatchlet"> + <file>metawatch-digital.qml</file> + </qresource> +</RCC> diff --git a/qmafwwatchlet/qmafwwatchletplayer.cpp b/qmafwwatchlet/qmafwwatchletplayer.cpp new file mode 100644 index 0000000..018795a --- /dev/null +++ b/qmafwwatchlet/qmafwwatchletplayer.cpp @@ -0,0 +1,227 @@ +#include <QtCore/QtDebug> +#include <QtCore/QDir> +#include <QtCore/QCryptographicHash> + +#include <MafwRenderer.h> +#include <MafwMediaInfo.h> +#include <MafwMetadata.h> + +#include "qmafwwatchlet.h" +#include "qmafwwatchletplayer.h" + +using namespace sowatch; + +QMafwWatchletPlayer::QMafwWatchletPlayer(QMafwWatchlet* watchlet) : + QObject(watchlet), + _active(false), + _renderer(0), + _state(MafwRenderer::Stopped), + _title(tr("No media")), + _album(), + _imageUrl() +{ + Q_ASSERT(watchlet); +} + +QString QMafwWatchletPlayer::title() const +{ + return _title; +} + +QString QMafwWatchletPlayer::album() const +{ + return _album; +} + +QString QMafwWatchletPlayer::artist() const +{ + return _artist; +} + +QUrl QMafwWatchletPlayer::imageUrl() const +{ + return _imageUrl; +} + +void QMafwWatchletPlayer::activate() +{ + _active = true; + reconnect(); +} + +void QMafwWatchletPlayer::deactivate() +{ + _active = false; + reconnect(); +} + +void QMafwWatchletPlayer::playPause() +{ + if (!_renderer) return; + if (_state == MafwRenderer::Playing) { + _renderer->pause(); + } else if (_state == MafwRenderer::Paused) { + _renderer->resume(); + } else { + _renderer->play(); + } +} + +void QMafwWatchletPlayer::play() +{ + if (!_renderer) return; + _renderer->play(); +} + +void QMafwWatchletPlayer::pause() +{ + if (!_renderer) return; + _renderer->pause(); +} + +void QMafwWatchletPlayer::stop() +{ + if (!_renderer) return; + _renderer->stop(); +} + +void QMafwWatchletPlayer::next() +{ + if (!_renderer) return; + qDebug() << "next"; + _renderer->next(); +} + +void QMafwWatchletPlayer::previous() +{ + if (!_renderer) return; + _renderer->previous(); +} + +void QMafwWatchletPlayer::volumeUp() +{ + if (!_renderer) return; + QString prop("volume"); + _renderer->mafwProperty(prop, qobject_cast<QObject*>(this), SLOT(doVolumeUp(QString,QVariant))); +} + +void QMafwWatchletPlayer::volumeDown() +{ + if (!_renderer) return; + QString prop("volume"); + _renderer->mafwProperty(prop, qobject_cast<QObject*>(this), SLOT(doVolumeDown(QString,QVariant))); +} + +void QMafwWatchletPlayer::setRenderer(MafwRenderer * renderer) +{ + if (_renderer && _active) { + disconnect(_renderer, 0, this, 0); + } + _renderer = renderer; + reconnect(); + if (!_renderer && _active) { + _imageUrl.clear(); + _title = tr("No media"); + emit imageUrlChanged(); + emit titleChanged(); + } +} + +void QMafwWatchletPlayer::reconnect() +{ + if (_renderer && _active) { + connect(_renderer, SIGNAL(metadataChanged(const QString&, const QList<QVariant>&)), + this, SLOT(handleChangedMetadata(const QString&, const QList<QVariant>&))); + connect(_renderer, SIGNAL(stateChanged(MafwRenderer::State)), + this, SLOT(handleChangedState(MafwRenderer::State))); + _renderer->getCurrentMediaInfo(this, SLOT(handleMediaInfo(MafwMediaInfo))); + } else if (_renderer) { + disconnect(_renderer, 0, this, 0); + } +} + +QString QMafwWatchletPlayer::stripAlbumArtComponent(const QString& component) +{ + static QRegExp rsb("\\[.*\\]"); + static QRegExp rfb("{.*}"); + static QRegExp rrb("\\(.*\\)"); + static QRegExp stripB("^[()_{}[]!@#$^&*+=|\\\\/\"'?<>~`\\s\\t]*"); + static QRegExp stripE("[()_{}[]!@#$^&*+=|\\\\/\"'?<>~`\\s\\t]*$"); + QString s(component); + s = s.replace(rsb, ""); + s = s.replace(rfb, ""); + s = s.replace(rrb, ""); + s = s.replace(stripB, ""); + s = s.replace(stripE, ""); + s = s.replace(" ", " "); + s = s.replace("\t", " "); + s = s.toLower(); + return s; +} + +QString QMafwWatchletPlayer::mediaArtPath() const +{ + QDir dir(QDir::homePath() + "/.cache/media-art/"); + QString album = stripAlbumArtComponent(_album); + QString artist = stripAlbumArtComponent(_artist); + QByteArray first_hash = QCryptographicHash::hash(artist.toUtf8(), QCryptographicHash::Md5).toHex(); + QByteArray second_hash = QCryptographicHash::hash(album.toUtf8(), QCryptographicHash::Md5).toHex(); + QString file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData()); + qDebug() << "testing" << file; + if (dir.exists(file)) { + return dir.absoluteFilePath(file); + } + + artist = " "; + first_hash = QCryptographicHash::hash(artist.toUtf8(), QCryptographicHash::Md5).toHex(); + file = QString("album-%1-%2.jpeg").arg(first_hash.constData()).arg(second_hash.constData()); + qDebug() << "testing" << file; + if (dir.exists(file)) { + return dir.absoluteFilePath(file); + } + + return QString(); +} + +void QMafwWatchletPlayer::handleChangedMetadata(const QString &s, const QList<QVariant> &l) +{ + if (l.isEmpty()) return; + if (s == MAFW_METADATA_KEY_TITLE) { + _title = l[0].toString(); + emit titleChanged(); + } else if (s == MAFW_METADATA_KEY_ALBUM) { + _album = l[0].toString(); + emit albumChanged(); + _imageUrl = QUrl::fromLocalFile(mediaArtPath()); + qDebug() << "got image url (album)" << _album << _imageUrl; + emit imageUrlChanged(); + } else if (s == MAFW_METADATA_KEY_ARTIST) { + _artist = l[0].toString(); + emit artistChanged(); + _imageUrl = QUrl::fromLocalFile(mediaArtPath()); + qDebug() << "got image url (artist)" << _album << _imageUrl; + emit imageUrlChanged(); + } +} + +void QMafwWatchletPlayer::handleChangedState(MafwRenderer::State state) +{ + _state = state; +} + +void QMafwWatchletPlayer::handleMediaInfo(const MafwMediaInfo &info) +{ + const QMap<QString, QList<QVariant> > & data = info.metaData(); + handleChangedMetadata(MAFW_METADATA_KEY_TITLE, data[MAFW_METADATA_KEY_TITLE]); + handleChangedMetadata(MAFW_METADATA_KEY_ALBUM, data[MAFW_METADATA_KEY_ALBUM]); +} + +void QMafwWatchletPlayer::doVolumeUp(const QString& name, const QVariant& value) +{ + _renderer->setMafwProperty(name, value.toUInt() + 10); +} + +void QMafwWatchletPlayer::doVolumeDown(const QString& name, const QVariant& value) +{ + _renderer->setMafwProperty(name, value.toUInt() - 10); +} diff --git a/qmafwwatchlet/qmafwwatchletplayer.h b/qmafwwatchlet/qmafwwatchletplayer.h new file mode 100644 index 0000000..d85f38c --- /dev/null +++ b/qmafwwatchlet/qmafwwatchletplayer.h @@ -0,0 +1,81 @@ +#ifndef QMAFWWATCHLETPLAYER_H +#define QMAFWWATCHLETPLAYER_H + +#include <QtCore/QUrl> + +#include <sowatch.h> + +#include <MafwRenderer.h> +#include <MafwMediaInfo.h> + +namespace sowatch +{ + +class QMafwWatchlet; + +class QMafwWatchletPlayer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString title READ title NOTIFY titleChanged) + Q_PROPERTY(QString album READ album NOTIFY albumChanged) + Q_PROPERTY(QString artist READ artist NOTIFY artistChanged) + Q_PROPERTY(QUrl imageUrl READ imageUrl NOTIFY imageUrlChanged) + +public: + explicit QMafwWatchletPlayer(QMafwWatchlet* watchlet); + + QString title() const; + QString album() const; + QString artist() const; + QUrl imageUrl() const; + +signals: + void titleChanged(); + void albumChanged(); + void artistChanged(); + void imageUrlChanged(); + +public slots: + void activate(); + void deactivate(); + + void playPause(); + void play(); + void pause(); + void stop(); + void next(); + void previous(); + + void volumeUp(); + void volumeDown(); + +private: + bool _active; + MafwRenderer* _renderer; + MafwRenderer::State _state; + QString _title; + QString _album; + QString _artist; + QUrl _imageUrl; + + void setRenderer(MafwRenderer*); + void reconnect(); + + static QString stripAlbumArtComponent(const QString& component); + QString mediaArtPath() const; + +private slots: + void handleChangedMetadata(const QString& s, const QList<QVariant>& l); + void handleChangedState(MafwRenderer::State state); + void handleMediaInfo(const MafwMediaInfo& info); + void doVolumeUp(const QString& name, const QVariant& value); + void doVolumeDown(const QString& name, const QVariant& value); + + friend class QMafwWatchlet; +}; + +} + +QML_DECLARE_TYPE(sowatch::QMafwWatchletPlayer) + +#endif // QMAFWWATCHLETPLAYER_H diff --git a/qmafwwatchlet/qmafwwatchletplugin.cpp b/qmafwwatchlet/qmafwwatchletplugin.cpp new file mode 100644 index 0000000..09984b4 --- /dev/null +++ b/qmafwwatchlet/qmafwwatchletplugin.cpp @@ -0,0 +1,29 @@ +#include "qmafwwatchlet.h" +#include "qmafwwatchletplugin.h" + +using namespace sowatch; + +QMafwWatchletPlugin::QMafwWatchletPlugin(QObject *parent) : + QObject(parent) +{ +} + +QMafwWatchletPlugin::~QMafwWatchletPlugin() +{ +} + +QStringList QMafwWatchletPlugin::watchlets() +{ + QStringList l; + l << "com.javispedro.sowatch.qmafw"; + return l; +} + +Watchlet* QMafwWatchletPlugin::getWatchlet(const QString& driver, QSettings& settings, WatchServer *server) +{ + Q_UNUSED(driver); + Q_UNUSED(settings); + return new QMafwWatchlet(server); +} + +Q_EXPORT_PLUGIN2(qmafwwatchlet, QMafwWatchletPlugin) diff --git a/qmafwwatchlet/qmafwwatchletplugin.h b/qmafwwatchlet/qmafwwatchletplugin.h new file mode 100644 index 0000000..c4ff3ef --- /dev/null +++ b/qmafwwatchlet/qmafwwatchletplugin.h @@ -0,0 +1,24 @@ +#ifndef QMAFWPLUGIN_H +#define QMAFWPLUGIN_H + +#include <sowatch.h> + +namespace sowatch +{ + +class QMafwWatchletPlugin : public QObject, public WatchletPluginInterface +{ + Q_OBJECT + Q_INTERFACES(sowatch::WatchletPluginInterface) + +public: + explicit QMafwWatchletPlugin(QObject *parent = 0); + ~QMafwWatchletPlugin(); + + QStringList watchlets(); + Watchlet* getWatchlet(const QString& driver, QSettings& settings, WatchServer* server); +}; + +} + +#endif // QMAFWPLUGIN_H diff --git a/sowatch.pro b/sowatch.pro index 6d850ef..90e1eb1 100644 --- a/sowatch.pro +++ b/sowatch.pro @@ -5,7 +5,7 @@ SUBDIRS = libsowatch \ sysinfowatchlet !isEmpty(MEEGO_VERSION_MAJOR) { - SUBDIRS += meegohandsetnotification ckitcallnotification + SUBDIRS += meegohandsetnotification ckitcallnotification qmafwwatchlet } unix:!symbian { diff --git a/sysinfowatchlet/sysinfowatchlet.cpp b/sysinfowatchlet/sysinfowatchlet.cpp index c9f44c2..9e4bbf2 100644 --- a/sysinfowatchlet/sysinfowatchlet.cpp +++ b/sysinfowatchlet/sysinfowatchlet.cpp @@ -21,6 +21,6 @@ void SysInfoWatchlet::handleActivated() if (cfgs.size() > 0) { rootContext()->setContextProperty("networkName", cfgs[0].name()); } else { - rootContext()->setContextProperty("networkName", ""); + rootContext()->setContextProperty("networkName", "-"); } } diff --git a/sysinfowatchlet/sysinfowatchlet.pro b/sysinfowatchlet/sysinfowatchlet.pro index 8c87ad8..ebbaf9c 100644 --- a/sysinfowatchlet/sysinfowatchlet.pro +++ b/sysinfowatchlet/sysinfowatchlet.pro @@ -6,7 +6,7 @@ TARGET = sysinfowatchlet TEMPLATE = lib -# CONFIG += plugin # Stupid Qt creator doesn't want to deploy plugins +# CONFIG += plugin # Qt creator doesn't want to deploy plugins QT += network CONFIG += mobility MOBILITY += systeminfo @@ -15,7 +15,10 @@ SOURCES += sysinfoplugin.cpp sysinfowatchlet.cpp HEADERS += sysinfoplugin.h sysinfowatchlet.h -unix: LIBS += -L$$OUT_PWD/../libsowatch/ -lsowatch +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../libsowatch/release/ -lsowatch +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../libsowatch/debug/ -lsowatch +else:symbian: LIBS += -lsowatch +else:unix: LIBS += -L$$OUT_PWD/../libsowatch/ -lsowatch INCLUDEPATH += $$PWD/../libsowatch DEPENDPATH += $$PWD/../libsowatch @@ -34,11 +37,3 @@ OTHER_FILES += \ RESOURCES += \ sysinfowatchlet.qrc - - - - - - - - |