summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qml/cover/CoverPage.qml47
-rw-r--r--qml/pages/WatchPage.qml222
-rw-r--r--qml/waterwatch.qml42
-rw-r--r--rpm/waterwatch.yaml31
-rw-r--r--src/watchconnector.cpp283
-rw-r--r--src/watchconnector.h125
-rw-r--r--src/waterwatch.cpp44
-rw-r--r--waterwatch.desktop7
-rw-r--r--waterwatch.pngbin0 -> 2965 bytes
-rw-r--r--waterwatch.pro20
10 files changed, 821 insertions, 0 deletions
diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml
new file mode 100644
index 0000000..b717b49
--- /dev/null
+++ b/qml/cover/CoverPage.qml
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2013 Jouni Roivas
+ Copyright (C) 2013 Jolla Ltd.
+ Contact: Thomas Perl <thomas.perl@jollamobile.com>
+ All rights reserved.
+
+ You may use this file under the terms of BSD license as follows:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Jolla Ltd nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+
+CoverBackground {
+ Label {
+ id: label
+ anchors.centerIn: parent
+ text: "WaterWatch"
+ }
+ Label {
+ anchors.top: label.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: watchConnector.name
+ font.pointSize: Theme.fontSizeSmall
+ }
+}
diff --git a/qml/pages/WatchPage.qml b/qml/pages/WatchPage.qml
new file mode 100644
index 0000000..743e130
--- /dev/null
+++ b/qml/pages/WatchPage.qml
@@ -0,0 +1,222 @@
+/*
+ Copyright (C) 2013 Jouni Roivas
+ Copyright (C) 2013 Jolla Ltd.
+ Contact: Thomas Perl <thomas.perl@jollamobile.com>
+ All rights reserved.
+
+ You may use this file under the terms of BSD license as follows:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Jolla Ltd nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+import QtQuick 2.0
+import QtQml 2.1
+import Sailfish.Silica 1.0
+import QtBluetooth 5.0
+import Sailfish.Bluetooth 1.0
+import Bluetooth 0.0
+import org.nemomobile.voicecall 1.0
+import org.nemomobile.notifications 1.0
+import watch 0.1
+
+Page {
+ id: page
+ WatchConnector {
+ id: watchConnector
+
+ onHangup: {
+ // Watch instantiated hangup, follow the orders
+ manager.hangupAll();
+ }
+ }
+ property var callerDetails: new Object
+
+ VoiceCallManager {
+ id:manager
+
+ function hangupAll() {
+ for (var index = 0; index < voiceCalls.count; index++) {
+ voiceCalls.instance(index).hangup();
+ }
+ }
+
+ onError: {
+ console.log("Error: "+message)
+ watchConnector.endPhoneCall();
+ }
+
+ function updateState() {
+ //This needs cleaning up...
+ var statusPriority = [
+ VoiceCall.STATUS_ALERTING,
+ VoiceCall.STATUS_DIALING,
+ VoiceCall.STATUS_DISCONNECTED,
+ VoiceCall.STATUS_ACTIVE,
+ VoiceCall.STATUS_HELD,
+ VoiceCall.STATUS_NULL
+ ]
+
+ var newPrimaryCall = null
+ for (var p = 0; p < statusPriority.length; p++) {
+ for (var i = 0; i < voiceCalls.count; i++) {
+ if (voiceCalls.instance(i).status === statusPriority[p]) {
+ newPrimaryCall = voiceCalls.instance(i)
+ break
+ }
+ }
+ if (newPrimaryCall) {
+ break
+ }
+ }
+ var person = "";
+ if (newPrimaryCall && callerDetails[newPrimaryCall.handlerId]) {
+ person = callerDetails[newPrimaryCall.handlerId].person
+ }
+
+ for (var ic = 0; ic < voiceCalls.count; ic++) {
+ var call = voiceCalls.instance(ic)
+ console.log("call: " + call.lineId + " state: " + call.statusText + " " + call.status + " " + call.handlerId + "\n")
+ if (call.status === VoiceCall.STATUS_ALERTING || call.status === VoiceCall.STATUS_DIALING) {
+ console.log("Tell outgoing: " + call.lineId);
+ //FIXME: Not working?
+ watchConnector.ring(call.lineId, person, 0);
+ } else if (call.status === VoiceCall.STATUS_INCOMING || call.status === VoiceCall.STATUS_WAITING) {
+ console.log("Tell incoming: " + call.lineId);
+ watchConnector.ring(call.lineId, person);
+ } else if (call.status === VoiceCall.STATUS_DISCONNECTED || call.status === VoiceCall.STATUS_NULL) {
+ console.log("Endphone");
+ watchConnector.endPhoneCall();
+ } else if (call.status === VoiceCall.ACTIVE) {
+ console.log("Startphone");
+ watchConnector.startPhoneCall();
+ }
+ }
+ }
+ }
+ Timer {
+ id: updateStateTimer
+ interval: 50
+ onTriggered: manager.updateState()
+ }
+
+ Instantiator {
+ id: callMonitor
+ model: manager.voiceCalls
+
+ delegate: QtObject {
+ property string callStatus: instance.status
+ property string remoteUid
+ property string person: ""
+ onCallStatusChanged: {
+ console.log("Status changed: " + callStatus);
+ if (callStatus === VoiceCall.STATUS_DISCONNECTED || callStatus === VoiceCall.STATUS_NULL) {
+ watchConnector.endPhoneCall();
+ manager.updateState();
+ } else {
+ updateStateTimer.start();
+ }
+ }
+ Component.onCompleted: {
+ remoteUid = instance.lineId
+ person = remoteUid !== "" ? people.personByPhoneNumber(remoteUid) : ""
+ manager.updateState()
+ }
+ }
+ onObjectAdded: {
+ callerDetails[object.handlerId] = object
+ }
+ onObjectRemoved: {
+ delete callerDetails[object.handlerId]
+ manager.updateState()
+ }
+ }
+
+
+ SilicaFlickable {
+ anchors.fill: parent
+
+ contentHeight: column.height
+
+ Column {
+ id: column
+
+ width: page.width
+ spacing: Theme.paddingLarge
+ PageHeader {
+ title: "WaterWatch"
+ }
+ Label {
+ visible: !watchConnector.isConnected
+ text: "Waiting for watch...\nIf it can't be found plase\ncheck it's available and\npaired in Bluetooth settings."
+ width: column.width
+ }
+ Repeater {
+ model: KnownDevicesModel { id: knownDevicesModel }
+ delegate: ListItem {
+ id: pairedItem
+ visible: (model.paired && watchConnector.isConnected)
+ Label {
+ text: model.alias.length ? model.alias : model.address
+ }
+ onVisibleChanged: {
+ if (pairedItem.visible) {
+ watchConnector.deviceConnect(model.alias, model.address);
+ }
+ }
+ }
+ }
+ Button {
+ text: "Ping"
+ onClicked: {
+ watchConnector.ping(66)
+ }
+ }
+ Button {
+ text: "Send SMS"
+ onClicked: {
+ watchConnector.sendSMSNotification("Dummy", "Hello world!")
+ }
+ }
+ Button {
+ text: "Ring"
+ onClicked: {
+ watchConnector.ring("+1234567890", "Test user")
+ }
+ }
+ Button {
+ text: "Start call"
+ onClicked: {
+ watchConnector.startPhoneCall()
+ }
+ }
+ Button {
+ text: "End call"
+ onClicked: {
+ watchConnector.endPhoneCall()
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/qml/waterwatch.qml b/qml/waterwatch.qml
new file mode 100644
index 0000000..b41c7f5
--- /dev/null
+++ b/qml/waterwatch.qml
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2013 Jouni Roivas
+ Copyright (C) 2013 Jolla Ltd.
+ Contact: Thomas Perl <thomas.perl@jollamobile.com>
+ All rights reserved.
+
+ You may use this file under the terms of BSD license as follows:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Jolla Ltd nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import "pages"
+
+ApplicationWindow
+{
+ initialPage: Component { WatchPage { } }
+ cover: Qt.resolvedUrl("cover/CoverPage.qml")
+}
+
+
diff --git a/rpm/waterwatch.yaml b/rpm/waterwatch.yaml
new file mode 100644
index 0000000..e2f0359
--- /dev/null
+++ b/rpm/waterwatch.yaml
@@ -0,0 +1,31 @@
+Name: waterwatch
+Summary: Support for Pebble watch in SailfishOS
+Version: 0.1
+Release: 1
+Group: Qt/Qt
+URL: http://example.org/
+License: BSD
+Sources:
+- '%{name}-%{version}.tar.bz2'
+Description: |
+ Include support for Pebble watch to receive event from SailfishOS device. Communicates via Bluetooth, supporting the Pebble protocol.
+Configure: none
+Builder: qtc5
+PkgConfigBR:
+- Qt5Bluetooth
+- Qt5Quick
+- Qt5Qml
+- Qt5Core
+- sailfishapp >= 0.0.10
+Requires:
+- sailfishsilica-qt5 >= 0.10.9
+Files:
+- '%{_bindir}'
+- '%{_datadir}/%{name}/qml'
+- '%{_datadir}/applications/%{name}.desktop'
+- '%{_datadir}/icons/hicolor/86x86/apps/%{name}.png'
+- /usr/bin
+- /usr/share/waterwatch
+- /usr/share/applications
+- /usr/share/icons/hicolor/86x86/apps
+PkgBR: []
diff --git a/src/watchconnector.cpp b/src/watchconnector.cpp
new file mode 100644
index 0000000..55e4b80
--- /dev/null
+++ b/src/watchconnector.cpp
@@ -0,0 +1,283 @@
+#include "watchconnector.h"
+#include <QDateTime>
+
+WatchConnector::WatchConnector(QObject *parent) :
+ QObject(parent)
+{
+ socket = nullptr;
+}
+
+WatchConnector::~WatchConnector()
+{
+}
+
+void WatchConnector::deviceDiscovered(const QBluetoothDeviceInfo &device)
+{
+ //FIXME: Configurable
+ if (device.name().startsWith("Pebble")) {
+ qDebug() << "Found Pebble:" << device.name() << '(' << device.address().toString() << ')';
+ handleWatch(device);
+ } else {
+ qDebug() << "Found other device:" << device.name() << '(' << device.address().toString() << ')';
+ }
+}
+
+void WatchConnector::deviceConnect(const QString name, const QString address)
+{
+ if (name.startsWith("Pebble")) {
+ QBluetoothDeviceInfo device(QBluetoothAddress(address), name, 0);
+ deviceDiscovered(device);
+ }
+}
+
+void WatchConnector::handleWatch(const QBluetoothDeviceInfo &device)
+{
+ qDebug() << "handleWatch" << device.name();
+ if (socket != nullptr) {
+ socket->close();
+ socket->deleteLater();
+ socket = nullptr;
+ }
+
+ socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket);
+ qDebug() << "Creating socket";
+
+ // FIXME: Assuming port 1 (with Pebble)
+ socket->connectToService(device.address(), 1);
+
+ connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
+ connect(socket, SIGNAL(connected()), this, SLOT(connected()));
+ connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
+}
+
+QString WatchConnector::decodeEndpoint(unsigned int val)
+{
+ //FIXME: Create a map of these values
+ switch(val) {
+ case watchTIME:
+ return "TIME";
+ case watchVERSION:
+ return "VERSION";
+ case watchPHONE_VERSION:
+ return "PHONE_VERSION";
+ case watchSYSTEM_MESSAGE:
+ return "SYSTEM_MESSAGE";
+ case watchMUSIC_CONTROL:
+ return "MUSIC_CONTROL";
+ case watchPHONE_CONTROL:
+ return "PHONE_CONTROL";
+ case watchAPPLICATION_MESSAGE:
+ return "APP_MSG";
+ case watchLAUNCHER:
+ return "LAUNCHER";
+ case watchLOGS:
+ return "LOGS";
+ case watchPING:
+ return "PING";
+ case watchLOG_DUMP:
+ return "DUMP";
+ case watchRESET:
+ return "RESET";
+ case watchAPP:
+ return "APP";
+ case watchAPP_LOGS:
+ return "APP_LOGS";
+ case watchNOTIFICATION:
+ return "NOTIFICATION";
+ case watchRESOURCE:
+ return "RESOURCE";
+ case watchAPP_MANAGER:
+ return "APP_MANAG";
+ case watchSCREENSHOT:
+ return "SCREENSHOT";
+ case watchPUTBYTES:
+ return "PUTBYTES";
+ default:
+ return "Unknown: "+ QString::number(val);
+ }
+}
+
+void WatchConnector::decodeMsg(QByteArray data)
+{
+ unsigned int datalen = 0;
+ int index = 0;
+ datalen = (data.at(index) << 8) + data.at(index+1);
+ index += 2;
+
+ unsigned int endpoint = 0;
+ endpoint = (data.at(index) << 8) + data.at(index+1);
+ index += 2;
+
+ qDebug() << "Length:" << datalen << " Endpoint:" << decodeEndpoint(endpoint);
+ qDebug() << "Data:" << data.mid(index).toHex();
+ if (endpoint == watchPHONE_CONTROL) {
+ if (data.length() >= 5) {
+ if (data.at(4) == callHANGUP) {
+ emit hangup();
+ }
+ }
+ }
+}
+
+void WatchConnector::readSocket()
+{
+ qDebug() << "read";
+
+ QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
+ if (!socket) return;
+
+ while (socket->bytesAvailable()) {
+ QByteArray line = socket->readAll();
+ emit messageReceived(socket->peerName(), QString::fromUtf8(line.constData(), line.length()));
+ decodeMsg(line);
+ }
+}
+
+void WatchConnector::connected()
+{
+ qDebug() << "Connected!";
+ is_connected = true;
+ emit nameChanged();
+ emit connectedChanged();
+}
+
+void WatchConnector::disconnected()
+{
+ qDebug() << "Disconnected!";
+ is_connected = false;
+
+ QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
+ if (!socket) return;
+
+ socket->deleteLater();
+ socket = nullptr;
+ emit connectedChanged();
+}
+
+void WatchConnector::sendData(const QByteArray &data)
+{
+ if (socket == nullptr) return;
+
+ socket->write(data);
+}
+
+void WatchConnector::sendMessage(unsigned int endpoint, QByteArray data)
+{
+ qDebug() << "Sending message";
+ QByteArray msg;
+
+ // First send the length
+ msg.append((data.length() & 0xFF00) >> 8);
+ msg.append(data.length() & 0xFF);
+
+ // Then the endpoint
+ msg.append((endpoint & 0xFF00) >> 8);
+ msg.append(endpoint & 0xFF);
+
+ // Finally the data
+ msg.append(data);
+
+ sendData(msg);
+}
+
+void WatchConnector::buildData(QByteArray &res, QStringList data)
+{
+ for (QString d : data)
+ {
+ QByteArray tmp = d.left(0xF0).toUtf8();
+ res.append(tmp.length() & 0xFF);
+ res.append(tmp);
+ }
+}
+
+QByteArray WatchConnector::buildMessageData(unsigned int lead, QStringList data)
+{
+ QByteArray res;
+ res.append(lead & 0xFF);
+ buildData(res, data);
+
+ return res;
+}
+
+void WatchConnector::ping(unsigned int val)
+{
+ QByteArray res;
+ res.append((char)0);
+
+ res.append((char)((val >> 24) & 0xff));
+ res.append((char)((val >> 16) & 0xff));
+ res.append((char)((val >> 8) & 0xff));
+ res.append((char)(val & 0xff));
+
+ sendMessage(watchPING, res);
+}
+
+QString WatchConnector::timeStamp()
+{
+ return QString::number(QDateTime::currentMSecsSinceEpoch());
+}
+
+void WatchConnector::sendNotification(unsigned int lead, QString sender, QString data, QString subject)
+{
+ QStringList tmp;
+ tmp.append(sender);
+ tmp.append(data);
+ tmp.append(timeStamp());
+ if (lead == 0) tmp.append(subject);
+
+ QByteArray res = buildMessageData(lead, tmp);
+
+ sendMessage(watchNOTIFICATION, res);
+}
+
+void WatchConnector::sendSMSNotification(QString sender, QString data)
+{
+ sendNotification(1, sender, data, "");
+}
+
+void WatchConnector::sendEmailNotification(QString sender, QString data, QString subject)
+{
+ sendNotification(0, sender, data, subject);
+}
+
+void WatchConnector::phoneControl(char act, unsigned int cookie, QStringList datas)
+{
+ QByteArray head;
+ head.append((char)act);
+ head.append((cookie >> 24)& 0xFF);
+ head.append((cookie >> 16)& 0xFF);
+ head.append((cookie >> 8)& 0xFF);
+ head.append(cookie & 0xFF);
+ if (datas.length()>0) buildData(head, datas);
+
+ sendMessage(watchPHONE_CONTROL, head);
+}
+
+void WatchConnector::ring(QString number, QString name, bool incoming, unsigned int cookie)
+{
+ QStringList tmp;
+ tmp.append(number);
+ tmp.append(name);
+
+ char act = callINCOMING;
+ if (!incoming) {
+ act = callOUTGOING;
+ }
+
+ phoneControl(act, cookie, tmp);
+}
+
+void WatchConnector::startPhoneCall(unsigned int cookie)
+{
+ phoneControl(callSTART, cookie, QStringList());
+}
+
+void WatchConnector::endPhoneCall(unsigned int cookie)
+{
+ phoneControl(callEND, cookie, QStringList());
+}
+
+void registerWatchConnector()
+{
+ qmlRegisterType<WatchConnector>("watch", 0, 1, "WatchConnector");
+}
diff --git a/src/watchconnector.h b/src/watchconnector.h
new file mode 100644
index 0000000..59ea632
--- /dev/null
+++ b/src/watchconnector.h
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 2013 Jouni Roivas
+ All rights reserved.
+
+ You may use this file under the terms of BSD license as follows:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Jolla Ltd nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WATCHCONNECTOR_H
+#define WATCHCONNECTOR_H
+
+#include <QObject>
+#include <QtQml>
+#include <QStringList>
+#include <QBluetoothDeviceInfo>
+#include <QBluetoothSocket>
+#include <QBluetoothServiceInfo>
+
+using namespace QtBluetooth;
+
+class WatchConnector : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
+ Q_PROPERTY(QString isConnected READ isConnected NOTIFY connectedChanged)
+public:
+ enum {
+ watchTIME = 11,
+ watchVERSION = 16,
+ watchPHONE_VERSION = 17,
+ watchSYSTEM_MESSAGE = 18,
+ watchMUSIC_CONTROL = 32,
+ watchPHONE_CONTROL = 33,
+ watchAPPLICATION_MESSAGE = 48,
+ watchLAUNCHER = 49,
+ watchLOGS = 2000,
+ watchPING = 2001,
+ watchLOG_DUMP = 2002,
+ watchRESET = 2003,
+ watchAPP = 2004,
+ watchAPP_LOGS = 2006,
+ watchNOTIFICATION = 3000,
+ watchRESOURCE = 4000,
+ watchAPP_MANAGER = 6000,
+ watchSCREENSHOT = 8000,
+ watchPUTBYTES = 48879
+ };
+ enum {
+ callANSWER = 1,
+ callHANGUP = 2,
+ callGET_STATE = 3,
+ callINCOMING = 4,
+ callOUTGOING = 5,
+ callMISSED = 6,
+ callRING = 7,
+ callSTART = 8,
+ callEND = 9
+ };
+ explicit WatchConnector(QObject *parent = 0);
+ virtual ~WatchConnector();
+ bool isConnected() const { return is_connected; }
+ QString name() const { if (socket != nullptr) return socket->peerName(); return "";}
+
+ QString timeStamp();
+ QString decodeEndpoint(unsigned int val);
+
+signals:
+ void messageReceived(QString peer, QString msg);
+ void nameChanged();
+ void connectedChanged();
+ void hangup();
+
+public slots:
+ void sendData(const QByteArray &data);
+ void sendMessage(unsigned int endpoint, QByteArray data);
+ void ping(unsigned int val);
+ void sendNotification(unsigned int lead, QString sender, QString data, QString subject);
+ void sendSMSNotification(QString sender, QString data);
+ void sendEmailNotification(QString sender, QString data, QString subject);
+
+ void buildData(QByteArray &res, QStringList data);
+ QByteArray buildMessageData(unsigned int lead, QStringList data);
+
+ void phoneControl(char act, unsigned int cookie, QStringList datas);
+ void ring(QString number, QString name, bool incoming=true, unsigned int cookie=0);
+ void startPhoneCall(unsigned int cookie=0);
+ void endPhoneCall(unsigned int cookie=0);
+
+ void deviceConnect(const QString name, const QString address);
+ void deviceDiscovered(const QBluetoothDeviceInfo&);
+ void handleWatch(const QBluetoothDeviceInfo&);
+ void readSocket();
+ void connected();
+ void disconnected();
+
+private:
+ void decodeMsg(QByteArray data);
+ QBluetoothSocket *socket;
+ bool is_connected;
+};
+
+void registerWatchConnector();
+
+#endif // WATCHCONNECTOR_H
diff --git a/src/waterwatch.cpp b/src/waterwatch.cpp
new file mode 100644
index 0000000..2f65cc0
--- /dev/null
+++ b/src/waterwatch.cpp
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2013 Jouni Roivas
+ Copyright (C) 2013 Jolla Ltd.
+ Contact: Thomas Perl <thomas.perl@jollamobile.com>
+ All rights reserved.
+
+ You may use this file under the terms of BSD license as follows:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Jolla Ltd nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <QtQuick>
+
+#include <sailfishapp.h>
+#include "watchconnector.h"
+
+int main(int argc, char *argv[])
+{
+ // Registert WatchController object on QML side
+ registerWatchConnector();
+
+ return SailfishApp::main(argc, argv);
+}
+
diff --git a/waterwatch.desktop b/waterwatch.desktop
new file mode 100644
index 0000000..4ddba76
--- /dev/null
+++ b/waterwatch.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Type=Application
+X-Nemo-Application-Type=silica-qt5
+Name=waterwatch
+Icon=waterwatch
+Exec=waterwatch
+
diff --git a/waterwatch.png b/waterwatch.png
new file mode 100644
index 0000000..4c883a0
--- /dev/null
+++ b/waterwatch.png
Binary files differ
diff --git a/waterwatch.pro b/waterwatch.pro
new file mode 100644
index 0000000..65a9018
--- /dev/null
+++ b/waterwatch.pro
@@ -0,0 +1,20 @@
+TARGET = waterwatch
+
+CONFIG += sailfishapp
+
+SOURCES += src/waterwatch.cpp \
+ src/watchconnector.cpp
+
+QT += bluetooth
+QMAKE_CXXFLAGS += -std=c++0x
+
+OTHER_FILES += qml/waterwatch.qml \
+ qml/cover/CoverPage.qml \
+ rpm/waterwatch.spec \
+ rpm/waterwatch.yaml \
+ waterwatch.desktop \
+ qml/pages/WatchPage.qml
+
+HEADERS += \
+ src/watchconnector.h
+