Merge PR #451: Add support for writing NFC tags and launching stuff with them

This commit is contained in:
Jenkins nymea 2020-10-15 20:01:19 +02:00
commit ed38dd2c82
21 changed files with 1064 additions and 38 deletions

View File

@ -2,7 +2,7 @@ TEMPLATE = lib
TARGET = service
CONFIG += dll
QT += core androidextras
QT += network qml quick quickcontrols2 svg websockets bluetooth charts
QT += network qml quick quickcontrols2 svg websockets bluetooth charts nfc
include(../config.pri)
include(../android_openssl/openssl.pri)
@ -29,6 +29,8 @@ SOURCES += \
nymeaappservice/androidbinder.cpp \
../nymea-app/stylecontroller.cpp \
../nymea-app/platformhelper.cpp \
../nymea-app/nfchelper.cpp \
../nymea-app/nfcthingactionwriter.cpp \
../nymea-app/platformintegration/android/platformhelperandroid.cpp \
service_main.cpp
@ -38,6 +40,8 @@ HEADERS += \
nymeaappservice/androidbinder.h \
../nymea-app/stylecontroller.h \
../nymea-app/platformhelper.h \
../nymea-app/nfchelper.h \
../nymea-app/nfcthingactionwriter.h \
../nymea-app/platformintegration/android/platformhelperandroid.h \
DISTFILES += \

View File

