From 9279db96086f7876e8dd478003fd4402d182f078 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 18 Sep 2018 23:20:22 +0200 Subject: [PATCH] working edition of push notifications on android, to be cleaned up still --- .gitmodules | 6 + QtFirebase | 1 + libnymea-app-core/connection/awsclient.cpp | 55 + libnymea-app-core/connection/awsclient.h | 2 + .../connection/cloudtransport.cpp | 4 +- libnymea-app-core/libnymea-app-core.pro | 1 + nymea-app/main.cpp | 18 + nymea-app/nymea-app.pro | 24 +- nymea-app/ui/MainPage.qml | 2 +- nymea-app/ui/Nymea.qml | 58 ++ packaging/android/AndroidManifest.xml | 21 +- packaging/android/build.gradle | 17 +- packaging/android/google-services.json | 42 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- packaging/android/notificationicon.svg | 939 ++++++++++++++++++ .../ic_stat_notificationicon.png | Bin 0 -> 1179 bytes packaging/android/res/drawable-ldpi/icon.png | Bin 0 -> 17652 bytes .../ic_stat_notificationicon.png | Bin 0 -> 759 bytes .../ic_stat_notificationicon.png | Bin 0 -> 1853 bytes .../ic_stat_notificationicon.png | Bin 0 -> 2779 bytes .../ic_stat_notificationicon.png | Bin 0 -> 4295 bytes .../src/io/guh/nymeaapp/NymeaAppActivity.java | 44 + .../nymeaapp/NymeaAppNotificationService.java | 75 ++ qtcloudmessaging | 1 + 24 files changed, 1294 insertions(+), 18 deletions(-) create mode 160000 QtFirebase create mode 100644 packaging/android/google-services.json create mode 100644 packaging/android/notificationicon.svg create mode 100644 packaging/android/res/drawable-hdpi/ic_stat_notificationicon.png create mode 100644 packaging/android/res/drawable-ldpi/icon.png create mode 100644 packaging/android/res/drawable-mdpi/ic_stat_notificationicon.png create mode 100644 packaging/android/res/drawable-xhdpi/ic_stat_notificationicon.png create mode 100644 packaging/android/res/drawable-xxhdpi/ic_stat_notificationicon.png create mode 100644 packaging/android/res/drawable-xxxhdpi/ic_stat_notificationicon.png create mode 100644 packaging/android/src/io/guh/nymeaapp/NymeaAppActivity.java create mode 100644 packaging/android/src/io/guh/nymeaapp/NymeaAppNotificationService.java create mode 160000 qtcloudmessaging diff --git a/.gitmodules b/.gitmodules index 2be744c1..71fb2c3b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "nymea-remoteproxy"] path = nymea-remoteproxy url = https://github.com/guh/nymea-remoteproxy.git +[submodule "qtcloudmessaging"] + path = qtcloudmessaging + url = https://github.com/qt/qtcloudmessaging.git +[submodule "QtFirebase"] + path = QtFirebase + url = https://github.com/Larpon/QtFirebase.git diff --git a/QtFirebase b/QtFirebase new file mode 160000 index 00000000..593032a7 --- /dev/null +++ b/QtFirebase @@ -0,0 +1 @@ +Subproject commit 593032a7c613d40c55212ec10790400fd4a30c8f diff --git a/libnymea-app-core/connection/awsclient.cpp b/libnymea-app-core/connection/awsclient.cpp index d66e59b4..f42dd7c8 100644 --- a/libnymea-app-core/connection/awsclient.cpp +++ b/libnymea-app-core/connection/awsclient.cpp @@ -605,6 +605,61 @@ void AWSClient::getId() }); } +void AWSClient::registerPushNotificationEndpoint(const QString ®istrationId) +{ + if (!isLoggedIn()) { + qWarning() << "Not logged in at AWS. Can't register push endpoint"; + return; + } + if (tokensExpired()) { + qDebug() << "Cannot register push endpoint. Need to refresh our tokens"; + refreshAccessToken(); + m_callQueue.append(QueuedCall("registerPushNotificationEndpoint", registrationId)); + return; + } + qDebug() << "Registering push notification endpoint."; + + QUrl url(QString("https://%1/notifications/endpoints/%2").arg(m_configs.at(m_usedConfigIndex).apiEndpoint).arg(m_userId)); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader("x-api-idToken", m_idToken); + + qDebug() << "POST" << url.toString(); + qDebug() << "HEADERS:"; + foreach (const QByteArray &hdr, request.rawHeaderList()) { + qDebug() << hdr << ":" << request.rawHeader(hdr); + } + + QVariantMap payload; + payload.insert("registrationId", registrationId); + payload.insert("channel", "GCM"); + payload.insert("mobileDeviceDisplayName", "test device"); + payload.insert("mobileDeviceUuid", "12345678"); + QJsonDocument jsonDoc = QJsonDocument::fromVariant(payload); + + QNetworkReply *reply = m_nam->post(request, jsonDoc.toJson(QJsonDocument::Compact)); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + reply->deleteLater(); + QByteArray data = reply->readAll(); + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error registering push notification endpoint:" << reply->error() << reply->errorString() << qUtf8Printable(data); +// emit deleteAccountResult(LoginErrorUnknownError); + return; + } + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse JSON from server" << error.errorString() << qUtf8Printable(data); +// emit deleteAccountResult(LoginErrorUnknownError); + return; + } +// emit deleteAccountResult(LoginErrorNoError); +// logout(); + qDebug() << "Push notification endpoint registered" << data; + }); + +} + QByteArray AWSClient::idToken() const { return m_idToken; diff --git a/libnymea-app-core/connection/awsclient.h b/libnymea-app-core/connection/awsclient.h index 3ef89562..58ee2dc2 100644 --- a/libnymea-app-core/connection/awsclient.h +++ b/libnymea-app-core/connection/awsclient.h @@ -118,6 +118,8 @@ public: Q_INVOKABLE bool postToMQTT(const QString &boxId, const QString ×tamp, std::function callback); Q_INVOKABLE void getId(); + Q_INVOKABLE void registerPushNotificationEndpoint(const QString ®istrationId); + bool tokensExpired() const; QByteArray idToken() const; QString cognitoIdentityId() const; diff --git a/libnymea-app-core/connection/cloudtransport.cpp b/libnymea-app-core/connection/cloudtransport.cpp index e8dc0071..53e48daf 100644 --- a/libnymea-app-core/connection/cloudtransport.cpp +++ b/libnymea-app-core/connection/cloudtransport.cpp @@ -95,13 +95,13 @@ NymeaTransportInterface::ConnectionState CloudTransport::connectionState() const void CloudTransport::sendData(const QByteArray &data) { - qDebug() << "should send" << data; +// qDebug() << "Cloud transport: Sending data:" << data; m_remoteproxyConnection->sendData(data); } void CloudTransport::ignoreSslErrors(const QList &errors) { - qDebug() << "Ignoring SSL errors" << errors; + qDebug() << "CloudTransport: Ignoring SSL errors" << errors; m_remoteproxyConnection->ignoreSslErrors(errors); } diff --git a/libnymea-app-core/libnymea-app-core.pro b/libnymea-app-core/libnymea-app-core.pro index ecbe52f0..6b85a26f 100644 --- a/libnymea-app-core/libnymea-app-core.pro +++ b/libnymea-app-core/libnymea-app-core.pro @@ -13,6 +13,7 @@ include(../config.pri) include(../nymea-remoteproxy/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri) + QT -= gui QT += network websockets bluetooth diff --git a/nymea-app/main.cpp b/nymea-app/main.cpp index e3895e19..860b8221 100644 --- a/nymea-app/main.cpp +++ b/nymea-app/main.cpp @@ -26,6 +26,8 @@ #include #ifdef Q_OS_ANDROID +#include +#include #include #endif @@ -69,6 +71,22 @@ int main(int argc, char *argv[]) Engine::instance(); QQmlApplicationEngine *engine = new QQmlApplicationEngine(); + +#ifdef Q_OS_ANDROID + QCloudMessaging *pushServices = new QCloudMessaging(); + QCloudMessagingFirebaseProvider *m_firebaseService = new QCloudMessagingFirebaseProvider(); + + QVariantMap provider_params; + provider_params["SERVER_API_KEY"] = "AIzaSyAvKQXY4-kZw9Y7MTqVDoF2XCvC7fnhKUs"; + + pushServices->registerProvider("GoogleFireBase", m_firebaseService, provider_params); + pushServices->connectClient("GoogleFireBase", "nymea:app", QVariantMap()); + + pushServices->subscribeToChannel("ChatRoom", "GoogleFireBase", "nymea:app"); + + engine->rootContext()->setContextProperty("pushServices", pushServices); +#endif + #ifdef BRANDING engine->rootContext()->setContextProperty("appBranding", BRANDING); #else diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro index 4fba9a75..53049f53 100644 --- a/nymea-app/nymea-app.pro +++ b/nymea-app/nymea-app.pro @@ -2,7 +2,7 @@ TEMPLATE=app TARGET=nymea-app include(../config.pri) -QT += network qml quick quickcontrols2 svg websockets bluetooth +QT += network qml quick quickcontrols2 svg websockets bluetooth #cloudmessaging INCLUDEPATH += $$top_srcdir/libnymea-common \ $$top_srcdir/libnymea-app-core @@ -32,26 +32,34 @@ equals(STYLES_PATH, "") { RESOURCES += $${STYLES_PATH}/styles.qrc } -contains(ANDROID_TARGET_ARCH,armeabi-v7a) { - ANDROID_EXTRA_LIBS = \ - /opt/android-openssl/prebuilt/armeabi-v7a/libcrypto.so \ - /opt/android-openssl/prebuilt/armeabi-v7a/libssl.so -} - android { ANDROID_PACKAGE_SOURCE_DIR = $$PWD/../packaging/android - QT += androidextras +# QTFIREBASE_CONFIG+=messaging +# QTFIREBASE_SDK_PATH=/opt/firebase_cpp_sdk/ +# include(../QtFirebase/qtfirebase.pri) + + INCLUDEPATH += /opt/firebase_cpp_sdk/include + + QT += androidextras cloudmessagingfirebase DISTFILES += \ $$ANDROID_PACKAGE_SOURCE_DIR/AndroidManifest.xml \ + $$ANDROID_PACKAGE_SOURCE_DIR/google-services.json \ $$ANDROID_PACKAGE_SOURCE_DIR/gradle/wrapper/gradle-wrapper.jar \ $$ANDROID_PACKAGE_SOURCE_DIR/gradlew \ $$ANDROID_PACKAGE_SOURCE_DIR/res/values/libs.xml \ $$ANDROID_PACKAGE_SOURCE_DIR/build.gradle \ $$ANDROID_PACKAGE_SOURCE_DIR/gradle/wrapper/gradle-wrapper.properties \ $$ANDROID_PACKAGE_SOURCE_DIR/gradlew.bat \ + $$ANDROID_PACKAGE_SOURCE_DIR/src/io/guh/nymeaapp/NymeaAppActivity.java \ + $$ANDROID_PACKAGE_SOURCE_DIR/src/io/guh/nymeaapp/NymeaAppNotificationService.java \ $$ANDROID_PACKAGE_SOURCE_DIR/LICENSE + + + ANDROID_EXTRA_LIBS = \ + /opt/android-openssl/prebuilt/armeabi-v7a/libcrypto.so \ + /opt/android-openssl/prebuilt/armeabi-v7a/libssl.so } macx: { diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index 433648a9..5e370dd2 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -160,7 +160,7 @@ Page { spacing: app.margins visible: Engine.deviceManager.fetchingData BusyIndicator { - anchors.horizontalCenter: parent.horizontalCenter + Layout.alignment: Qt.AlignHCenter running: parent.visible } Label { diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index 7a4ca9bb..578f5fb4 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -6,6 +6,8 @@ import Qt.labs.settings 1.0 import QtQuick.Window 2.3 import Nymea 1.0 +//import QtFirebase 1.0 + ApplicationWindow { id: app visible: true @@ -51,6 +53,10 @@ ApplicationWindow { Component.onCompleted: { pageStack.push(Qt.resolvedUrl("connection/ConnectPage.qml")) + + var clientUuid = pushServices.clientToken("GoogleFireBase", "nymea:app"); + print("Messaging client uuid:", clientUuid) + Engine.awsClient.registerPushNotificationEndpoint(clientUuid); } Connections { @@ -375,6 +381,58 @@ ApplicationWindow { } } + Connections { + target:pushServices + onMessageReceived:{ + console.log("Message to " + providerId + " service to " + clientId + " client.") + console.log("Message: " + message) + + var msg_in_json = JSON.parse(message); + + // Example to respond to embedded system request: + if (msg_in_json.command === "REQUESTING_TEMPERATURE") + embeddedPublishTemperatureToServer(msg_in_json.serverID, mydevicecommand.getTemperature()); + + // Or firebase the message itself is a container of the info. + updateGameNotification(message); + } + + onServiceStateUpdated: { + print("push service state updated", state) + } + + // Own Uuid to be used or broadcasted to server. + onClientTokenReceived: { + + console.log("MY Uuid:"+rid) + + // Id this is server code: + serverUuid = rid; + + // Id this is client code: + clientUuid = rid; + + } + } + + +// Messaging { +// id: messaging + +// onReadyChanged: { +// App.log("Messaging.ready", ready) +// } +// onTokenChanged: { +// App.log("Messaging.token", token) +// } +// onDataChanged: { +// App.log("Messaging.data", JSON.stringify(data)) +// } +// onMessageReceived: { +// App.log("onMessageReceived","Messaging.data", JSON.stringify(data)) +// } +// } + KeyboardLoader { id: keyboardRect anchors { left: parent.left; bottom: parent.bottom; right: parent.right } diff --git a/packaging/android/AndroidManifest.xml b/packaging/android/AndroidManifest.xml index d72575a6..c3cd3ee5 100644 --- a/packaging/android/AndroidManifest.xml +++ b/packaging/android/AndroidManifest.xml @@ -1,7 +1,7 @@ - + @@ -32,6 +32,8 @@ + + @@ -55,15 +57,24 @@ * minimal - useful for Quick Controls 2 apps, it is much faster than "full" * none - useful for apps that don't use any of the above Qt modules --> - + - + - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/android/res/drawable-hdpi/ic_stat_notificationicon.png b/packaging/android/res/drawable-hdpi/ic_stat_notificationicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8918827fbb153427d5985739bee26b8a2fdc17d4 GIT binary patch literal 1179 zcmV;M1Z4Y(P)OH8qByDyBpvrfP&B zA%x%p2}(7FNQ1w%s1yNz_-9sU@`EDq<`8jycM8`@JlZMZUeSxn>_ti0#^YKNLtkt+XyHk z_RW><3Ee7MdHIjP@sd8N12qs(MEKds!1KU`!1=&IO)G5id?xUeBya5)>kBBs%yF54 z|9}aS{)&jNfIZf-QU-A;aBn|Qg8-chEK2zQ0`CIH0=olu0>=RBx2Q&)%PdI?s}5rT zMa2HVrzOXglEy{E%fPjO0qz3a5A4`y%DUj3Ch5a+Ko6jtrtg8tRY3k85w6brz~}jV zTi_mGzb+_BzCQs|B)Kg{tqRC}^I#>posW{VBqDYO4B|ZC1K{KI-2r$4*k%Y|b0vA9 zy?`QOBj9IX%SzIbtiW~IjNT@jNzx1Q=O6iby+<2(8#o6rA@1a<%Kqzz*Rhid@?2A) zi13J;S*zypbkF<-%+AD*=gX?T8v=U)PZtvu5fcDc_FUld0TrAn>B*igiwM8u>;VDK zN}7>5KIBBpzOBjTZsORc(=^)2e{Xr0#`5HXrczJp*hCxEh0O znWW`;_L(B)0yhG$0-N*+vj6D2%Ujl$IZMHJ16O2E{0&U38Tk=OUq*z19}Jub{0X=Z z2b~W4IHn6AW1B7Mk=zci)V<+h7}Ix>KFdKlA_wJRV0=wg=SW)66_E4Y;6F*Llef%S z)ycGHIi-`29SeIjvn#XEh!?x+qZpX3l9PA12$*?QaoNOKt&Rd zv8m$MJcM^EfqJ7OQI595uoWr*T?s5nQZ%U=n77a(&IfWAn=0w+GN51bSm=_(+UB)v z?s34f1UC(E6SuV$l17i6G9WYM8ErG9-#kgTM#R?1VVeQJ1I~3ohg>g6vQF;-bb69r zhdeBnWbI@n;H~l`S-w2hC5aDfNsm?m`H)-zxb$t!hv#@nBN5?ga#Nc?E#}&qF98!J znQX_%k4rLP+hq1TNzzMMrAdG<1)i|BHeb@sg>zL8nRS2YIIc@29hQL1#Fi%}!_ogW zn0I7y`QFw~!XB8!*OaVy?lW+Pq~{{SC%JoR7I1Zo1QveQPHSwC$hRWwGPc%AQ&SC? zvCmBXU5Du+N!H~(R(B0@Ki$=0m4(YkfG5@4emihNP3%11g3DUEZx59dpwmUM0?e%ID^SyEU4&U9TeenhIWS$)dv&X8yxTiCA}k{=1FRai zYFn=KvoN~_xI>cfbhXwBP>~_YZ+a@gBU4*fb9m~$1K#mZG5&3!&95GfJ=C<4tlSjf t=+r_6<`e%-Nxp0jWt}QC)Ehbm{STHIS2U%{n$G|L002ovPDHLkV1iL-DntMP literal 0 HcmV?d00001 diff --git a/packaging/android/res/drawable-ldpi/icon.png b/packaging/android/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bf47e160611c5fa2348a142611c99b6d8d7c17ac GIT binary patch literal 17652 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 literal 0 HcmV?d00001 diff --git a/packaging/android/res/drawable-mdpi/ic_stat_notificationicon.png b/packaging/android/res/drawable-mdpi/ic_stat_notificationicon.png new file mode 100644 index 0000000000000000000000000000000000000000..9501aea48280abb65a8fc7948ff6e638a1cf3f90 GIT binary patch literal 759 zcmV@i4BzxqS-!hOe+4J0s$s-ni2MN-2}@EH1~5 zIC}sV3wGg=h&a}c9|2H{=W7;W87{)3NU8=o?_gy_{L}>Z0=$R^>gE0T5?A7xI*UO- zc16U}(*Q~-i))(==qy}_^Kl$k;8x7TnH@+;*Q$uvkum=jE2U(Sw=lPrxB=T*AQO?T z-;7PQySH&IQV z^9xdvNo&q#CC0bz_e8`{1Mq3peDCZIVRfZra+PgU9RnMzEw6$~gM#TK4gY|e~j4jGN*^jCC zwMuniN6zMmSli1!5#i@2{3UAY&p zV@b<47Jh#= z#DJ>W8n_2=H{ia&ZtdT@!03#>0>1}-3S0~P1-LQEzt(-gwG61Ldjih`o(1d(JP_Ch zxJ}2!ZUz1fTn$_adb#LGh;6%XJUq|%9Nx+Aa=%tlpB?GGJPQZ(R zBZ1u)y!1+!0QAhyfDZy6O=8F`B}*GnRjxf3*c-SVaG#}4SZz@O7bJPXvfGw2psF4X zybss|I05)7@Co2S%O14ix}N~AO!D2neZ2-$)q{Zxfd>Hp0iFt61iV;x_Z=|scRg_p zuxFBAEz+^jfU0^F@C9IprsVIyhk-W%{{)T!UIpwl@S=U&t_Sv8k3Mx7&L0M*#b`bylm55Od;n zNlu$pwwVD9q`uPX{Oo!|=zt`@@Q0Qo&j#)Ve6uCqzuTsV0j~!h3*3GKtnkczll*2< z*E|DW3%t7nr2f?4|8x_psw|`OA9;}fzdP`c#(6~8I|3Rg@QL1I`7iK0z%^Dk*Y$~D z_m(8@=ro|JyvT0>5qF-9ssivbzIb$;es>(P$4>+(#!5K-8Zio8-RwId>uYG=_&Rr^QN+J^-U;ehhV*qKl zVo5$7kmYuXkN4ap;?V#5fvR$|Kl)OON~ytZW4Yb$@3@T*)GhIXesTJYm;2xFh|eZ&AHzO$x75GCnT{6 znlj*>z#IB@&iroDAD6_MK9Z^u)cjlYilbz%DodzU=kdT(8t+=>3TGy<^iCOIojzij z-4ko{gw*;V6MDi36IyRr_vgtd530)2=}U^%uD2>JBj+SJbk+bH7QtkQh`w*MK?kl& za%)v>)xyClHQVHy2d@TRzC^swyU)2vEZtKcI2AZ{$nD!6OXn|vGh4T2Qj5@{vejnt zb!|%xS&bYbo3LmT5?7VY$$N%qo7wY`W`xrUiI;Pru@U3*q}}FQZ%5d1pW~C9JnMmd zfiG@=0XF{95m~7@U>hon-FAXwdAOWvsF-tN(NqZ8i2QIt;w^iaJjK_wTN7Cg6GQ2e zhS=(nt~T~M>JU&jl2@{}Z_ez~eNz>@lA;H4|xUL6k7 z^uSdA-8C1|<(5OiZKy~q9D|IT7rQpmd9OA`Uq!FOWWnpE*-f1oX zAC}~n2@lBsC4I|^53xrQKTB;UeY4TW0iRt1HKp4o^H~$4c&FPEzGcMmiJ0<@uEo7C zTUAb;?LTc&hKN0^)cHGY^V=F4_v!NTzWiu@G}wTafQ~-w7xc&waUkYY+o6FU_QqqB zE?r{Ck>kdFZ3CJSavG`f0RwYFfRhjTZLLeJFrO1ImiIq&g-&gx3oc}iC@V6333Bxv#)ztr@FL!U8zk(Ar`x$3IfI^VZ>kO32hh^PlS z>T9f1!^Ds-y@rV8(D9<2%W(N*5~q2CWGw?G3=v`Nd*wS)5qk=W;dsg?_4T93&)W#m r585{Wc57?Nh8VEc4c6Se#T)QH7f=aL?vRF=00000NkvXXu0mjfafF;k literal 0 HcmV?d00001 diff --git a/packaging/android/res/drawable-xxhdpi/ic_stat_notificationicon.png b/packaging/android/res/drawable-xxhdpi/ic_stat_notificationicon.png new file mode 100644 index 0000000000000000000000000000000000000000..2b5d206913a3dd12f6d98010c800880e8b819089 GIT binary patch literal 2779 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 literal 0 HcmV?d00001 diff --git a/packaging/android/src/io/guh/nymeaapp/NymeaAppActivity.java b/packaging/android/src/io/guh/nymeaapp/NymeaAppActivity.java new file mode 100644 index 00000000..651b3bea --- /dev/null +++ b/packaging/android/src/io/guh/nymeaapp/NymeaAppActivity.java @@ -0,0 +1,44 @@ +package io.guh.nymeaapp; +import android.util.Log; +import android.content.Intent; +import android.os.Bundle; +import com.google.firebase.messaging.MessageForwardingService; + +public class NymeaAppActivity extends org.qtproject.qt5.android.bindings.QtActivity +{ + // The key in the intent's extras that maps to the incoming message's message ID. Only sent by + // the server, GmsCore sends EXTRA_MESSAGE_ID_KEY below. Server can't send that as it would get + // stripped by the client. + private static final String EXTRA_MESSAGE_ID_KEY_SERVER = "message_id"; + + // An alternate key value in the intent's extras that also maps to the incoming message's message + // ID. Used by upstream, and set by GmsCore. + private static final String EXTRA_MESSAGE_ID_KEY = "google.message_id"; + + // The key in the intent's extras that maps to the incoming message's sender value. + private static final String EXTRA_FROM = "google.message_id"; + + + @Override + protected void onNewIntent(Intent intent) + { + +// Bundle extras = intent.getExtras(); +// String from = extras.getString(EXTRA_FROM); +// String messageId = extras.getString(EXTRA_MESSAGE_ID_KEY); +// Log.d("*************** messageid", messageId); +//// Log.d("Bundle", extras); + +// if (messageId == null) { +// messageId = extras.getString(EXTRA_MESSAGE_ID_KEY_SERVER); +// } +// // if (from != null && messageId != null) { +// Intent message = new Intent(this, MessageForwardingService.class); +// message.setAction(MessageForwardingService.ACTION_REMOTE_INTENT); +// message.putExtras(intent); +// message.setData(intent.getData()); +// startService(message); +// // } + setIntent(intent); + } +} diff --git a/packaging/android/src/io/guh/nymeaapp/NymeaAppNotificationService.java b/packaging/android/src/io/guh/nymeaapp/NymeaAppNotificationService.java new file mode 100644 index 00000000..5b8d2da3 --- /dev/null +++ b/packaging/android/src/io/guh/nymeaapp/NymeaAppNotificationService.java @@ -0,0 +1,75 @@ +package io.guh.nymeaapp; + +import com.google.firebase.messaging.RemoteMessage; +import com.google.firebase.messaging.FirebaseMessagingService; + +import android.util.Log; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.net.Uri; +import android.content.Context; +import android.provider.Settings.System; +import android.os.Build; + +import android.support.v4.app.NotificationCompat; + +import java.util.Random; + +public class NymeaAppNotificationService extends FirebaseMessagingService { + + + /** + * Called when message is received. + * + * @param remoteMessage Object representing the message received from Firebase Cloud Messaging. + */ + // [START receive_message] + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + // If the application is in the foreground handle both data and notification messages here. + // Also if you intend on generating your own notifications as a result of a received FCM + // message, here is where that should be initiated. See sendNotification method below. + sendNotification(remoteMessage); + } + // [END receive_message] + + /** + * Create and show a simple notification containing the received FCM message. + * + * @param remoteMessage FCM RemoteMessage received. + */ + private void sendNotification(RemoteMessage remoteMessage) { + + Intent intent = new Intent(this, NymeaAppActivity.class); +// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); +// PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, 0); + + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "notify_001") + .setSmallIcon(R.drawable.ic_stat_notificationicon) + .setColor(0xFF57BAAE) + .setContentTitle(remoteMessage.getData().get("title")) + .setContentText(remoteMessage.getData().get("body")) + .setAutoCancel(true) + .setSound(android.provider.Settings.System.DEFAULT_RINGTONE_URI) + .setContentIntent(pendingIntent); + + NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel("notify_001", "Channel human readable title", NotificationManager.IMPORTANCE_HIGH); + notificationManager.createNotificationChannel(channel); + } + + + int notificationId = new Random().nextInt(60000); + + Log.d("Posting Notification", remoteMessage.getMessageId()); + notificationManager.notify(notificationId, notificationBuilder.build()); + + } + +} diff --git a/qtcloudmessaging b/qtcloudmessaging new file mode 160000 index 00000000..bf62d04b --- /dev/null +++ b/qtcloudmessaging @@ -0,0 +1 @@ +Subproject commit bf62d04b3d6aad292b7dab46d7c4567965450537