diff --git a/androidservice/androidservice.pro b/androidservice/androidservice.pro
new file mode 100644
index 00000000..8b6cfe84
--- /dev/null
+++ b/androidservice/androidservice.pro
@@ -0,0 +1,52 @@
+TEMPLATE = lib
+TARGET = service
+CONFIG += dll
+QT += core androidextras
+QT += network qml quick quickcontrols2 svg websockets bluetooth charts
+
+include(../config.pri)
+include(../android_openssl/openssl.pri)
+
+
+INCLUDEPATH += $$top_srcdir/libnymea-app/
+
+# https://bugreports.qt.io/browse/QTBUG-83165
+LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
+
+LIBS += -L$$top_builddir/libnymea-app/ -lnymea-app
+PRE_TARGETDEPS += ../libnymea-app
+
+RESOURCES += controlviews/controlviews.qrc \
+ ../nymea-app/resources.qrc \
+ ../nymea-app/images.qrc \
+ ../nymea-app/styles.qrc
+
+INCLUDEPATH += ../nymea-app/
+
+SOURCES += \
+ controlviews/devicecontrolapplication.cpp \
+ nymeaappservice/nymeaappservice.cpp \
+ nymeaappservice/androidbinder.cpp \
+ ../nymea-app/stylecontroller.cpp \
+ ../nymea-app/platformhelper.cpp \
+ ../nymea-app/platformintegration/android/platformhelperandroid.cpp \
+ service_main.cpp
+
+HEADERS += \
+ controlviews/devicecontrolapplication.h \
+ nymeaappservice/nymeaappservice.h \
+ nymeaappservice/androidbinder.h \
+ ../nymea-app/stylecontroller.h \
+ ../nymea-app/platformhelper.h \
+ ../nymea-app/platformintegration/android/platformhelperandroid.h \
+
+DISTFILES += \
+ ../packaging/android/src/io/guh/nymeaapp/Action.java \
+ ../packaging/android/src/io/guh/nymeaapp/NymeaAppControlService.java \
+ ../packaging/android/src/io/guh/nymeaapp/NymeaAppService.java \
+ ../packaging/android/src/io/guh/nymeaapp/NymeaAppControlsActivity.java \
+ ../packaging/android/src/io/guh/nymeaapp/NymeaAppServiceConnection.java \
+ ../packaging/android/src/io/guh/nymeaapp/Thing.java \
+ ../packaging/android/src/io/guh/nymeaapp/State.java \
+ controlviews/Main.qml
+
diff --git a/androidservice/controlviews/Main.qml b/androidservice/controlviews/Main.qml
new file mode 100644
index 00000000..c87839d2
--- /dev/null
+++ b/androidservice/controlviews/Main.qml
@@ -0,0 +1,57 @@
+import QtQuick 2.8
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.1
+import QtQuick.Layouts 1.2
+import Qt.labs.settings 1.0
+import Nymea 1.0
+import "qrc:/ui/devicepages/"
+
+ApplicationWindow {
+ id: app
+ visible: true
+ visibility: ApplicationWindow.FullScreen
+
+ color: Material.background
+
+ // Those variables must be present in the Style
+ title: appName
+ Material.primary: primaryColor
+ Material.accent: accentColor
+ Material.foreground: foregroundColor
+
+ property int margins: 16
+ property int bigMargins: 20
+ property int extraSmallFont: 10
+ property int smallFont: 13
+ property int mediumFont: 16
+ property int largeFont: 20
+ property int iconSize: 30
+ property int delegateHeight: 60
+ property color backgroundColor: Material.background
+
+ readonly property bool landscape: app.width > app.height
+
+ ThingsProxy {
+ id: thingProxy
+ engine: _engine
+ filterDeviceId: controlledThingId
+ }
+
+ property Thing controlledThing: engine.thingManager.fetchingData ? null : engine.thingManager.things.getThing(controlledThingId)
+
+ onControlledThingChanged: {
+ loader.setSource("qrc:/ui/devicepages/" + NymeaUtils.interfaceListToDevicePage(controlledThing.thingClass.interfaces), {thing: controlledThing, header: null})
+ PlatformHelper.hideSplashScreen();
+ }
+
+ Loader {
+ id: loader
+ anchors.fill: parent
+ anchors.bottomMargin: app.margins // For some reason the bottom edge seems a bit off in the overlay
+ }
+
+ onClosing: {
+ print("************* Control View closing")
+ }
+
+}
diff --git a/androidservice/controlviews/controlviews.qrc b/androidservice/controlviews/controlviews.qrc
new file mode 100644
index 00000000..f907b18e
--- /dev/null
+++ b/androidservice/controlviews/controlviews.qrc
@@ -0,0 +1,5 @@
+
+
+ Main.qml
+
+
diff --git a/androidservice/controlviews/devicecontrolapplication.cpp b/androidservice/controlviews/devicecontrolapplication.cpp
new file mode 100644
index 00000000..1b319967
--- /dev/null
+++ b/androidservice/controlviews/devicecontrolapplication.cpp
@@ -0,0 +1,66 @@
+#include "devicecontrolapplication.h"
+
+#include "engine.h"
+#include "connection/discovery/nymeadiscovery.h"
+#include "connection/nymeahosts.h"
+#include "libnymea-app-core.h"
+#include "../nymea-app/stylecontroller.h"
+#include "../nymea-app/platformhelper.h"
+#include "../nymea-app/platformintegration/android/platformhelperandroid.h"
+
+#include
+#include
+#include
+#include
+#include
+
+QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+ return new PlatformHelperAndroid();
+}
+
+DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QApplication(argc, argv)
+{
+ setApplicationName("nymea-app");
+ setOrganizationName("nymea");
+
+ QString nymeaId = QtAndroid::androidActivity().callObjectMethod("nymeaId").toString();
+ QString thingId = QtAndroid::androidActivity().callObjectMethod("thingId").toString();
+
+ QSettings settings;
+
+ NymeaDiscovery *discovery = new NymeaDiscovery(this);
+ AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
+ discovery->setAwsClient(AWSClient::instance());
+ NymeaHost *host = 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;
+ m_engine->jsonRpcClient()->connectToHost(host);
+
+ qDebug() << "Creating QML view";
+ QQmlApplicationEngine *qmlEngine = new QQmlApplicationEngine(this);
+
+ registerQmlTypes();
+
+ qmlRegisterSingletonType("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")));
+}
+
diff --git a/androidservice/controlviews/devicecontrolapplication.h b/androidservice/controlviews/devicecontrolapplication.h
new file mode 100644
index 00000000..4c80e850
--- /dev/null
+++ b/androidservice/controlviews/devicecontrolapplication.h
@@ -0,0 +1,14 @@
+#ifndef DEVICECONTROLAPPLICATION_H
+#define DEVICECONTROLAPPLICATION_H
+
+#include
+
+class DeviceControlApplication : public QApplication
+{
+ Q_OBJECT
+public:
+ explicit DeviceControlApplication(int argc, char *argv[]);
+
+};
+
+#endif // DEVICECONTROLAPPLICATION_H
diff --git a/androidservice/nymeaappservice/androidbinder.cpp b/androidservice/nymeaappservice/androidbinder.cpp
new file mode 100644
index 00000000..b0213fc5
--- /dev/null
+++ b/androidservice/nymeaappservice/androidbinder.cpp
@@ -0,0 +1,115 @@
+#include "androidbinder.h"
+#include "engine.h"
+#include "types/device.h"
+
+#include
+#include
+#include
+#include
+#include
+
+AndroidBinder::AndroidBinder(NymeaAppService *service):
+ m_service(service)
+{
+}
+
+bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags)
+{
+ qDebug() << "onTransact: code " << code << ", flags " << int(flags);
+
+// QString payload = data.readData();
+ QString payload = data.handle().callObjectMethod("readString").toString();
+
+ QJsonParseError error;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(payload.toUtf8(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "Error parsing JSON from parcel:" << error.errorString();
+ qWarning() << payload;
+ return false;
+ }
+ QVariantMap request = jsonDoc.toVariant().toMap();
+
+ if (request.value("method").toString() == "GetInstances") {
+ QVariantMap params;
+ QVariantList instances;
+ foreach (const QUuid &nymeaId, m_service->engines().keys()) {
+ Engine *engine = m_service->engines().value(nymeaId);
+ QVariantMap instance;
+ instance.insert("id", nymeaId);
+ instance.insert("isReady", engine->jsonRpcClient()->connected() && !engine->thingManager()->fetchingData());
+ instance.insert("name", engine->jsonRpcClient()->currentHost()->name());
+ instances.append(instance);
+ }
+ params.insert("instances", instances);
+ sendReply(reply, params);
+ return true;
+ }
+
+ if (request.value("method").toString() == "GetThings") {
+ QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
+ Engine *engine = m_service->engines().value(nymeaId);
+ if (!engine) {
+ qWarning() << "Android client requested things for an invalid nymea instance:" << nymeaId;
+ return false;
+ }
+ QVariantList thingsList;
+ for (int i = 0; i < engine->thingManager()->things()->rowCount(); i++) {
+ Device *thing = engine->thingManager()->things()->get(i);
+ QVariantMap thingMap;
+ thingMap.insert("id", thing->id());
+ thingMap.insert("name", thing->name());
+ thingMap.insert("className", thing->thingClass()->displayName());
+ thingMap.insert("interfaces", thing->thingClass()->interfaces());
+ QVariantList states;
+ for (int j = 0; j < thing->states()->rowCount(); j++) {
+ State *state = thing->states()->get(j);
+ QVariantMap stateMap;
+ stateMap.insert("stateTypeId", state->stateTypeId());
+ stateMap.insert("name", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->name());
+ stateMap.insert("displayName", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->displayName());
+ stateMap.insert("value", state->value());
+ states.append(stateMap);
+ }
+ thingMap.insert("states", states);
+ QVariantList actions;
+ for (int j = 0; j < thing->thingClass()->actionTypes()->rowCount(); j++) {
+ ActionType *actionType = thing->thingClass()->actionTypes()->get(j);
+ QVariantMap actionMap;
+ actionMap.insert("actionTypeId", actionType->id());
+ actionMap.insert("name", actionType->name());
+ actionMap.insert("displayName", actionType->displayName());
+ actions.append(actionMap);
+ }
+ thingMap.insert("actions", actions);
+ thingsList.append(thingMap);
+ }
+ QVariantMap params;
+ params.insert("things", thingsList);
+ sendReply(reply, params);
+ return true;
+ }
+
+ if (request.value("method").toString() == "ExecuteAction") {
+ qDebug() << "ExecuteAction";
+ QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
+ Engine *engine = m_service->engines().value(nymeaId);
+ if (!engine) {
+ qWarning() << "Android client requested executeAction for an invalid nymea instance:" << nymeaId;
+ return false;
+ }
+ QUuid thingId = request.value("params").toMap().value("thingId").toUuid();
+ QUuid actionTypeId = request.value("params").toMap().value("actionTypeId").toUuid();
+ QVariantList params = request.value("params").toMap().value("params").toList();
+
+ qDebug() << "**** executeAction:" << thingId << actionTypeId << params;
+ engine->thingManager()->executeAction(thingId, actionTypeId, params);
+ }
+
+ return false;
+}
+
+void AndroidBinder::sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms)
+{
+ QString payload = QJsonDocument::fromVariant(params).toJson();
+ reply.handle().callMethod("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(payload).object());
+}
diff --git a/androidservice/nymeaappservice/androidbinder.h b/androidservice/nymeaappservice/androidbinder.h
new file mode 100644
index 00000000..36a9b795
--- /dev/null
+++ b/androidservice/nymeaappservice/androidbinder.h
@@ -0,0 +1,23 @@
+#ifndef ANDROIDBINDER_H
+#define ANDROIDBINDER_H
+
+#include
+
+#include "nymeaappservice.h"
+#include "engine.h"
+
+class AndroidBinder : public QAndroidBinder
+{
+public:
+ explicit AndroidBinder(NymeaAppService *service);
+
+ bool onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags) override;
+
+private:
+ void sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms);
+
+private:
+ NymeaAppService *m_service = nullptr;
+};
+
+#endif // ANDROIDBINDER_H
diff --git a/androidservice/nymeaappservice/nymeaappservice.cpp b/androidservice/nymeaappservice/nymeaappservice.cpp
new file mode 100644
index 00000000..d2c673ff
--- /dev/null
+++ b/androidservice/nymeaappservice/nymeaappservice.cpp
@@ -0,0 +1,83 @@
+#include "nymeaappservice.h"
+#include "androidbinder.h"
+
+#include
+#include
+#include
+#include
+
+#include "connection/discovery/nymeadiscovery.h"
+#include "connection/nymeahosts.h"
+
+NymeaAppService::NymeaAppService(int argc, char **argv):
+ QAndroidService(argc, argv, [=](const QAndroidIntent &) {
+ return new AndroidBinder{this};
+ })
+{
+ setApplicationName("nymea-app");
+ setOrganizationName("nymea");
+
+ QSettings settings;
+
+ NymeaDiscovery *discovery = new NymeaDiscovery(this);
+ AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
+ discovery->setAwsClient(AWSClient::instance());
+
+
+ for (int i = 0; i < 5; i++) {
+ settings.beginGroup(QString("tabSettings%1").arg(i));
+ QUuid lastConnected = settings.value("lastConnectedHost").toUuid();
+ settings.endGroup();
+
+ if (lastConnected.isNull()) {
+ continue;
+ }
+ NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
+ if (!host) {
+ continue;
+ }
+
+ Engine *engine = new Engine(this);
+ engine->jsonRpcClient()->connectToHost(host);
+ m_engines.insert(host->uuid(), engine);
+
+
+ QObject::connect(engine->thingManager(), &DeviceManager::thingStateChanged, [=](const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value){
+ QVariantMap params;
+ params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
+ params.insert("thingId", thingId);
+ params.insert("stateTypeId", stateTypeId);
+ params.insert("value", value);
+ sendNotification("ThingStateChanged", params);
+ });
+
+ connect(engine->thingManager(), &DeviceManager::fetchingDataChanged, [=]() {
+ qDebug() << "Fetching data changed";
+ QVariantMap params;
+ params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
+ params.insert("isReady", !engine->thingManager()->fetchingData());
+ qDebug() << "Nymea host is ready" << engine->jsonRpcClient()->currentHost()->uuid();
+ sendNotification("ReadyStateChanged", params);
+ });
+ }
+
+ qDebug() << "NymeaAppService started.";
+
+}
+
+QHash NymeaAppService::engines() const
+{
+ return m_engines;
+}
+
+void NymeaAppService::sendNotification(const QString ¬ification, const QVariantMap ¶ms)
+{
+ QVariantMap data;
+ data.insert("notification", notification);
+ data.insert("params", params);
+ QString payload = QJsonDocument::fromVariant(data).toJson();
+ QtAndroid::androidService().callMethod("sendBroadcast",
+ "(Ljava/lang/String;)V",
+ QAndroidJniObject::fromString(payload).object());
+
+}
diff --git a/androidservice/nymeaappservice/nymeaappservice.h b/androidservice/nymeaappservice/nymeaappservice.h
new file mode 100644
index 00000000..6f6e653a
--- /dev/null
+++ b/androidservice/nymeaappservice/nymeaappservice.h
@@ -0,0 +1,25 @@
+#ifndef NYMEAAPPSERVICE_H
+#define NYMEAAPPSERVICE_H
+
+#include
+
+#include "engine.h"
+
+class NymeaAppService : public QAndroidService
+{
+ Q_OBJECT
+public:
+ explicit NymeaAppService(int argc, char** argv);
+
+ QHash engines() const;
+
+private:
+ void sendNotification(const QString ¬ification, const QVariantMap ¶ms);
+
+
+private:
+ QHash m_engines;
+
+};
+
+#endif // NYMEAAPPSERVICE_H
diff --git a/androidservice/service_main.cpp b/androidservice/service_main.cpp
new file mode 100644
index 00000000..46efab22
--- /dev/null
+++ b/androidservice/service_main.cpp
@@ -0,0 +1,37 @@
+#include
+#include
+
+#include "nymeaappservice/nymeaappservice.h"
+#include "controlviews/devicecontrolapplication.h"
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ qWarning() << "Service starting from a separate .so file";
+
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=true\n");
+
+ QStringList args;
+ for (int i = 0; i < argc; i++) {
+ args.append(QByteArray(argv[i]));
+ qDebug() << "nymea-app: Added command line arg" << args.last();
+ }
+ QCommandLineParser parser;
+ QCommandLineOption controlActivityOption("controlActivity");
+ parser.addOption(controlActivityOption);
+ parser.parse(args);
+
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QCoreApplication *app;
+ if (parser.isSet(controlActivityOption)) {
+ qDebug() << "nymea-app: Starting Device Control Activity";
+ app = new DeviceControlApplication(argc, argv);
+ } else {
+ qDebug() << "nymea-app: Starting NymeaAppService background service";
+ app = new NymeaAppService(argc, argv);
+ }
+ return app->exec();
+}
diff --git a/config.pri b/config.pri
index 9d0cae52..1dfee639 100644
--- a/config.pri
+++ b/config.pri
@@ -11,3 +11,6 @@ APP_REVISION=$$member(VERSION_INFO, 1)
DEFINES+=APP_VERSION=\\\"$${APP_VERSION}\\\"
android:QMAKE_POST_LINK += cp $$top_srcdir/version.txt $$top_builddir/
+
+DISTFILES += \
+ $$PWD/packaging/android/src/io/guh/nymeaapp/NymeaHost.java
diff --git a/libnymea-app/devicemanager.cpp b/libnymea-app/devicemanager.cpp
index a2eaafd1..b2ce20d7 100644
--- a/libnymea-app/devicemanager.cpp
+++ b/libnymea-app/devicemanager.cpp
@@ -175,10 +175,11 @@ void DeviceManager::notificationReceived(const QVariantMap &data)
qWarning() << "Device state change notification received for an unknown device";
return;
}
- QUuid stateTyoeId = data.value("params").toMap().value("stateTypeId").toUuid();
+ QUuid stateTypeId = data.value("params").toMap().value("stateTypeId").toUuid();
QVariant value = data.value("params").toMap().value("value");
-// qDebug() << "Device state changed for:" << dev->name() << "State name:" << dev->thingClass()->stateTypes()->getStateType(stateTyoeId) << "value:" << value;
- dev->setStateValue(stateTyoeId, value);
+// qDebug() << "Device state changed for:" << dev->name() << "State name:" << dev->thingClass()->stateTypes()->getStateType(stateTypeId) << "value:" << value;
+ dev->setStateValue(stateTypeId, value);
+ emit thingStateChanged(dev->id(), stateTypeId, value);
} else if (notification == "Devices.DeviceAdded") {
Device *dev = JsonTypes::unpackDevice(this, data.value("params").toMap().value("device").toMap(), m_thingClasses);
if (!dev) {
diff --git a/libnymea-app/devicemanager.h b/libnymea-app/devicemanager.h
index b09d3ddc..f8e1fc1d 100644
--- a/libnymea-app/devicemanager.h
+++ b/libnymea-app/devicemanager.h
@@ -61,6 +61,7 @@ class DeviceManager : public JsonHandler
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged)
+ Q_ENUMS(RemovePolicy)
public:
enum RemovePolicy {
RemovePolicyNone,
@@ -151,7 +152,8 @@ signals:
void fetchingDataChanged();
void notificationReceived(const QString &deviceId, const QString &eventTypeId, const QVariantList ¶ms);
- void eventTriggered(const QString &deviceId, const QString &eventTypeId, const QVariantMap params);
+ void eventTriggered(const QUuid &deviceId, const QUuid &eventTypeId, const QVariantMap params);
+ void thingStateChanged(const QUuid &deviceId, const QUuid &stateTypeId, const QVariant &value);
private:
Vendors *m_vendors;
diff --git a/libnymea-app/engine.h b/libnymea-app/engine.h
index 300b7fb4..07b38c6a 100644
--- a/libnymea-app/engine.h
+++ b/libnymea-app/engine.h
@@ -61,9 +61,6 @@ class Engine : public QObject
public:
explicit Engine(QObject *parent = nullptr);
- bool connected() const;
- QString connectedHost() const;
-
DeviceManager *deviceManager() const;
DeviceManager *thingManager() const;
RuleManager *ruleManager() const;
diff --git a/libnymea-common/libnymea-common.h b/libnymea-common/libnymea-common.h
deleted file mode 100644
index 1fd15938..00000000
--- a/libnymea-common/libnymea-common.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include
-
-#if defined(LIBNYMEA_COMMON)
-# define LIBNYMEA_COMMON_EXPORT Q_DECL_EXPORT
-#else
-# define LIBNYMEA_COMMON_EXPORT Q_DECL_IMPORT
-#endif
diff --git a/libnymea-common/libnymea-common.pro b/libnymea-common/libnymea-common.pro
deleted file mode 100644
index a7e17797..00000000
--- a/libnymea-common/libnymea-common.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-include(../config.pri)
-
-TARGET = nymea-common
-TEMPLATE = lib
-CONFIG += staticlib
-
-QT -= gui
-QT += network
-
-HEADERS += \
-
-
-SOURCES += \
-
-
diff --git a/nymea-app.pro b/nymea-app.pro
index da9e334c..7a4e805b 100644
--- a/nymea-app.pro
+++ b/nymea-app.pro
@@ -82,6 +82,12 @@ icons.path = /usr/share/
INSTALLS += desktopfile icons
}
+# Android service
+android: {
+SUBDIRS += androidservice
+androidservice.depends = libnymea-app
+}
+
# Linux desktop (snap package)
snap: {
desktopfile.files = packaging/linux/nymea-app.desktop
diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro
index 3f368f1d..8bb1b85e 100644
--- a/nymea-app/nymea-app.pro
+++ b/nymea-app/nymea-app.pro
@@ -81,6 +81,8 @@ android {
# https://bugreports.qt.io/browse/QTBUG-83165
LIBS += -L$${top_builddir}/libnymea-app/$${ANDROID_TARGET_ARCH}
+
+ ANDROID_ABIS = armeabi-v7a arm64-v8a
}
macx: {
@@ -160,4 +162,3 @@ BR=$$BRANDING
target.path = /usr/bin
INSTALLS += target
-
diff --git a/nymea-app/platformintegration/android/platformhelperandroid.cpp b/nymea-app/platformintegration/android/platformhelperandroid.cpp
index 7332b8e9..7dcdb315 100644
--- a/nymea-app/platformintegration/android/platformhelperandroid.cpp
+++ b/nymea-app/platformintegration/android/platformhelperandroid.cpp
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
// WindowManager.LayoutParams
@@ -47,13 +48,16 @@ static PlatformHelperAndroid *m_instance;
static QAndroidJniObject getAndroidWindow()
{
QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;");
- window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS);
return window;
}
PlatformHelperAndroid::PlatformHelperAndroid(QObject *parent) : PlatformHelper(parent)
{
+// QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(), "io.guh.nymeaapp.NymeaAppControlService");
+
+// m_serviceConnection = new DeviceControlServiceConnection();
+// QtAndroid::bindService(serviceIntent, *m_serviceConnection, QtAndroid::BindFlag::AutoCreate);
+
m_instance = this;
}
@@ -123,6 +127,33 @@ void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType
QtAndroid::androidActivity().callMethod("vibrate","(I)V", duration);
}
+//void PlatformHelperAndroid::syncThings()
+//{
+
+// QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(),
+// "io/guh/nymeaapp/NymeaAppService");
+// QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod(
+// "startService",
+// "(Landroid/content/Intent;)Landroid/content/ComponentName;",
+// serviceIntent.handle().object());
+
+
+//// QtAndroid::androidService()
+
+//// QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(),
+//// "io/guh/nymeaapp/NymeaAppControlService");
+//// serviceIntent.putExtra("name", QByteArray("foobar"));
+
+
+//// m_serviceConnection->handle().callMethod("syncThings", "(Ljava/lang/String;)V", "bla");
+
+
+//// QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod(
+//// "syncThings",
+//// "(Landroid/content/Intent;)Landroid/content/ComponentName;",
+//// m_serviceConnection->handle().object());
+//}
+
void PlatformHelperAndroid::setTopPanelColor(const QColor &color)
{
PlatformHelper::setTopPanelColor(color);
@@ -132,6 +163,8 @@ void PlatformHelperAndroid::setTopPanelColor(const QColor &color)
QtAndroid::runOnAndroidThread([=]() {
QAndroidJniObject window = getAndroidWindow();
+ window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS);
window.callMethod("setStatusBarColor", "(I)V", color.rgba());
});
diff --git a/nymea-app/platformintegration/android/platformhelperandroid.h b/nymea-app/platformintegration/android/platformhelperandroid.h
index b648b755..fed19a80 100644
--- a/nymea-app/platformintegration/android/platformhelperandroid.h
+++ b/nymea-app/platformintegration/android/platformhelperandroid.h
@@ -31,9 +31,11 @@
#ifndef PLATFORMHELPERANDROID_H
#define PLATFORMHELPERANDROID_H
-#include
#include "platformhelper.h"
+
+#include
#include
+#include
class PlatformHelperAndroid : public PlatformHelper
{
@@ -62,7 +64,6 @@ public:
private:
static void permissionRequestFinished(const QtAndroid::PermissionResultMap &);
-
};
#endif // PLATFORMHELPERANDROID_H
diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml
index 87f17cb9..e50a72c0 100644
--- a/nymea-app/ui/Nymea.qml
+++ b/nymea-app/ui/Nymea.qml
@@ -456,52 +456,6 @@ ApplicationWindow {
}
}
- function interfaceListToDevicePage(interfaceList) {
- var page;
- if (interfaceList.indexOf("media") >= 0) {
- page = "MediaDevicePage.qml";
- } else if (interfaceList.indexOf("button") >= 0) {
- page = "ButtonDevicePage.qml";
- } else if (interfaceList.indexOf("powerswitch") >= 0) {
- page = "ButtonDevicePage.qml";
- } else if (interfaceList.indexOf("weather") >= 0) {
- page = "WeatherDevicePage.qml";
- } else if (interfaceList.indexOf("heating") >= 0 || interfaceList.indexOf("thermostat") >= 0) {
- page = "HeatingDevicePage.qml";
- } else if (interfaceList.indexOf("sensor") >= 0) {
- page = "SensorDevicePage.qml";
- } else if (interfaceList.indexOf("inputtrigger") >= 0) {
- page = "InputTriggerDevicePage.qml";
- } else if (interfaceList.indexOf("garagedoor") >= 0 ) {
- page = "GarageThingPage.qml";
- } else if (interfaceList.indexOf("light") >= 0) {
- page = "LightDevicePage.qml";
- } else if (interfaceList.indexOf("shutter") >= 0 || interfaceList.indexOf("blind") >= 0) {
- page = "ShutterDevicePage.qml";
- } else if (interfaceList.indexOf("awning") >= 0) {
- page = "AwningDevicePage.qml";
- } else if (interfaceList.indexOf("notifications") >= 0) {
- page = "NotificationsDevicePage.qml";
- } else if (interfaceList.indexOf("fingerprintreader") >= 0) {
- page = "FingerprintReaderDevicePage.qml";
- } else if (interfaceList.indexOf("smartmeter") >= 0) {
- page = "SmartMeterDevicePage.qml"
- } else if (interfaceList.indexOf("powersocket") >= 0) {
- page = "PowersocketDevicePage.qml";
- } else if (interfaceList.indexOf("doorbell") >= 0) {
- page = "DoorbellDevicePage.qml";
- } else if (interfaceList.indexOf("irrigation") >= 0) {
- page = "IrrigationDevicePage.qml";
- } else if (interfaceList.indexOf("ventilation") >= 0) {
- page = "VentilationDevicePage.qml";
- } else if (interfaceList.indexOf("barcodescanner") >= 0) {
- page = "BarcodeScannerThingPage.qml";
- } else {
- page = "GenericDevicePage.qml";
- }
- print("Selecting page", page, "for interface list:", interfaceList)
- return page;
- }
function pad(num, size) {
var s = "000000000" + num;
diff --git a/nymea-app/ui/devicepages/GarageThingPage.qml b/nymea-app/ui/devicepages/GarageThingPage.qml
index e12e34cf..e314ad76 100644
--- a/nymea-app/ui/devicepages/GarageThingPage.qml
+++ b/nymea-app/ui/devicepages/GarageThingPage.qml
@@ -79,7 +79,7 @@ DevicePageBase {
Layout.alignment: Qt.AlignHCenter
property string currentImage: {
if (root.isExtended) {
- return app.pad(Math.round(root.percentageState.value / 10), 2) + "0"
+ return NymeaUtils.pad(Math.round(root.percentageState.value / 10), 2) + "0"
}
if (root.intermediatePositionStateType) {
return root.stateState.value === "closed" ? "100"
diff --git a/nymea-app/ui/grouping/GroupThingsPage.qml b/nymea-app/ui/grouping/GroupThingsPage.qml
index b5ea065c..6966be01 100644
--- a/nymea-app/ui/grouping/GroupThingsPage.qml
+++ b/nymea-app/ui/grouping/GroupThingsPage.qml
@@ -129,7 +129,7 @@ Page {
device: devicesInGroup.get(index)
- onClicked: pageStack.push(Qt.resolvedUrl("../devicepages/" + app.interfaceListToDevicePage(deviceClass.interfaces)), {device: device})
+ onClicked: pageStack.push(Qt.resolvedUrl("../devicepages/" + NymeaUtils.interfaceListToDevicePage(deviceClass.interfaces)), {device: device})
}
}
diff --git a/nymea-app/ui/mainviews/FavoritesView.qml b/nymea-app/ui/mainviews/FavoritesView.qml
index 48c4eaf9..d54f10b9 100644
--- a/nymea-app/ui/mainviews/FavoritesView.qml
+++ b/nymea-app/ui/mainviews/FavoritesView.qml
@@ -64,7 +64,7 @@ MainViewBase {
height: gridView.cellHeight
device: engine.deviceManager.devices.getDevice(deviceId)
- onClicked: pageStack.push(Qt.resolvedUrl("../devicepages/" + app.interfaceListToDevicePage(deviceClass.interfaces)), {device: device})
+ onClicked: pageStack.push(Qt.resolvedUrl("../devicepages/" + NymeaUtils.interfaceListToDevicePage(deviceClass.interfaces)), {device: device})
onPressAndHold: root.editMode = true
diff --git a/nymea-app/ui/utils/NymeaUtils.qml b/nymea-app/ui/utils/NymeaUtils.qml
index 2ed6f93d..a705e64c 100644
--- a/nymea-app/ui/utils/NymeaUtils.qml
+++ b/nymea-app/ui/utils/NymeaUtils.qml
@@ -15,4 +15,53 @@ Item {
}
return str;
}
+
+ function interfaceListToDevicePage(interfaceList) {
+ print("**** getting page for interfaces", interfaceList)
+ var page;
+ if (interfaceList.indexOf("media") >= 0) {
+ page = "MediaDevicePage.qml";
+ } else if (interfaceList.indexOf("button") >= 0) {
+ page = "ButtonDevicePage.qml";
+ } else if (interfaceList.indexOf("powerswitch") >= 0) {
+ page = "ButtonDevicePage.qml";
+ } else if (interfaceList.indexOf("weather") >= 0) {
+ page = "WeatherDevicePage.qml";
+ } else if (interfaceList.indexOf("heating") >= 0 || interfaceList.indexOf("thermostat") >= 0) {
+ page = "HeatingDevicePage.qml";
+ } else if (interfaceList.indexOf("sensor") >= 0) {
+ page = "SensorDevicePage.qml";
+ } else if (interfaceList.indexOf("inputtrigger") >= 0) {
+ page = "InputTriggerDevicePage.qml";
+ } else if (interfaceList.indexOf("garagedoor") >= 0 ) {
+ page = "GarageThingPage.qml";
+ } else if (interfaceList.indexOf("light") >= 0) {
+ page = "LightDevicePage.qml";
+ } else if (interfaceList.indexOf("shutter") >= 0 || interfaceList.indexOf("blind") >= 0) {
+ page = "ShutterDevicePage.qml";
+ } else if (interfaceList.indexOf("awning") >= 0) {
+ page = "AwningDevicePage.qml";
+ } else if (interfaceList.indexOf("notifications") >= 0) {
+ page = "NotificationsDevicePage.qml";
+ } else if (interfaceList.indexOf("fingerprintreader") >= 0) {
+ page = "FingerprintReaderDevicePage.qml";
+ } else if (interfaceList.indexOf("smartmeter") >= 0) {
+ page = "SmartMeterDevicePage.qml"
+ } else if (interfaceList.indexOf("powersocket") >= 0) {
+ page = "PowersocketDevicePage.qml";
+ } else if (interfaceList.indexOf("doorbell") >= 0) {
+ page = "DoorbellDevicePage.qml";
+ } else if (interfaceList.indexOf("irrigation") >= 0) {
+ page = "IrrigationDevicePage.qml";
+ } else if (interfaceList.indexOf("ventilation") >= 0) {
+ page = "VentilationDevicePage.qml";
+ } else if (interfaceList.indexOf("barcodescanner") >= 0) {
+ page = "BarcodeScannerThingPage.qml";
+ } else {
+ page = "GenericDevicePage.qml";
+ }
+ print("Selecting page", page, "for interface list:", interfaceList)
+ return page;
+ }
+
}
diff --git a/packaging/android/AndroidManifest.xml b/packaging/android/AndroidManifest.xml
index 4bbbaaf7..0b5b5f28 100644
--- a/packaging/android/AndroidManifest.xml
+++ b/packaging/android/AndroidManifest.xml
@@ -62,8 +62,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -73,9 +126,15 @@
+
+
+
+
+
+
-
+