@ -6,6 +6,8 @@
#include "libnymea-app-core.h"
#include "../nymea-app/stylecontroller.h"
#include "../nymea-app/platformhelper.h"
#include "../nymea-app/nfchelper.h"
#include "../nymea-app/nfcthingactionwriter.h"
#include "../nymea-app/platformintegration/android/platformhelperandroid.h"
#include <QQmlApplicationEngine>
@ -13,6 +15,8 @@
#include <QtQml>
#include <QtAndroid>
#include <QAndroidJniObject>
#include <QAndroidIntent>
#include <QNdefNfcUriRecord>
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
@ -26,41 +30,190 @@ DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QAp
setApplicationName("nymea-app");
setOrganizationName("nymea");
QString nymeaId = QtAndroid::androidActivity().callObjectMethod<jstring>("nymeaId").toString();
QString thingId = QtAndroid::androidActivity().callObjectMethod<jstring>("thingId").toString();
QSettings settings;
NymeaDiscovery *discovery = new NymeaDiscovery(this);
m_discovery = new NymeaDiscovery(this);
AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
discovery->setAwsClient(AWSClient::instance());
NymeaHost *host = discovery->nymeaHosts()->find(nymeaId);
m_discovery->setAwsClient(AWSClient::instance());
m_engine = new Engine(this);
m_qmlEngine = new QQmlApplicationEngine(this);
registerQmlTypes();
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
qmlRegisterSingletonType(QUrl("qrc:///ui/utils/NymeaUtils.qml"), "Nymea", 1, 0, "NymeaUtils" );
qmlRegisterType<NfcThingActionWriter>("Nymea", 1, 0, "NfcThingActionWriter");
qmlRegisterSingletonType<NfcHelper>("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
StyleController *styleController = new StyleController(this);
m_qmlEngine->rootContext()->setContextProperty("styleController", styleController);
m_qmlEngine->rootContext()->setContextProperty("engine", m_engine);
m_qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", ""); // Unknown at this point
m_qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
jboolean startedByNfc = QtAndroid::androidActivity().callMethod<jboolean>("startedByNfc", "()Z");
if (startedByNfc) {
qDebug() << "**** Started by NFC";
qDebug() << "Registering NFC handler and waiting for message.";
QNearFieldManager *manager = new QNearFieldManager(this);
manager->registerNdefMessageHandler(this, SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*)));
} else {
qDebug() << "*** Started by other intent";
qDebug() << "Expecing nymeaId and thingId in intent extras.";
QString nymeaId = QtAndroid::androidActivity().callObjectMethod<jstring>("nymeaId").toString();
QString thingId = QtAndroid::androidActivity().callObjectMethod<jstring>("thingId").toString();
connectToNymea(nymeaId);
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
}
}
void DeviceControlApplication::handleNdefMessage(QNdefMessage message, QNearFieldTarget *target)
{
qDebug() << "************* NFC message!" << message.toByteArray();
if (message.count() < 1) {
qWarning() << "NFC message doesn't contain any records...";
return;
}
// NOTE: At this point we're only supporting one NDEF record per message
QNdefRecord record = message.first();
QNdefNfcUriRecord uriRecord(record);
QUrl url = uriRecord.uri();
if (url.scheme() != "nymea") {
qWarning() << "NDEF URI record scheme is not \"nymea://\"";
return;
}
QUuid nymeaId = QUuid(url.host());
if (nymeaId.isNull()) {
qWarning() << "Invalid nymea UUID in NDEF record.";
return;
}
QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
if (thingId.isNull()) {
qWarning() << "Invalid thing in NDEF record";
return;
}
m_pendingNfcAction = url;
connectToNymea(nymeaId);
m_qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
connect(m_engine->thingManager(), &DeviceManager::fetchingDataChanged, [this](){
if (m_engine->jsonRpcClient()->connected() && !m_engine->thingManager()->fetchingData()) {
qDebug() << "Ready to process commands";
runNfcAction();
}
});
}
void DeviceControlApplication::connectToNymea(const QUuid &nymeaId)
{
NymeaHost *host = m_discovery->nymeaHosts()->find(nymeaId);
if (!host) {
qWarning() << "No such nymea host:" << nymeaId;
// TODO: We could wait here until the discovery finds it... But it really should be cached already...
exit(1);
}
Engine *m_engine = new Engine(this);
qDebug() << "Connecting to:" << host;
qDebug() << "Connecting to:" << host->name();
m_engine->jsonRpcClient()->connectToHost(host);
qDebug() << "Creating QML view";
QQmlApplicationEngine *qmlEngine = new QQmlApplicationEngine(this);
registerQmlTypes();
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
qmlRegisterSingletonType(QUrl("qrc:///ui/utils/NymeaUtils.qml"), "Nymea", 1, 0, "NymeaUtils" );
StyleController styleController;
qmlEngine->rootContext()->setContextProperty("styleController", &styleController);
qmlEngine->rootContext()->setContextProperty("engine", m_engine);
qmlEngine->rootContext()->setContextProperty("_engine", m_engine);
qmlEngine->rootContext()->setContextProperty("controlledThingId", thingId);
qmlEngine->load(QUrl(QLatin1String("qrc:/Main.qml")));
}
void DeviceControlApplication::runNfcAction()
{
if (!m_pendingNfcAction.isEmpty()) {
qDebug() << "NFC action:" << m_pendingNfcAction;
}
QUrl url = m_pendingNfcAction;
m_pendingNfcAction.clear();
if (url.scheme() != "nymea") {
qWarning() << "NDEF URI record scheme is not \"nymea://\" in" << url.toString();
return;
}
QUuid nymeaId = QUuid(url.host());
if (nymeaId.isNull()) {
qWarning() << "Invalid nymea UUID" << url.host() << "in NDEF record" << url.toString();
return;
}
QUuid thingId = QUuid(QUrlQuery(url).queryItemValue("t"));
Device *thing = m_engine->thingManager()->things()->getThing(thingId);
if (!thing) {
qDebug() << "Thing" << thingId.toString() << "from" << url.toString() << "doesn't exist on nymea host" << nymeaId.toString();
return;
}
QList<QPair<QString, QString>> queryItems = QUrlQuery(url.query()).queryItems();
for (int i = 0; i < queryItems.count(); i++) {
QString entryName = queryItems.at(i).first;
if (entryName == "t") {
continue;
}
if (!entryName.startsWith("a")) {
qDebug() << "Only actions are supported. Skipping query item" << entryName;
continue;
}
QString actionString = queryItems.at(i).second;
QStringList parts = actionString.split("#");
if (parts.count() == 0) {
qDebug() << "Invalid action definition:" << actionString;
continue;
}
if (parts.count() > 2) {
// The parameters might contain a #, let's merge them again
parts[1] = parts.mid(1).join('#');
}
QString actionTypeName = parts.at(0);
ActionType *actionType = thing->thingClass()->actionTypes()->findByName(actionTypeName);
if (!actionType) {
qWarning() << "Invalid action name" << actionType << "in url:" << url.toString();
continue;
}
QHash<QString, QVariant> paramsInUri;
if (parts.count() > 1) {
QString paramsString = parts.at(1);
foreach (const QString &paramString, paramsString.split("+")) {
QStringList parts = paramString.split(":");
if (parts.count() != 2) {
qWarning() << "Invalid param format" << paramString << "in url:" << url.toString();
continue;
}
paramsInUri.insert(parts.at(0), parts.at(1));
}
}
qDebug() << "Parameters in NFC uri:" << paramsInUri;
QVariantList params;
for (int j = 0; j < actionType->paramTypes()->rowCount(); j++) {
ParamType *paramType = actionType->paramTypes()->get(j);
QVariantMap param;
param.insert("paramTypeId", paramType->id());
if (paramsInUri.contains(paramType->name())) {
param.insert("value", paramsInUri.value(paramType->name()));
} else {
param.insert("value", paramType->defaultValue());
}
params.append(param);
}
qDebug() << "Action parameters:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
m_engine->thingManager()->executeAction(thingId, actionType->id(), params);
}
}

View File

