summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier S. Pedro <maemo@javispedro.com>2013-06-15 20:35:33 +0200
committerJavier S. Pedro <maemo@javispedro.com>2013-06-15 20:35:33 +0200
commit378611f629abc146eaf0b13301f119d826edb86b (patch)
tree3f2447b75bfe155bbb013b07e08f2922d23a0f3a
parenta3797790c7da7a5c88005735619dc56a96264930 (diff)
downloadsowatch-378611f629abc146eaf0b13301f119d826edb86b.tar.gz
sowatch-378611f629abc146eaf0b13301f119d826edb86b.zip
add some support for notifications in liveview
-rw-r--r--libsowatch/notificationsmodel.cpp90
-rw-r--r--libsowatch/notificationsmodel.h9
-rw-r--r--libsowatch/watchserver.cpp3
-rw-r--r--liveview/liveview.cpp339
-rw-r--r--liveview/liveview.h48
-rw-r--r--liveview/liveviewpaintengine.cpp6
-rw-r--r--nekowatchlet/liveview-icon.pngbin225 -> 308 bytes
-rw-r--r--qmafwwatchlet/liveview-icon.pngbin0 -> 1328 bytes
-rw-r--r--qmapwatchlet/map-liveview-icon.pngbin207 -> 1450 bytes
-rw-r--r--qmsgwatchlet/liveview-icon.pngbin0 -> 1370 bytes
-rw-r--r--qmsgwatchlet/metawatch-digital-icon.pngbin0 -> 258 bytes
-rw-r--r--qorgwatchlet/liveview-icon.pngbin0 -> 1162 bytes
-rw-r--r--sysinfowatchlet/liveview-icon.pngbin0 -> 1412 bytes
-rw-r--r--testnotification/testnotificationprovider.cpp2
14 files changed, 408 insertions, 89 deletions
diff --git a/libsowatch/notificationsmodel.cpp b/libsowatch/notificationsmodel.cpp
index 53b714e..16f6692 100644
--- a/libsowatch/notificationsmodel.cpp
+++ b/libsowatch/notificationsmodel.cpp
@@ -22,17 +22,13 @@ NotificationsModel::NotificationsModel(QObject *parent) :
int NotificationsModel::rowCount(const QModelIndex &parent) const
{
- int count = 0;
Q_UNUSED(parent);
- FOREACH_TYPE(type) {
- count += _list[type].count();
- }
- return count;
+ return size();
}
QVariant NotificationsModel::data(const QModelIndex &index, int role) const
{
- const Notification *n = getNotificationByIndex(index.row());
+ const Notification *n = at(index.row());
if (!n) return QVariant();
switch (role) {
case Qt::DisplayRole:
@@ -47,6 +43,63 @@ QVariant NotificationsModel::data(const QModelIndex &index, int role) const
return QVariant();
}
+int NotificationsModel::size() const
+{
+ int count = 0;
+ FOREACH_TYPE(type) {
+ count += _list[type].count();
+ }
+ return count;
+}
+
+int NotificationsModel::size(const QList<Notification::Type>& types) const
+{
+ int count = 0;
+ foreach(Notification::Type type, types) {
+ count += _list[type].count();
+ }
+ return count;
+}
+
+Notification * NotificationsModel::at(int position) const
+{
+ FOREACH_TYPE(type) {
+ const int size = _list[type].size();
+ if (position < size) {
+ return _list[type].at(position);
+ } else {
+ position -= size;
+ }
+ }
+ qWarning() << "Notification with index" << position << "not found";
+ return 0;
+}
+
+Notification * NotificationsModel::at(Notification::Type type, int position) const
+{
+ const int size = _list[type].size();
+ if (position < size) {
+ return _list[type].at(position);
+ } else {
+ qWarning() << "Notification with index" << position << "not found";
+ return 0;
+ }
+}
+
+Notification * NotificationsModel::at(const QList<Notification::Type>& types, int position) const
+{
+ foreach(Notification::Type type, types) {
+ const int size = _list[type].size();
+ if (position < size) {
+ return _list[type].at(position);
+ } else {
+ position -= size;
+ }
+ }
+ qWarning() << "Notification with index" << position << "not found";
+ return 0;
+}
+
void NotificationsModel::add(Notification *n)
{
const Notification::Type type = n->type();
@@ -83,6 +136,17 @@ void NotificationsModel::remove(Notification::Type type, Notification *n)
emit modelChanged();
}
+int NotificationsModel::countByType(Notification::Type type) const
+{
+ int count = 0;
+ Q_FOREACH(const Notification *n, _list[type]) {
+ if (n->priority() != Notification::Silent) {
+ count++;
+ }
+ }
+ return count;
+}
+
int NotificationsModel::fullCount() const
{
int count = 0;
@@ -160,20 +224,6 @@ int NotificationsModel::getIndexForNotification(Notification *n) const
return getOffsetForType(type) + subindex;
}
-const Notification * NotificationsModel::getNotificationByIndex(int index) const
-{
- FOREACH_TYPE(type) {
- const int size = _list[type].size();
- if (index < size) {
- return _list[type].at(index);
- } else {
- index -= size;
- }
- }
- qWarning() << "Notification with index" << index << "not found";
- return 0;
-}
-
void NotificationsModel::handleNotificationChanged()
{
QObject *obj = sender();
diff --git a/libsowatch/notificationsmodel.h b/libsowatch/notificationsmodel.h
index ffd8ab7..86ed2af 100644
--- a/libsowatch/notificationsmodel.h
+++ b/libsowatch/notificationsmodel.h
@@ -24,10 +24,18 @@ public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
+ int size() const;
+ int size(const QList<Notification::Type>& types) const;
+ Notification* at(int position) const;
+ Notification* at(Notification::Type type, int position) const;
+ Notification* at(const QList<Notification::Type>& types, int position) const;
+
void add(Notification *n);
void remove(Notification *n);
void remove(Notification::Type type, Notification *n);
+ Q_INVOKABLE int countByType(Notification::Type type) const;
+
Q_INVOKABLE int fullCount() const;
Q_INVOKABLE int fullCountByType(Notification::Type type) const;
Q_INVOKABLE int fullCountByType(int type) const; // See QTBUG-26415
@@ -44,7 +52,6 @@ private:
int getOffsetForType(Notification::Type type) const;
int getAppendOffsetForType(Notification::Type type) const;
int getIndexForNotification(Notification *n) const;
- const Notification* getNotificationByIndex(int index) const;
private slots:
void handleNotificationChanged();
diff --git a/libsowatch/watchserver.cpp b/libsowatch/watchserver.cpp
index da93730..373d367 100644
--- a/libsowatch/watchserver.cpp
+++ b/libsowatch/watchserver.cpp
@@ -32,6 +32,7 @@ WatchServer::WatchServer(Watch* watch, QObject* parent) :
_watchlets->setWatchModel(_watch->model());
_watch->setWatchletsModel(_watchlets);
+ _watch->setNotificationsModel(_notifications);
}
Watch* WatchServer::watch()
@@ -242,7 +243,7 @@ void WatchServer::closeWatchlet()
deactivateActiveWatchlet();
}
_currentWatchlet = 0;
- if (_watch->isConnected() && _pendingNotifications.empty()) {
+ if (_watch->isConnected()) {
goToIdle();
}
}
diff --git a/liveview/liveview.cpp b/liveview/liveview.cpp
index f293bd9..450e802 100644
--- a/liveview/liveview.cpp
+++ b/liveview/liveview.cpp
@@ -8,21 +8,24 @@ QTM_USE_NAMESPACE
#define PROTOCOL_DEBUG 1
+const int LiveView::MaxBitmapSize = 64;
+QMap<LiveView::MessageType, LiveView::MessageType> LiveView::_ackMap;
+QList<LiveView::RootMenuNotificationItem> LiveView::_rootNotificationItems;
+
LiveView::LiveView(ConfigKey* settings, QObject* parent) :
BluetoothWatch(QBluetoothAddress(settings->value("address").toString()), parent),
_settings(settings->getSubkey(QString(), this)),
- _watchlets(0),
+ _watchlets(0), _notifications(0),
_24hMode(settings->value("24h-mode", false).toBool()),
_screenWidth(0), _screenHeight(0),
_mode(RootMenuMode),
_paintEngine(0),
_rootMenuFirstWatchlet(0),
- _sendTimer(new QTimer(this))
+ _waitingForAck(NoMessage)
{
- _sendTimer->setInterval(DelayBetweenMessages);
- connect(_sendTimer, SIGNAL(timeout()), SLOT(handleSendTimerTick()));
-
+ initializeAckMap();
_buttons << "Select" << "Up" << "Down" << "Left" << "Right";
+ initializeRootNotificationItems();
}
LiveView::~LiveView()
@@ -82,7 +85,7 @@ bool LiveView::busy() const
{
return !_connected ||
_socket->state() != QBluetoothSocket::ConnectedState ||
- _sendingMsgs.size() > 20;
+ _sendingMsgs.size() > 1;
}
void LiveView::setDateTime(const QDateTime& dateTime)
@@ -126,6 +129,7 @@ bool LiveView::charging() const
void LiveView::displayIdleScreen()
{
+ qDebug() << "LiveView display idle screen (cur mode=" << _mode << ")";
if (_mode != RootMenuMode) {
_mode = RootMenuMode;
refreshMenu();
@@ -134,7 +138,7 @@ void LiveView::displayIdleScreen()
void LiveView::displayNotification(Notification *notification)
{
-
+ qDebug() << "LiveView display notification" << notification->title();
}
void LiveView::displayApplication()
@@ -160,6 +164,19 @@ void LiveView::setWatchletsModel(WatchletsModel *model)
}
}
+void LiveView::setNotificationsModel(NotificationsModel *model)
+{
+ qDebug() << Q_FUNC_INFO;
+ if (_notifications) {
+ disconnect(_notifications, 0, this, 0);
+ }
+ _notifications = model;
+ if (_notifications) {
+ connect(_notifications, SIGNAL(modelChanged()), SLOT(handleNotificationsChanged()));
+ handleNotificationsChanged();
+ }
+}
+
QImage* LiveView::image()
{
return &_image;
@@ -167,11 +184,25 @@ QImage* LiveView::image()
void LiveView::renderImage(int x, int y, const QImage &image)
{
+ const QSize image_size = image.size();
qDebug() << "Rendering image at" << x << 'x' << y << "of size" << image.size();
- QByteArray data = encodeImage(image.copy(0,0,64,64));
- if (!data.isEmpty()) {
- displayBitmap(x, y, data);
+ QByteArray data;
+ if (image.size().isEmpty()) {
+ return; // Empty image
}
+
+ if (image_size.width() > MaxBitmapSize || image_size.height() > MaxBitmapSize) {
+ const QRect new_size(0, 0,
+ qMin(MaxBitmapSize, image_size.width()),
+ qMin(MaxBitmapSize, image_size.height()));
+ data = encodeImage(image.copy(new_size));
+ } else {
+ data = encodeImage(image);
+ }
+
+ Q_ASSERT(!data.isEmpty());
+
+ displayBitmap(x, y, data);
}
void LiveView::clear()
@@ -179,9 +210,53 @@ void LiveView::clear()
displayClear();
}
+void LiveView::initializeAckMap()
+{
+ if (_ackMap.empty()) {
+ _ackMap[GetDisplayProperties] = GetDisplayPropertiesResponse;
+ _ackMap[DeviceStatusChange] = DeviceStatusChangeResponse;
+ _ackMap[DisplayBitmap] = DisplayBitmapResponse;
+ _ackMap[DisplayClear] = DisplayClearResponse;
+ //_ackMap[SetMenuSize] = SetMenuSizeResponse; // fw does not send this, for some reason.
+ _ackMap[EnableLed] = EnableLedResponse;
+ }
+}
+
+LiveView::MessageType LiveView::ackForMessage(MessageType type)
+{
+ QMap<MessageType, MessageType>::const_iterator i = _ackMap.constFind(type);
+ if (i != _ackMap.constEnd()) {
+ return i.value();
+ }
+ return NoMessage;
+}
+
+void LiveView::initializeRootNotificationItems()
+{
+ if (_rootNotificationItems.empty()) {
+ RootMenuNotificationItem item;
+ item.icon = encodeImage(QUrl::fromLocalFile(SOWATCH_RESOURCES_DIR "/liveview/graphics/menu_missed_calls.png"));
+ item.title = tr("Missed calls");
+ item.notificationTypes.append(Notification::MissedCallNotification);
+ _rootNotificationItems.append(item);
+
+ item.icon = encodeImage(QUrl::fromLocalFile(SOWATCH_RESOURCES_DIR "/liveview/graphics/menu_notifications.png"));
+ item.title = tr("Events");
+ // All other notifications
+ item.notificationTypes.append(Notification::OtherNotification);
+ item.notificationTypes.append(Notification::SmsNotification);
+ item.notificationTypes.append(Notification::MmsNotification);
+ item.notificationTypes.append(Notification::ImNotification);
+ item.notificationTypes.append(Notification::EmailNotification);
+ item.notificationTypes.append(Notification::CalendarNotification);
+ _rootNotificationItems.append(item);
+ }
+}
+
void LiveView::setupBluetoothWatch()
{
_mode = RootMenuMode;
+ _waitingForAck = NoMessage;
connect(_socket, SIGNAL(readyRead()), SLOT(handleDataReceived()));
updateDisplayProperties();
@@ -190,10 +265,38 @@ void LiveView::setupBluetoothWatch()
void LiveView::desetupBluetoothWatch()
{
- _sendTimer->stop();
_sendingMsgs.clear();
}
+void LiveView::recreateNotificationsMenu()
+{
+ // Erase all current notifications from the menu
+ QList<RootMenuItem>::iterator it = _rootMenu.begin();
+ it += _rootMenuFirstWatchlet;
+ _rootMenu.erase(_rootMenu.begin(), it);
+
+ _rootMenuFirstWatchlet = 0;
+
+ if (_notifications) {
+ foreach (const RootMenuNotificationItem& nitem, _rootNotificationItems) {
+ int count = 0;
+ foreach (Notification::Type type, nitem.notificationTypes) {
+ count += _notifications->countByType(type);
+ }
+ if (count > 0) {
+ RootMenuItem item;
+ item.type = MenuNotificationList;
+ item.title = nitem.title;
+ item.icon = nitem.icon;
+ item.unread = count;
+ item.notificationItem = &nitem;
+ _rootMenu.insert(_rootMenuFirstWatchlet, item);
+ _rootMenuFirstWatchlet++;
+ }
+ }
+ }
+}
+
void LiveView::recreateWatchletsMenu()
{
// Erase all current watchlets frm the menu
@@ -208,6 +311,9 @@ void LiveView::recreateWatchletsMenu()
QModelIndex index = _watchlets->index(i);
item.type = MenuOther;
item.title = _watchlets->data(index, WatchletsModel::TitleRole).toString();
+ if (item.title.isEmpty()) {
+ qWarning() << "Watchlet" << _watchlets->at(i)->id() << "without title";
+ }
item.icon = encodeImage(_watchlets->data(index, WatchletsModel::IconRole).toUrl());
item.unread = 0;
item.watchletId = _watchlets->at(i)->id();
@@ -223,7 +329,7 @@ void LiveView::refreshMenu()
}
}
-QByteArray LiveView::encodeImage(const QImage& image) const
+QByteArray LiveView::encodeImage(const QImage& image)
{
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
@@ -235,7 +341,7 @@ QByteArray LiveView::encodeImage(const QImage& image) const
}
}
-QByteArray LiveView::encodeImage(const QUrl& url) const
+QByteArray LiveView::encodeImage(const QUrl& url)
{
if (url.encodedPath().endsWith(".png")) {
// Just load the image
@@ -257,8 +363,10 @@ void LiveView::send(const Message &msg)
{
Q_ASSERT(_connected);
_sendingMsgs.enqueue(msg);
- if (!_sendTimer->isActive()) {
- _sendTimer->start();
+ if (_waitingForAck == NoMessage) {
+ sendMessageFromQueue();
+ } else {
+ qDebug() << "Enqueing message while waiting for ack" << _waitingForAck;
}
}
@@ -323,6 +431,36 @@ void LiveView::sendMenuItem(unsigned char id, MenuItemType type, unsigned short
send(Message(MenuItemResponse, data));
}
+void LiveView::sendNotification(unsigned short id, unsigned short unread, unsigned short count, const QString &date, const QString &header, const QString &body, const QByteArray &image)
+{
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+
+ ds << quint8(0); // Unknown
+ ds << quint16(count);
+ ds << quint16(unread);
+ ds << quint16(id);
+ ds << quint8(0) << quint8(0); // Unknown
+
+ QByteArray str = date.toLatin1();
+ ds << quint16(str.length());
+ ds.writeRawData(str.constData(), str.length());
+
+ str = header.toLatin1();
+ ds << quint16(str.length());
+ ds.writeRawData(str.constData(), str.length());
+
+ str = body.toLatin1();
+ ds << quint16(str.length());
+ ds.writeRawData(str.constData(), str.length());
+
+ ds << quint8(0) << quint8(0) << quint8(0); // Unknown
+ ds << quint16(image.length());
+ ds.writeRawData(image.constData(), image.size());
+
+ send(Message(NotificationResponse, data));
+}
+
void LiveView::enableLed(const QColor& color, unsigned short delay, unsigned short time)
{
QByteArray data;
@@ -345,6 +483,11 @@ void LiveView::enableLed(const QColor& color, unsigned short delay, unsigned sho
void LiveView::handleMessage(const Message &msg)
{
send(Message(Ack, QByteArray(1, msg.type)));
+ if (msg.type == _waitingForAck) {
+ qDebug() << "Got ack to" << _waitingForAck;
+ _waitingForAck = NoMessage;
+ sendMessageFromQueue();
+ }
switch (msg.type) {
case DeviceStatusChange:
handleDeviceStatusChange(msg);
@@ -400,8 +543,79 @@ void LiveView::handleMenuItemRequest(const Message &msg)
void LiveView::handleNotificationRequest(const Message &msg)
{
- // TODO
- sendResponse(NotificationResponse, ResponseError); // TODO Crashes the watch
+ if (msg.data.size() < 4) {
+ // Packet too small
+ sendResponse(NotificationResponse, ResponseError);
+ return;
+ }
+
+ int menu_id = static_cast<unsigned char>(msg.data[0]);
+ NotificationAction action = static_cast<NotificationAction>(msg.data[1]);
+ unsigned int max_size = static_cast<unsigned char>(msg.data[2]) << 8;
+ max_size |= static_cast<unsigned char>(msg.data[3]);
+ qDebug() << "notification rq" << action << menu_id << "(" << max_size << ")";
+
+ if (menu_id >= _rootMenu.size()) {
+ sendNotification(0, 0, 0, "", "", "", QByteArray());
+ return;
+ }
+
+ const RootMenuNotificationItem *notification_item = _rootMenu[menu_id].notificationItem;
+ if (!notification_item) {
+ sendNotification(0, 0, 0, "", "", "", QByteArray());
+ return;
+ }
+
+ const QList<Notification::Type> &notification_types = notification_item->notificationTypes;
+ const int num_notifications = _notifications->size(notification_types);
+
+ if (_mode != NotificationListMode) {
+ _mode = NotificationListMode;
+ _curNotificationIndex = 0;
+ }
+
+ switch (action) {
+ case NotificationShowFirst:
+ _curNotificationIndex = 0;
+ break;
+ case NotificationShowLast:
+ _curNotificationIndex = num_notifications - 1;
+ break;
+ case NotificationShowPrev:
+ if (_curNotificationIndex > 0) {
+ _curNotificationIndex--;
+ } else {
+ _curNotificationIndex = 0;
+ }
+ break;
+ case NotificationShowNext:
+ if (_curNotificationIndex < num_notifications - 1) {
+ _curNotificationIndex++;
+ } else {
+ _curNotificationIndex = num_notifications - 1;
+ }
+ break;
+ case NotificationShowCurrent:
+ if (_curNotificationIndex >= num_notifications - 1 ||
+ _curNotificationIndex < 0) {
+ _curNotificationIndex = 0;
+ }
+ break;
+ }
+
+ const Notification *notification = _notifications->at(notification_types,
+ _curNotificationIndex);
+ if (!notification) {
+ sendNotification(_curNotificationIndex, num_notifications, num_notifications,
+ "", "", "", QByteArray());
+ return;
+ }
+
+ sendNotification(_curNotificationIndex, num_notifications, num_notifications,
+ notification->dateTime().toString(Qt::SystemLocaleShortDate),
+ notification->title(),
+ notification->body(),
+ QByteArray());
}
void LiveView::handleNavigation(const Message &msg)
@@ -438,6 +652,10 @@ void LiveView::handleNavigation(const Message &msg)
sendResponse(NavigationResponse, ResponseCancel);
emit closeWatchledRequested();
return;
+ } else if (_mode == NotificationListMode) {
+ sendResponse(NavigationResponse, ResponseCancel);
+ _mode = RootMenuMode;
+ return;
}
break;
case SelectMenu:
@@ -446,7 +664,7 @@ void LiveView::handleNavigation(const Message &msg)
switch(_rootMenu[item_id].type) {
case MenuNotificationList:
- Q_ASSERT(false); // TODO
+ // This should not happen!
break;
case MenuOther:
emit watchletRequested(_rootMenu[item_id].watchletId);
@@ -467,9 +685,12 @@ void LiveView::handleNavigation(const Message &msg)
void LiveView::handleMenuItemsRequest(const Message &msg)
{
qDebug() << "Sending menu items";
+ if (_mode == NotificationListMode) {
+ _mode = RootMenuMode; // Switch to the root menu
+ }
if (_mode == RootMenuMode) {
for (int i = 0; i < _rootMenu.size(); i++) {
- qDebug() << "Sending one menu item";
+ qDebug() << "Sending one menu item" << _rootMenu[i].title;
sendMenuItem(i, _rootMenu[i].type, _rootMenu[i].unread,
_rootMenu[i].title, _rootMenu[i].icon);
}
@@ -522,6 +743,43 @@ void LiveView::handleSoftwareVersion(const Message &msg)
<< QString::fromAscii(msg.data.constData(), msg.data.size());
}
+
+void LiveView::sendMessageFromQueue()
+{
+ static const int HEADER_SIZE = 6;
+ Q_ASSERT(_waitingForAck == NoMessage);
+
+ // If there are packets to be sent...
+ while (!_sendingMsgs.empty()) {
+ // Send a message to the watch
+ Message msg = _sendingMsgs.dequeue();
+ const quint32 data_size = msg.data.size();
+ QByteArray packet;
+
+ Q_ASSERT(_connected && _socket);
+
+ packet.resize(HEADER_SIZE + data_size);
+ packet[0] = msg.type;
+ packet[1] = HEADER_SIZE - 2;
+ packet[2] = (data_size & 0xFF000000U) >> 24;
+ packet[3] = (data_size & 0x00FF0000U) >> 16;
+ packet[4] = (data_size & 0x0000FF00U) >> 8;
+ packet[5] = (data_size & 0x000000FFU);
+ packet.replace(HEADER_SIZE, data_size, msg.data);
+
+#if PROTOCOL_DEBUG
+ qDebug() << "sending" << msg.type << packet.mid(6, 24).toHex();
+#endif
+
+ _socket->write(packet);
+
+ _waitingForAck = ackForMessage(msg.type);
+ if (_waitingForAck != NoMessage) {
+ break; // Wait for that ack before sending more messages.
+ }
+ }
+}
+
void LiveView::handleDataReceived()
{
#pragma pack(push)
@@ -597,48 +855,17 @@ void LiveView::handleDataReceived()
} while (_socket->bytesAvailable() > 0);
}
-void LiveView::handleSendTimerTick()
+void LiveView::handleWatchletsChanged()
{
- static const int HEADER_SIZE = 6;
-
- // If there are packets to be sent...
- if (!_sendingMsgs.empty()) {
- // Send a message to the watch
- Message msg = _sendingMsgs.dequeue();
- const quint32 data_size = msg.data.size();
- QByteArray packet;
-
- Q_ASSERT(_connected && _socket);
-
- packet.resize(HEADER_SIZE + data_size);
- packet[0] = msg.type;
- packet[1] = HEADER_SIZE - 2;
- packet[2] = (data_size & 0xFF000000U) >> 24;
- packet[3] = (data_size & 0x00FF0000U) >> 16;
- packet[4] = (data_size & 0x0000FF00U) >> 8;
- packet[5] = (data_size & 0x000000FFU);
- packet.replace(HEADER_SIZE, data_size, msg.data);
-
-#if PROTOCOL_DEBUG
- if (packet.size() < 20) {
- qDebug() << "sending" << packet.toHex();
- } else {
- qDebug() << "sending" << packet.left(20).toHex() << "...";
- }
-#endif
-
- _socket->write(packet);
- }
- // If we just finished sending all packets...
- if (_sendingMsgs.empty()) {
- // Stop the send timer to save battery
- _sendTimer->stop();
+ recreateWatchletsMenu();
+ if (_connected) {
+ refreshMenu();
}
}
-void LiveView::handleWatchletsChanged()
+void LiveView::handleNotificationsChanged()
{
- recreateWatchletsMenu();
+ recreateNotificationsMenu();
if (_connected) {
refreshMenu();
}
diff --git a/liveview/liveview.h b/liveview/liveview.h
index aba5b32..b85a574 100644
--- a/liveview/liveview.h
+++ b/liveview/liveview.h
@@ -42,6 +42,9 @@ public:
void vibrate(int msecs);
void setWatchletsModel(WatchletsModel *model);
+ void setNotificationsModel(NotificationsModel *model);
+
+ static const int MaxBitmapSize;
// Only for application mode
QImage* image();
@@ -51,7 +54,7 @@ public:
void clear();
protected:
- static const int DelayBetweenMessages = 10;
+ static const int DelayBetweenMessages = 200;
enum MessageType {
NoMessage = 0,
@@ -102,7 +105,8 @@ protected:
enum Mode {
RootMenuMode = 0,
- ApplicationMode
+ ApplicationMode,
+ NotificationListMode
};
enum NavigationEvent {
@@ -116,6 +120,14 @@ protected:
SelectMenu = 32
};
+ enum NotificationAction {
+ NotificationShowCurrent = 0,
+ NotificationShowFirst = 1,
+ NotificationShowLast = 2,
+ NotificationShowNext = 3,
+ NotificationShowPrev = 4
+ };
+
struct Message {
MessageType type;
QByteArray data;
@@ -124,24 +136,40 @@ protected:
{ }
};
+ struct RootMenuNotificationItem {
+ QByteArray icon;
+ QString title;
+ QList<Notification::Type> notificationTypes;
+ };
+
struct RootMenuItem {
MenuItemType type;
QByteArray icon;
QString title;
int unread;
QString watchletId;
+ const RootMenuNotificationItem *notificationItem;
};
+ static QMap<MessageType, MessageType> _ackMap;
+ static void initializeAckMap();
+ static MessageType ackForMessage(MessageType type);
+
+ static QList<RootMenuNotificationItem> _rootNotificationItems;
+ static void initializeRootNotificationItems();
+
void setupBluetoothWatch();
void desetupBluetoothWatch();
+
+ void recreateNotificationsMenu();
/** Recreate the device menu (after watchlets change) */
void recreateWatchletsMenu();
/** Update the device menu (after a power on, etc.) */
void refreshMenu();
- QByteArray encodeImage(const QImage& image) const;
- QByteArray encodeImage(const QUrl& url) const;
+ static QByteArray encodeImage(const QImage& image);
+ static QByteArray encodeImage(const QUrl& url);
protected:
void send(const Message& msg);
@@ -153,6 +181,7 @@ protected:
void displayClear();
void setMenuSize(unsigned char size);
void sendMenuItem(unsigned char id, MenuItemType type, unsigned short unread, const QString& text, const QByteArray& image);
+ void sendNotification(unsigned short id, unsigned short unread, unsigned short count, const QString& date, const QString& header, const QString& body, const QByteArray& image);
void enableLed(const QColor& color, unsigned short delay, unsigned short time);
void handleMessage(const Message& msg);
@@ -165,14 +194,18 @@ protected:
void handleDisplayProperties(const Message& msg);
void handleSoftwareVersion(const Message& msg);
+private:
+ void sendMessageFromQueue();
+
private slots:
void handleDataReceived();
- void handleSendTimerTick();
void handleWatchletsChanged();
+ void handleNotificationsChanged();
private:
ConfigKey *_settings;
WatchletsModel *_watchlets;
+ NotificationsModel *_notifications;
bool _24hMode : 1;
@@ -181,6 +214,7 @@ private:
QStringList _buttons;
Mode _mode;
+ int _curNotificationIndex;
// Required by QPaintDevice
mutable LiveViewPaintEngine* _paintEngine;
@@ -190,9 +224,9 @@ private:
/** Keeps the index of the first watchlet. */
int _rootMenuFirstWatchlet;
- /** Message outbox queue. */
+ /** Outgoing message queue. */
QQueue<Message> _sendingMsgs;
- QTimer* _sendTimer;
+ MessageType _waitingForAck;
/** Incomplete message that is being received. */
Message _receivingMsg;
};
diff --git a/liveview/liveviewpaintengine.cpp b/liveview/liveviewpaintengine.cpp
index 2370477..c073901 100644
--- a/liveview/liveviewpaintengine.cpp
+++ b/liveview/liveviewpaintengine.cpp
@@ -22,13 +22,13 @@ bool LiveViewPaintEngine::end()
if (ret) {
QRect rect = _damaged.boundingRect();
- const int tile_size = 64;
+ const int tile_size = LiveView::MaxBitmapSize;
// Have to make tiles
for (int x = rect.left(); x < rect.right(); x += tile_size) {
for (int y = rect.top(); y < rect.bottom(); y += tile_size) {
QRect tile(x, y,
- qMin(x + tile_size, rect.right()),
- qMin(y + tile_size, rect.bottom()));
+ qMin(tile_size, rect.width()),
+ qMin(tile_size, rect.height()));
QImage sub_image = _watch->image()->copy(tile);
_watch->renderImage(tile.x(), tile.y(), sub_image);
}
diff --git a/nekowatchlet/liveview-icon.png b/nekowatchlet/liveview-icon.png
index cbc5382..394ba77 100644
--- a/nekowatchlet/liveview-icon.png
+++ b/nekowatchlet/liveview-icon.png
Binary files differ
diff --git a/qmafwwatchlet/liveview-icon.png b/qmafwwatchlet/liveview-icon.png
new file mode 100644
index 0000000..5452f4b
--- /dev/null
+++ b/qmafwwatchlet/liveview-icon.png
Binary files differ
diff --git a/qmapwatchlet/map-liveview-icon.png b/qmapwatchlet/map-liveview-icon.png
index 4e9cd9e..10331a1 100644
--- a/qmapwatchlet/map-liveview-icon.png
+++ b/qmapwatchlet/map-liveview-icon.png
Binary files differ
diff --git a/qmsgwatchlet/liveview-icon.png b/qmsgwatchlet/liveview-icon.png
new file mode 100644
index 0000000..63d1c7f
--- /dev/null
+++ b/qmsgwatchlet/liveview-icon.png
Binary files differ
diff --git a/qmsgwatchlet/metawatch-digital-icon.png b/qmsgwatchlet/metawatch-digital-icon.png
new file mode 100644
index 0000000..005d9ee
--- /dev/null
+++ b/qmsgwatchlet/metawatch-digital-icon.png
Binary files differ
diff --git a/qorgwatchlet/liveview-icon.png b/qorgwatchlet/liveview-icon.png
new file mode 100644
index 0000000..6786c4a
--- /dev/null
+++ b/qorgwatchlet/liveview-icon.png
Binary files differ
diff --git a/sysinfowatchlet/liveview-icon.png b/sysinfowatchlet/liveview-icon.png
new file mode 100644
index 0000000..81fcf05
--- /dev/null
+++ b/sysinfowatchlet/liveview-icon.png
Binary files differ
diff --git a/testnotification/testnotificationprovider.cpp b/testnotification/testnotificationprovider.cpp
index 8f1db76..1e9fcdc 100644
--- a/testnotification/testnotificationprovider.cpp
+++ b/testnotification/testnotificationprovider.cpp
@@ -30,7 +30,7 @@ TestNotificationProvider::~TestNotificationProvider()
void TestNotificationProvider::generateInitialNotification()
{
- TestNotification *n = new TestNotification(Notification::EmailNotification,
+ TestNotification *n = new TestNotification(Notification::MissedCallNotification,
"A friend",
"This is a test email notification");
emit incomingNotification(n);