From bcbd5230eba047d77668e8d5535558df2608049f Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 7 Apr 2017 18:26:08 +0200 Subject: [PATCH] android notification service stub, improve login Added retroshare-android-notify-service a stub will handle notifications to android system, at the moment it only attempt autologin if default password is used retroshare-android-service quit QCoreApplication gracefully Android Studio update has changed some android build files Create BusyOverlay.qml componet so it is reusable accross the qml app Contacts.qml create a pseudonimous GXS identity as needed without prompting the user RsLoginPassView.qml nicer look, on mobile phone password usage is not common so do not use password by default QML app main view handle correctly +waiting_startup+ runstate QML app main view use BusyOverlay as initial item --- RetroShare.pro | 11 ++ .../src/libresapilocalclient.cpp | 1 + .../src/libresapilocalclient.h | 1 + .../src/notify.cpp | 73 +++++++++ .../src/notify.qml | 151 ++++++++++++++++++ retroshare-android-notify-service/src/qml.qrc | 5 + .../src/retroshare-android-notify-service.pro | 22 +++ retroshare-android-service/src/service.cpp | 17 +- .../src/android/AndroidManifest.xml | 51 +++++- retroshare-qml-app/src/android/android.iml | 36 +++-- retroshare-qml-app/src/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- .../android/qml_app/AppUpdatedReceiver.java | 15 +- .../qml_app/BootCompletedReceiver.java | 12 +- .../RetroShareAndroidNotifyService.java | 23 +++ .../qml_app/RetroShareQmlActivity.java | 10 +- retroshare-qml-app/src/qml.qrc | 1 + retroshare-qml-app/src/qml/BusyOverlay.qml | 44 +++++ retroshare-qml-app/src/qml/Contacts.qml | 32 +--- retroshare-qml-app/src/qml/Locations.qml | 26 ++- .../src/qml/RsLoginPassView.qml | 78 +++++++-- retroshare-qml-app/src/qml/main.qml | 29 ++-- retroshare-qml-app/src/retroshare-qml-app.pro | 2 +- retroshare.pri | 10 ++ 24 files changed, 562 insertions(+), 94 deletions(-) create mode 120000 retroshare-android-notify-service/src/libresapilocalclient.cpp create mode 120000 retroshare-android-notify-service/src/libresapilocalclient.h create mode 100644 retroshare-android-notify-service/src/notify.cpp create mode 100644 retroshare-android-notify-service/src/notify.qml create mode 100644 retroshare-android-notify-service/src/qml.qrc create mode 100644 retroshare-android-notify-service/src/retroshare-android-notify-service.pro create mode 100644 retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareAndroidNotifyService.java create mode 100644 retroshare-qml-app/src/qml/BusyOverlay.qml diff --git a/RetroShare.pro b/RetroShare.pro index 3d71f892c..043785f69 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -38,11 +38,22 @@ retroshare_android_service { retroshare_android_service.target = retroshare_android_service } +retroshare_android_notify_service { + SUBDIRS += retroshare_android_notify_service + retroshare_android_notify_service.file = retroshare-android-notify-service/src/retroshare-android-notify-service.pro + retroshare_android_notify_service.depends = libretroshare retroshare_android_service + retroshare_android_notify_service.target = retroshare_android_notify_service +} + retroshare_qml_app { SUBDIRS += retroshare_qml_app retroshare_qml_app.file = retroshare-qml-app/src/retroshare-qml-app.pro retroshare_qml_app.depends = libretroshare retroshare_android_service retroshare_qml_app.target = retroshare_qml_app + + android-g++ { + retroshare_qml_app.depends += retroshare_android_notify_service + } } retroshare_plugins { diff --git a/retroshare-android-notify-service/src/libresapilocalclient.cpp b/retroshare-android-notify-service/src/libresapilocalclient.cpp new file mode 120000 index 000000000..f273f917b --- /dev/null +++ b/retroshare-android-notify-service/src/libresapilocalclient.cpp @@ -0,0 +1 @@ +../../retroshare-qml-app/src/libresapilocalclient.cpp \ No newline at end of file diff --git a/retroshare-android-notify-service/src/libresapilocalclient.h b/retroshare-android-notify-service/src/libresapilocalclient.h new file mode 120000 index 000000000..8834d7e6b --- /dev/null +++ b/retroshare-android-notify-service/src/libresapilocalclient.h @@ -0,0 +1 @@ +../../retroshare-qml-app/src/libresapilocalclient.h \ No newline at end of file diff --git a/retroshare-android-notify-service/src/notify.cpp b/retroshare-android-notify-service/src/notify.cpp new file mode 100644 index 000000000..817960b59 --- /dev/null +++ b/retroshare-android-notify-service/src/notify.cpp @@ -0,0 +1,73 @@ +/* + * RetroShare Android Service + * Copyright (C) 2016 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#ifdef __ANDROID__ +# include "util/androiddebug.h" +#endif + +#include "libresapilocalclient.h" +#include "retroshare/rsinit.h" + + +int main(int argc, char *argv[]) +{ +#ifdef __ANDROID__ + AndroidStdIOCatcher dbg; (void) dbg; +#endif + + QCoreApplication app(argc, argv); + + QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory()); + sockPath.append("/libresapi.sock"); + + QQmlApplicationEngine engine; + qmlRegisterType( + "org.retroshare.qml_components.LibresapiLocalClient", 1, 0, + "LibresapiLocalClient"); + +#ifdef QT_DEBUG + engine.rootContext()->setContextProperty("QT_DEBUG", true); +#else + engine.rootContext()->setContextProperty("QT_DEBUG", false); +#endif // QT_DEBUG + + engine.rootContext()->setContextProperty("apiSocketPath", sockPath); + + LibresapiLocalClient rsApi; + + while (!QFileInfo::exists(sockPath)) + { + qDebug() << "RetroShareAndroidNotifyService waiting for core to" + << "listen on:" << sockPath; + + usleep(2500000); + } + + rsApi.openConnection(sockPath); + + engine.rootContext()->setContextProperty("rsApi", &rsApi); + engine.load(QUrl(QLatin1String("qrc:/notify.qml"))); + + return app.exec(); +} diff --git a/retroshare-android-notify-service/src/notify.qml b/retroshare-android-notify-service/src/notify.qml new file mode 100644 index 000000000..655287f3a --- /dev/null +++ b/retroshare-android-notify-service/src/notify.qml @@ -0,0 +1,151 @@ +/* + * RetroShare Android Autologin Service + * Copyright (C) 2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import QtQml 2.2 +import org.retroshare.qml_components.LibresapiLocalClient 1.0 + +QtObject +{ + id: mo + + property string profileName + property string profileSslId + property string hardcodedPassword: "hardcoded default password" + property int loginAttemptCount: 0 + property bool attemptingLogin: false + + property Timer runStateTimer: Timer + { + repeat: true + interval: 5000 + triggeredOnStart: true + Component.onCompleted: start() + onTriggered: + rsApi.request("/control/runstate/", "", mo.runStateCallback) + } + + function runStateCallback(par) + { + var jsonReponse = JSON.parse(par.response) + var runState = jsonReponse.data.runstate + if(typeof(runState) !== 'string') + { + console.log("runStateCallback(...) Core is hanged") + return + } + + switch(runState) + { + case "waiting_init": + console.log("Core is starting") + break + case "fatal_error": + console.log("Core hanged") + break + case "waiting_account_select": + if(!attemptingLogin && loginAttemptCount < 5) + rsApi.request("/control/locations/", "", requestLocationsListCB) + break + case "waiting_startup": + break + case "running_ok": + case "running_ok_no_full_control": + runStateTimer.interval = 30000 + break + } + } + + function requestLocationsListCB(par) + { + console.log("requestLocationsListCB") + var jsonData = JSON.parse(par.response).data + if(jsonData.length === 1) + { + // There is only one location so we can attempt autologin + var location = jsonData[0] + profileName = location.name + profileSslId = location.peer_id + if(!attemptingLogin && loginAttemptCount < 5) attemptLogin() + } + else if (jsonData.length === 0) + { + console.log("requestLocationsListCB 0") + // The user haven't created a location yet + // TODO: notify user to create a location + } + else + { + console.log("requestLocationsListCB *") + // There is more then one location to choose from + // TODO: notify user to login manually + } + } + + function attemptLogin() + { + console.log("attemptLogin") + attemptingLogin = true + ++loginAttemptCount + rsApi.request( + "/control/login/", JSON.stringify({ id: profileSslId }), + attemptLoginCB) + } + + function attemptLoginCB(par) + { + console.log("attemptLoginCB") + var jsonRet = JSON.parse(par.response).returncode + if (jsonRet === "ok") attemptPassTimer.start() + else console.log("Login hanged!") + } + + property Timer attemptPassTimer: Timer + { + interval: 700 + repeat: true + triggeredOnStart: true + onTriggered: rsApi.request("/control/password/", "", attemptPasswordCB) + + function attemptPasswordCB(par) + { + console.log("attemptPasswordCB", mo.attemptPassTimer, "running?", running) + if(JSON.parse(par.response).data.want_password) + { + console.log("attemptPasswordCB want_password") + rsApi.request( + "/control/password/", + JSON.stringify({ password: mo.hardcodedPassword }), + attemptPasswordCBCB) + } + } + + function attemptPasswordCBCB() + { + console.log("attemptPasswordCBCB") + stop() + + /* Wait 10 seconds so the core has time to process login and update + * runstate */ + var timeStart = new Date().getTime(); + while (new Date().getTime() - timeStart < 10000) {} + + mo.attemptingLogin = false + rsApi.request("/control/runstate/", "", mo.runStateCallback) + } + } +} diff --git a/retroshare-android-notify-service/src/qml.qrc b/retroshare-android-notify-service/src/qml.qrc new file mode 100644 index 000000000..4d56492f2 --- /dev/null +++ b/retroshare-android-notify-service/src/qml.qrc @@ -0,0 +1,5 @@ + + + notify.qml + + diff --git a/retroshare-android-notify-service/src/retroshare-android-notify-service.pro b/retroshare-android-notify-service/src/retroshare-android-notify-service.pro new file mode 100644 index 000000000..98bf4e24c --- /dev/null +++ b/retroshare-android-notify-service/src/retroshare-android-notify-service.pro @@ -0,0 +1,22 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + +TARGET = retroshare-android-notify-service + +QT += core network qml +QT -= gui + +CONFIG += c++11 +CONFIG += dll + +RESOURCES += qml.qrc + +android-g++:TEMPLATE = lib +!android-g++:TEMPLATE = app + +HEADERS += libresapilocalclient.h +SOURCES += libresapilocalclient.cpp notify.cpp + +DEPENDPATH *= ../../libretroshare/src +INCLUDEPATH *= ../../libretroshare/src +PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a +LIBS *= ../../libretroshare/src/lib/libretroshare.a diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index d3759dc61..d49c869d4 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -1,6 +1,6 @@ /* * RetroShare Android Service - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -20,7 +20,6 @@ #include #ifdef __ANDROID__ -# include # include "util/androiddebug.h" #endif @@ -41,23 +40,23 @@ int main(int argc, char *argv[]) QCoreApplication a(argc, argv); ApiServer api; RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true); - api.addResourceHandler("control", dynamic_cast(&ctrl_mod), &resource_api::RsControlModule::handleRequest); + api.addResourceHandler( + "control", + dynamic_cast(&ctrl_mod), + &resource_api::RsControlModule::handleRequest); QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory()); sockPath.append("/libresapi.sock"); qDebug() << "Listening on:" << sockPath; ApiServerLocal apiServerLocal(&api, sockPath); (void) apiServerLocal; -#ifdef __ANDROID__ - qDebug() << "Is service.cpp running as a service?" << QtAndroid::androidService().isValid(); - qDebug() << "Is service.cpp running as an activity?" << QtAndroid::androidActivity().isValid(); -#endif - while (!ctrl_mod.processShouldExit()) { a.processEvents(); usleep(20000); } - return 0; + QCoreApplication::quit(); + + return a.exec(); } diff --git a/retroshare-qml-app/src/android/AndroidManifest.xml b/retroshare-qml-app/src/android/AndroidManifest.xml index 64b2bca6a..b329c312b 100644 --- a/retroshare-qml-app/src/android/AndroidManifest.xml +++ b/retroshare-qml-app/src/android/AndroidManifest.xml @@ -75,8 +75,9 @@ - - + + + @@ -114,6 +115,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/retroshare-qml-app/src/android/android.iml b/retroshare-qml-app/src/android/android.iml index 4dde2c8b9..722af3989 100644 --- a/retroshare-qml-app/src/android/android.iml +++ b/retroshare-qml-app/src/android/android.iml @@ -16,34 +16,30 @@ generateDebugSources