@ -2,6 +2,14 @@
#define DEVICECONTROLAPPLICATION_H
#include <QApplication>
#include <QNearFieldManager>
#include <QNdefMessage>
#include <QQmlApplicationEngine>
#include <QNdefMessage>
#include "types/ruleactions.h"
#include "connection/discovery/nymeadiscovery.h"
#include "engine.h"
class DeviceControlApplication : public QApplication
{
@ -9,6 +17,21 @@ class DeviceControlApplication : public QApplication
public:
explicit DeviceControlApplication(int argc, char *argv[]);
private slots:
void handleNdefMessage(QNdefMessage message,QNearFieldTarget* target);
void connectToNymea(const QUuid &nymeaId);
void runNfcAction();
private:
NymeaDiscovery *m_discovery = nullptr;
Engine *m_engine = nullptr;
QQmlApplicationEngine *m_qmlEngine = nullptr;
QUrl m_pendingNfcAction;
};
#endif // DEVICECONTROLAPPLICATION_H

View File

@ -2,6 +2,8 @@
#define NYMEAAPPSERVICE_H
#include <QAndroidService>
#include <QNearFieldManager>
#include <QNdefMessage>
#include "engine.h"

View File

@ -49,11 +49,12 @@ ActionType *ActionTypes::get(int index) const
ActionType *ActionTypes::getActionType(const QUuid &actionTypeId) const
{
foreach (ActionType *actionType, m_actionTypes) {
qDebug() << "checking:" << actionType->id();
if (actionType->id() == actionTypeId) {
return actionType;
}
}
return 0;
return nullptr;
}
int ActionTypes::rowCount(const QModelIndex &parent) const

View File

@ -236,5 +236,7 @@
<file>ui/images/connections/nm-signal-100-secure.svg</file>
<file>ui/images/connections/bluetooth.svg</file>
<file>ui/images/connections/network-wired-disabled.svg</file>
<file>ui/images/nfc.svg</file>
<file>ui/images/smartphone.svg</file>
</qresource>
</RCC>

View File

@ -52,6 +52,8 @@
#include "pushnotifications.h"
#include "applogcontroller.h"
#include "ruletemplates/messages.h"
#include "nfchelper.h"
#include "nfcthingactionwriter.h"
QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
@ -66,7 +68,6 @@ QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
#endif
}
int main(int argc, char *argv[])
{
@ -124,6 +125,8 @@ int main(int argc, char *argv[])
QQmlApplicationEngine *engine = new QQmlApplicationEngine();
qmlRegisterSingletonType<PlatformHelper>("Nymea", 1, 0, "PlatformHelper", platformHelperProvider);
qmlRegisterSingletonType<NfcHelper>("Nymea", 1, 0, "NfcHelper", NfcHelper::nfcHelperProvider);
qmlRegisterType<NfcThingActionWriter>("Nymea", 1, 0, "NfcThingActionWriter");
PushNotifications::instance()->connectClient();
qmlRegisterSingletonType<PushNotifications>("Nymea", 1, 0, "PushNotifications", PushNotifications::pushNotificationsProvider);

28
nymea-app/nfchelper.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "nfchelper.h"
#include <QNearFieldManager>
NfcHelper::NfcHelper(QObject *parent) : QObject(parent)
{
}
NfcHelper *NfcHelper::instance()
{
static NfcHelper *thiz = nullptr;
if (!thiz) {
thiz = new NfcHelper();
}
return thiz;
}
QObject *NfcHelper::nfcHelperProvider(QQmlEngine */*engine*/, QJSEngine */*scriptEngine*/)
{
return instance();
}
bool NfcHelper::isAvailable() const
{
QNearFieldManager manager;
return manager.isAvailable();
}

23
nymea-app/nfchelper.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef NFCHELPER_H
#define NFCHELPER_H
#include <QObject>
#include <QQmlEngine>
class NfcHelper : public QObject
{
Q_OBJECT
Q_PROPERTY(bool isAvailable READ isAvailable CONSTANT)
public:
static NfcHelper* instance();
static QObject *nfcHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
bool isAvailable() const;
private:
explicit NfcHelper(QObject *parent = nullptr);
};
#endif // NFCHELPER_H

View File

@ -0,0 +1,185 @@
#include "nfcthingactionwriter.h"
#include "types/deviceclass.h"
#include "types/statetype.h"
#include "types/ruleaction.h"
#include "types/ruleactionparams.h"
#include "types/ruleactionparam.h"
#include <QNearFieldManager>
#include <QNdefMessage>
#include <QDebug>
#include <QNdefNfcUriRecord>
#include <QUrl>
#include <QUrlQuery>
NfcThingActionWriter::NfcThingActionWriter(QObject *parent):
QObject(parent),
m_manager(new QNearFieldManager(this)),
m_actions(new RuleActions(this))
{
connect(m_manager, &QNearFieldManager::targetDetected, this, &NfcThingActionWriter::targetDetected);
connect(m_manager, &QNearFieldManager::targetLost, this, &NfcThingActionWriter::targetLost);
connect(m_actions, &RuleActions::countChanged, this, &NfcThingActionWriter::updateContent);
m_manager->startTargetDetection();
}
NfcThingActionWriter::~NfcThingActionWriter()
{
m_manager->stopTargetDetection();
}
bool NfcThingActionWriter::isAvailable() const
{
return m_manager->isAvailable();
}
Engine *NfcThingActionWriter::engine() const
{
return m_engine;
}
void NfcThingActionWriter::setEngine(Engine *engine)
{
if (m_engine != engine) {
m_engine = engine;
emit engineChanged();
updateContent();
}
}
Device *NfcThingActionWriter::thing() const
{
return m_thing;
}
void NfcThingActionWriter::setThing(Device *thing)
{
if (m_thing != thing) {
m_thing = thing;
emit thingChanged();
updateContent();
}
}
RuleActions *NfcThingActionWriter::actions() const
{
return m_actions;
}
int NfcThingActionWriter::messageSize() const
{
return m_currentMessage.toByteArray().size();
int ret = 0;
for (int i = 0; i < m_currentMessage.size(); i++) {
ret += m_currentMessage.at(i).payload().size();
}
return ret;
}
NfcThingActionWriter::TagStatus NfcThingActionWriter::status() const
{
return m_status;
}
void NfcThingActionWriter::updateContent()
{
qDebug() << "Updating" << m_engine << m_thing;
// Creating an URI type record with this format:
// nymea://<nymeaId>
// ? t=<thingId>
// & a[0]=<actionTypeName>
// & a[1]=<actionTypeName>#<paramName1>:<paramValue>
// & a[2]=<actionTypeName>#<paramName1>:<paramValue>+<paramName2>:<paramValue>
// & ...
// NOTE: We're using actionType and paramType *name* instead of the ID because NFC tags are
// small and normally names are shorter than ids so we save some space.
// NOTE: param values are percentage encoded to prevent messing with the parsing if they
// contain + or :
QUrl url;
url.setScheme("nymea");
if (!m_engine || !m_thing) {
return;
}
url.setHost(m_engine->jsonRpcClient()->currentHost()->uuid().toString().remove(QRegExp("[{}]")));
QUrlQuery query;
query.addQueryItem("t", m_thing->id().toString().remove(QRegExp("[{}]")));
for (int i = 0; i < m_actions->rowCount(); i++) {
RuleAction *action = m_actions->get(i);
QStringList params;
ActionType *at = m_thing->thingClass()->actionTypes()->getActionType(action->actionTypeId());
if (!at) {
qWarning() << "ActionType not found in thing" << action->actionTypeId();
continue;
}
for (int j = 0; j < action->ruleActionParams()->rowCount(); j++) {
RuleActionParam *param = action->ruleActionParams()->get(j);
ParamType *pt = at->paramTypes()->getParamType(param->paramTypeId());
if (!pt) {
qWarning() << "ParamType not found in thing";
continue;
}
params.append(pt->name() + ":" + param->value().toByteArray().toPercentEncoding());
}
QString actionString = at->name();
if (params.length() > 0) {
actionString += "#" + params.join("+");
}
query.addQueryItem(QString("a[%1]").arg(i), actionString);
}
url.setQuery(query);
qDebug() << "writing message" << url;
QNdefNfcUriRecord record;
record.setUri(url);
QNdefMessage message;
message.append(record);
m_currentMessage = message;
emit messageSizeChanged();
}
void NfcThingActionWriter::targetDetected(QNearFieldTarget *target)
{
QDateTime startTime = QDateTime::currentDateTime();
qDebug() << "target detected";
connect(target, &QNearFieldTarget::error, this, [=](QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id){
qDebug() << "Tag error:" << error;
m_status = TagStatusFailed;
emit statusChanged();
});
connect(target, &QNearFieldTarget::ndefMessagesWritten, this, [=](){
qDebug() << "Tag written in" << startTime.msecsTo(QDateTime::currentDateTime());
m_status = TagStatusWritten;
emit statusChanged();
});
QNearFieldTarget::RequestId m_request = target->writeNdefMessages(QList<QNdefMessage>() << m_currentMessage);
if (!m_request.isValid()) {
qDebug() << "Error writing tag";
m_status = TagStatusFailed;
emit statusChanged();
}
m_status = TagStatusWriting;
emit statusChanged();
}
void NfcThingActionWriter::targetLost(QNearFieldTarget *target)
{
qDebug() << "Target lost" << target;
m_status = TagStatusWaiting;
emit statusChanged();
}

View File

@ -0,0 +1,76 @@
#ifndef NFCTHINGACTIONWRITER_H
#define NFCTHINGACTIONWRITER_H
#include <QObject>
#include <QNearFieldManager>
#include <QNdefMessage>
#include "types/device.h"
#include "engine.h"
#include "types/ruleactions.h"
class NfcThingActionWriter : public QObject
{
Q_OBJECT
Q_PROPERTY(bool isAvailable READ isAvailable CONSTANT)
Q_PROPERTY(Engine *engine READ engine WRITE setEngine NOTIFY engineChanged)
Q_PROPERTY(Device *thing READ thing WRITE setThing NOTIFY thingChanged)
Q_PROPERTY(RuleActions *actions READ actions CONSTANT)
Q_PROPERTY(int messageSize READ messageSize NOTIFY messageSizeChanged)
Q_PROPERTY(TagStatus status READ status NOTIFY statusChanged)
public:
enum TagStatus {
TagStatusWaiting,
TagStatusWriting,
TagStatusWritten,
TagStatusFailed
};
Q_ENUM(TagStatus)
static NfcThingActionWriter *instance();
explicit NfcThingActionWriter(QObject *parent = nullptr);
~NfcThingActionWriter();
bool isAvailable() const;
Engine *engine() const;
void setEngine(Engine *engine);
Device *thing() const;
void setThing(Device *thing);
RuleActions *actions() const;
int messageSize() const;
TagStatus status() const;
signals:
void engineChanged();
void thingChanged();
void messageSizeChanged();
void statusChanged();
private slots:
void updateContent();
void targetDetected(QNearFieldTarget *target);
void targetLost(QNearFieldTarget *target);
private:
QNearFieldManager *m_manager = nullptr;
Engine *m_engine = nullptr;
Device *m_thing = nullptr;
RuleActions* m_actions;
TagStatus m_status = TagStatusWaiting;
QNdefMessage m_currentMessage;
};
#endif // NFCTHINGACTIONWRITER_H

View File

@ -2,7 +2,7 @@ TEMPLATE=app
TARGET=nymea-app
include(../config.pri)
QT += network qml quick quickcontrols2 svg websockets bluetooth charts gui-private
QT += network qml quick quickcontrols2 svg websockets bluetooth charts gui-private nfc
INCLUDEPATH += $$top_srcdir/libnymea-app
LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app
@ -14,6 +14,8 @@ PRE_TARGETDEPS += ../libnymea-app
HEADERS += \
mainmenumodel.h \
nfchelper.h \
nfcthingactionwriter.h \
platformintegration/generic/raspberrypihelper.h \
stylecontroller.h \
pushnotifications.h \
@ -24,6 +26,8 @@ HEADERS += \
SOURCES += main.cpp \
mainmenumodel.cpp \
nfchelper.cpp \
nfcthingactionwriter.cpp \
platformintegration/generic/raspberrypihelper.cpp \
stylecontroller.cpp \
pushnotifications.cpp \
@ -162,3 +166,12 @@ BR=$$BRANDING
target.path = /usr/bin
INSTALLS += target
contains(ANDROID_TARGET_ARCH,) {
ANDROID_ABIS = \
armeabi-v7a \
arm64-v8a
}
ANDROID_ABIS = armeabi-v7a arm64-v8a

View File

@ -223,5 +223,6 @@
<file>ui/components/BatteryStatusIcon.qml</file>
<file>ui/components/SetupStatusIcon.qml</file>
<file>ui/components/UpdateStatusIcon.qml</file>
<file>ui/magic/WriteNfcTagPage.qml</file>
</qresource>
</RCC>

View File

@ -96,7 +96,7 @@ Page {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu, {text: qsTr("Logs"), iconSource: "../images/logs.svg", functionName: "openDeviceLogPage"}))
}
if (engine.jsonRpcClient.ensureServerVersion(1.6)) {
if (engine.jsonRpcClient.ensureServerVersion("1.6")) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
{
text: Qt.binding(function() { return favoritesProxy.count === 0 ? qsTr("Mark as favorite") : qsTr("Remove from favorites")}),
@ -111,7 +111,20 @@ Page {
functionName: "addToGroup"
}))
}
print("*** creating menu")
print("NFC", NfcHelper.isAvailable)
if (NfcHelper.isAvailable) {
thingMenu.addItem(menuEntryComponent.createObject(thingMenu,
{
text: qsTr("Write NFC tag"),
iconSource: "../images/nfc.svg",
functionName: "writeNfcTag"
}));
}
}
function openDeviceMagicPage() {
pageStack.push(Qt.resolvedUrl("../magic/DeviceRulesPage.qml"), {device: root.device})
}
@ -138,6 +151,10 @@ Page {
pageStack.push(Qt.resolvedUrl("DeviceLogPage.qml"), {device: root.device });
}
function writeNfcTag() {
pageStack.push(Qt.resolvedUrl("../magic/WriteNfcTagPage.qml"), {thing: root.thing})
}
Component {
id: menuEntryComponent
IconMenuItem {

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg4874"
height="96"
viewBox="0 0 96 96.000001"
width="96"
version="1.1"
sodipodi:docname="nfc.svg"
inkscape:version="1.0.1 (1.0.1+r73)">
<path
id="path884"
style="color:#000000;fill:none"
d="M 30.00026,1.073013 V -94.92699 h 96 V 1.073013 Z" />
<path
id="path886"
style="color:#000000;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#808080;fill-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto"
d="m 42.041184,59.03214 19.92185,19.147163 c 2.283959,1.18636 3.037486,-5.033283 -0.0035,-9.561123 L 42.236652,49.66296 M 68.001221,84.147015 V 20.14502 c 0,-2.63041 -0.23782,-4.7121 -0.89648,-6.4668 -0.65866,-1.75461 -1.85,-3.15961 -3.3555,-3.9902 -3.011,-1.6613 -6.6918,-1.4848 -11.725,-1.543 h -0.01172 l -0.03472,4.0001 h 0.02344 c 5.0383,0.0588 6.3519,0.23688 7.8164,1.0449 0.73364,0.40478 1.1508,0.85491 1.541,1.8945 0.39025,1.0396 0.563732,2.692312 0.64258,5.0606 v 58.072038 z"
sodipodi:nodetypes="cccccsccccccscscc" />
<defs
id="defs9" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1380"
inkscape:window-height="873"
id="namedview7"
showgrid="true"
inkscape:zoom="2.4135194"
inkscape:cx="42.404861"
inkscape:cy="39.439781"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg4874">
<inkscape:grid
type="xygrid"
id="grid834" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
transform="translate(67.856999,-78.504993)">
<rect
id="rect4782"
style="color:#000000;fill:none"
transform="rotate(90)"
height="96"
width="96"
y="-28.143"
x="78.504997" />
<path
id="path4643"
style="color:#000000;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#808080;color-rendering:auto;image-rendering:auto;shape-rendering:auto"
d="m -43.869,86.504 -0.01172,0.002 c -5.0328,0.05818 -8.7136,-0.12027 -11.725,1.541 -1.5055,0.83064 -2.6968,2.2356 -3.3555,3.9902 -0.65866,1.7547 -0.89648,3.8364 -0.89648,6.4668 v 56.002 c 0,2.6304 0.23782,4.7121 0.89648,6.4668 0.65866,1.7546 1.85,3.1596 3.3555,3.9902 3.011,1.6613 6.6918,1.4848 11.725,1.543 H -43.869 4.154 4.165719 c 5.0328,-0.0582 8.7136,0.11832 11.725,-1.543 1.5055,-0.83064 2.6968,-2.2356 3.3555,-3.9902 0.65866,-1.7547 0.89648,-3.8364 0.89648,-6.4668 V 98.504 c 0,-2.6304 -0.23782,-4.7121 -0.89648,-6.4668 -0.66,-1.759 -1.851,-3.163 -3.356,-3.994 -3.011,-1.661 -6.6922,-1.483 -11.725,-1.541 L 4.1535,86.5002 h -48.023 z m 0.01172,4 h 48 c 5.0383,0.05877 8.3519,0.23688 9.8164,1.0449 0.73364,0.40478 1.1527,0.85491 1.543,1.8945 0.39025,1.0396 0.64062,2.691 0.64062,5.0605 v 56.002 c 0,2.3696 -0.25037,4.0209 -0.64062,5.0606 -0.39025,1.0396 -0.80933,1.4898 -1.543,1.8945 -1.4645,0.80804 -4.7782,0.98616 -9.8164,1.0449 h -47.977 -0.02344 c -5.0383,-0.0588 -8.3519,-0.23688 -9.8164,-1.0449 -0.73364,-0.40478 -1.1508,-0.85491 -1.541,-1.8945 -0.39025,-1.0396 -0.64258,-2.691 -0.64258,-5.0606 v -56.002 c 0,-2.3696 0.25232,-4.0209 0.64258,-5.0605 0.39025,-1.0396 0.80738,-1.4898 1.541,-1.8945 1.4645,-0.80804 4.7782,-0.98616 9.8164,-1.0449 z" />
</g>
<g
id="g868"
transform="translate(87.856999,-78.504993)">
<path
id="rect864"
style="color:#000000;fill:none"
transform="rotate(90)"
d="M 78.504997,-28.143 H 174.505 v 96 H 78.504997 Z" />
</g>
<path
id="path892"
style="color:#000000;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#808080;fill-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto"
d="M 54.001221,37.259895 34.079371,18.112732 c -2.283959,-1.18636 -3.037486,5.033283 0.0035,9.561123 l 19.899987,18.95522 M 28.041184,12.14502 v 64.001995 c 0,2.63041 0.23782,4.7121 0.89648,6.4668 0.65866,1.75461 1.85,3.15961 3.3555,3.9902 3.011,1.6613 6.6918,1.4848 11.725,1.543 h 0.01172 l 0.03472,-4.0001 h -0.02344 c -5.0383,-0.0588 -6.3519,-0.23688 -7.8164,-1.0449 -0.73364,-0.40478 -1.1508,-0.85491 -1.541,-1.8945 -0.39025,-1.0396 -0.563732,-2.692312 -0.64258,-5.0606 V 18.074877 Z"
sodipodi:nodetypes="cccccsccccccscscc" />
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="0.91+devel r"
viewBox="0 0 96 96.000001"
sodipodi:docname="phone-smartphone-symbolic.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.7812488"
inkscape:cx="15.954447"
inkscape:cy="64.905333"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076" />
<sodipodi:guide
orientation="1,0"
position="84,-8.0000001"
id="guide4080" />
<sodipodi:guide
position="48,-8.0000001"
orientation="1,0"
id="guide4170" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172" />
<sodipodi:guide
position="92,-8.0000001"
orientation="1,0"
id="guide4760" />
<sodipodi:guide
position="108,12"
orientation="0,1"
id="guide4182" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 35.976562,2.0000001 C 30.943803,2.0581871 27.26124,1.881546 24.25,3.5429689 22.74438,4.3736802 21.553141,5.7767541 20.894531,7.5312501 20.235931,9.2857461 19.998047,11.369641 19.998047,14 v 68 c 0,2.630359 0.237884,4.714254 0.896484,6.46875 0.65861,1.754496 1.849849,3.15757 3.355469,3.988281 3.01124,1.661433 6.693803,1.484792 11.726562,1.542969 h 0.01172 24.021485 0.01172 c 5.03276,-0.05818 8.715323,0.118464 11.726563,-1.542969 1.50562,-0.830711 2.696869,-2.233785 3.355469,-3.988281 C 75.762116,86.714254 76,84.630359 76,82 V 14 C 76,11.369641 75.762116,9.2857461 75.103516,7.5312501 74.444916,5.7767541 73.253667,4.3736802 71.748047,3.5429689 68.736807,1.881546 65.054244,2.0581771 60.021484,2.0000001 H 60.009766 35.988281 Z M 24.080078,12 h 47.839844 c 0.04599,0.606222 0.07813,1.255513 0.07813,2 V 82 H 24 V 14 c 0,-0.744487 0.03408,-1.393778 0.08008,-2 z M 40,86 h 16 v 3.998047 H 40 Z"
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
id="path4297"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsscccccccsssssccccccsccscccccc" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,222 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
property Thing thing: null
readonly property ThingClass thingClass: thing.thingClass
header: NymeaHeader {
text: qsTr("Write NFC tag")
onBackPressed: {
pageStack.pop()
}
}
NfcThingActionWriter {
id: nfcWriter
engine: _engine
thing: root.thing
}
// nfcHelper.writeThingStates(engine, root.thing)
GridLayout {
anchors.fill: parent
columns: app.landscape ? 2 : 1
ColumnLayout {
Layout.preferredWidth: parent.width / parent.columns
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins
Label {
Layout.fillWidth: true
text: {
switch (nfcWriter.status) {
case NfcThingActionWriter.TagStatusWaiting:
return qsTr("Tap an NFC tag to link it to %1.").arg(root.thing.name)
case NfcThingActionWriter.TagStatusWriting:
return qsTr("Writing NFC tag...")
case NfcThingActionWriter.TagStatusWritten:
return qsTr("NFC tag linked to %1.").arg(root.thing.name)
case NfcThingActionWriter.TagStatusFailed:
return qsTr("Failed linking the NFC tag to %1.").arg(root.thing.name)
}
}
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
Label {
Layout.fillWidth: true
text: qsTr("Required tag size: %1 bytes").arg(nfcWriter.messageSize)
font.pixelSize: app.smallFont
horizontalAlignment: Text.AlignHCenter
enabled: false
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: app.iconSize * 8
SequentialAnimation {
loops: Animation.Infinite
running: true
PropertyAction { target: phoneIcon; property: "anchors.horizontalCenterOffset"; value: app.iconSize * 2 }
PropertyAction { target: phoneIcon; property: "scale"; value: 1.3 }
NumberAnimation { target: phoneIcon; property: "opacity"; duration: 500; to: 1 }
PauseAnimation { duration: 500 }
ParallelAnimation {
NumberAnimation { target: phoneIcon; property: "anchors.horizontalCenterOffset"; from: app.iconSize * 2; to: -app.iconSize * 2; duration: 1500; easing.type: Easing.OutQuad }
NumberAnimation { target: phoneIcon; property: "scale"; duration: 1500; from: 1.3; to: 1; easing.type: Easing.InOutQuad }
}
PauseAnimation { duration: 500 }
NumberAnimation { target: phoneIcon; property: "opacity"; duration: 500; to: 0 }
PauseAnimation { duration: 500 }
}
ColorIcon {
id: nfcIcon
name: "../images/nfc.svg"
height: app.iconSize * 2
width: app.iconSize * 2
anchors.centerIn: parent
anchors.horizontalCenterOffset: - app.iconSize * 2
visible: nfcWriter.status == NfcThingActionWriter.TagStatusWaiting
}
Item {
id: phoneIcon
height: app.iconSize * 5
width: app.iconSize * 5
scale: 1.5
anchors.centerIn: parent
anchors.horizontalCenterOffset: app.iconSize * 2
visible: nfcWriter.status == NfcThingActionWriter.TagStatusWaiting
Rectangle {
anchors.fill: parent
anchors.leftMargin: phoneIcon.width * .21
anchors.rightMargin: phoneIcon.width * .21
anchors.topMargin: phoneIcon.height * .1
anchors.bottomMargin: phoneIcon.height * .1
color: app.backgroundColor
}
ColorIcon {
name: "../images/smartphone.svg"
anchors.fill: parent
}
}
Rectangle {
id: tick
anchors.centerIn: parent
height: app.iconSize * 6
width: app.iconSize * 6
radius: width / 2
color: app.backgroundColor
border.width: 4
border.color: app.foregroundColor
opacity: nfcWriter.status == NfcThingActionWriter.TagStatusWaiting ? 0 : 1
Behavior on opacity { NumberAnimation { duration: 300 } }
property bool shown: nfcWriter.status == NfcThingActionWriter.TagStatusWritten || nfcWriter.status == NfcThingActionWriter.TagStatusFailed
BusyIndicator {
anchors.fill: parent
running: visible
visible: nfcWriter.status == NfcThingActionWriter.TagStatusWriting
}
Item {
anchors.fill: parent
anchors.rightMargin: tick.shown ? 0 : parent.width
Behavior on anchors.rightMargin { NumberAnimation { duration: 500 } }
clip: true
ColorIcon {
x: (tick.width - width) / 2
y: (tick.height - height) / 2
height: app.iconSize * 4
width: app.iconSize * 4
name: nfcWriter.status == NfcThingActionWriter.TagStatusFailed ? "../images/close.svg" : "../images/tick.svg"
color: nfcWriter.status == NfcThingActionWriter.TagStatusFailed ? "red" : "green"
}
}
}
}
}
ColumnLayout {
Layout.preferredWidth: parent.width / parent.columns
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: nfcWriter.actions
clip: true
delegate: RuleActionDelegate {
ruleAction: nfcWriter.actions.get(index)
width: parent.width
onRemoveRuleAction: nfcWriter.actions.removeRuleAction(index)
}
}
Button {
text: qsTr("Add action")
Layout.fillWidth: true
Layout.margins: app.margins
onClicked: {
var action = nfcWriter.actions.createNewRuleAction()
action.thingId = root.thing.id
var page = pageStack.push("SelectRuleActionPage.qml", {ruleAction: action});
page.done.connect(function() {
nfcWriter.actions.addRuleAction(action);
pageStack.pop();
})
page.backPressed.connect(function() {
action.destroy()
pageStack.pop();
})
}
}
}
}
}

View File

@ -64,6 +64,11 @@
<activity android:process=":qt_controlsActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="io.guh.nymeaapp.NymeaAppControlsActivity" android:label="nymea:app" android:screenOrientation="unspecified" android:launchMode="standard">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="nymea"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="service"/>
<meta-data android:name="android.app.arguments" android:value="--controlActivity"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
@ -95,6 +100,11 @@
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
<service android:process=":qt_service" android:name="io.guh.nymeaapp.NymeaAppService">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="xbmc"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="service"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
@ -145,4 +155,5 @@
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.NFC" />
</manifest>

View File

@ -61,9 +61,8 @@ public class NymeaAppControlService extends ControlsProviderService {
}
}
@Override public void onUpdate(UUID nymeaId, UUID thingId) {
Log.d(TAG, "onUpdate()");
if (m_updatePublisher != null && m_activeControlIds.contains(thingId.toString())) {
Log.d(TAG, "Updating publisher for thing: " + thingId);
// Log.d(TAG, "Updating publisher for thing: " + thingId);
m_updatePublisher.onNext(thingToControl(nymeaId, thingId));
// m_updatePublisher.onComplete();
}

View File

@ -8,6 +8,9 @@ import android.telephony.TelephonyManager;
import android.provider.Settings.Secure;
import android.os.Vibrator;
import android.os.Process;
import android.nfc.NfcAdapter;
import android.nfc.NdefMessage;
import android.os.Parcelable;
// An activity spawned by android device controls on demand.
@ -26,11 +29,13 @@ public class NymeaAppControlsActivity extends org.qtproject.qt5.android.bindings
Log.d(TAG, "Resuming...");
}
@Override public void onDestroy() {
Log.d(TAG, "Destroying...");
}
public boolean startedByNfc() {
return NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction());
}
public String nymeaId()
{
@ -47,5 +52,4 @@ public class NymeaAppControlsActivity extends org.qtproject.qt5.android.bindings
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(duration);
}
}

View File

@ -154,7 +154,6 @@ public class NymeaAppServiceConnection implements ServiceConnection {
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "In OnReceive broadcast receiver");
if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
String payload = intent.getStringExtra("data");
try {
@ -170,7 +169,7 @@ public class NymeaAppServiceConnection implements ServiceConnection {
{
JSONObject data = new JSONObject(payload);
JSONObject params = data.getJSONObject("params");
Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
// Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
Log.d(TAG, params.toString());
if (data.getString("notification").equals("ThingStateChanged")) {
@ -178,7 +177,7 @@ public class NymeaAppServiceConnection implements ServiceConnection {
UUID thingId = UUID.fromString(params.getString("thingId"));
UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
String value = params.getString("value");
Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
// Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
Thing thing = getThing(thingId);
if (thing != null) {