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
This commit is contained in:
Gioacchino Mazzurco 2017-04-07 18:26:08 +02:00
parent 70e91f7164
commit bcbd5230eb
24 changed files with 562 additions and 94 deletions

View file

@ -38,11 +38,22 @@ retroshare_android_service {
retroshare_android_service.target = 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 { retroshare_qml_app {
SUBDIRS += retroshare_qml_app SUBDIRS += retroshare_qml_app
retroshare_qml_app.file = retroshare-qml-app/src/retroshare-qml-app.pro retroshare_qml_app.file = retroshare-qml-app/src/retroshare-qml-app.pro
retroshare_qml_app.depends = libretroshare retroshare_android_service retroshare_qml_app.depends = libretroshare retroshare_android_service
retroshare_qml_app.target = retroshare_qml_app retroshare_qml_app.target = retroshare_qml_app
android-g++ {
retroshare_qml_app.depends += retroshare_android_notify_service
}
} }
retroshare_plugins { retroshare_plugins {

View file

@ -0,0 +1 @@
../../retroshare-qml-app/src/libresapilocalclient.cpp

View file

@ -0,0 +1 @@
../../retroshare-qml-app/src/libresapilocalclient.h

View file

@ -0,0 +1,73 @@
/*
* RetroShare Android Service
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QCoreApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QFileInfo>
#include <QDebug>
#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<LibresapiLocalClient>(
"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();
}

View file

@ -0,0 +1,151 @@
/*
* RetroShare Android Autologin Service
* Copyright (C) 2017 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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)
}
}
}

View file

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>notify.qml</file>
</qresource>
</RCC>

View file

@ -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

View file

@ -1,6 +1,6 @@
/* /*
* RetroShare Android Service * RetroShare Android Service
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> * Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -20,7 +20,6 @@
#include <QDebug> #include <QDebug>
#ifdef __ANDROID__ #ifdef __ANDROID__
# include <QtAndroidExtras>
# include "util/androiddebug.h" # include "util/androiddebug.h"
#endif #endif
@ -41,23 +40,23 @@ int main(int argc, char *argv[])
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
ApiServer api; ApiServer api;
RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true); RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true);
api.addResourceHandler("control", dynamic_cast<resource_api::ResourceRouter*>(&ctrl_mod), &resource_api::RsControlModule::handleRequest); api.addResourceHandler(
"control",
dynamic_cast<resource_api::ResourceRouter*>(&ctrl_mod),
&resource_api::RsControlModule::handleRequest);
QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory()); QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory());
sockPath.append("/libresapi.sock"); sockPath.append("/libresapi.sock");
qDebug() << "Listening on:" << sockPath; qDebug() << "Listening on:" << sockPath;
ApiServerLocal apiServerLocal(&api, sockPath); (void) apiServerLocal; 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()) while (!ctrl_mod.processShouldExit())
{ {
a.processEvents(); a.processEvents();
usleep(20000); usleep(20000);
} }
return 0; QCoreApplication::quit();
return a.exec();
} }

View file

@ -75,8 +75,9 @@
</receiver> </receiver>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices --> <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
<service android:process=":rs" android:name=".RetroShareAndroidService" android:label="RetroShare Service" android:exported="true"> <!-- Added to be able to run the service from adb shell --> <service android:process=":rs" android:name=".RetroShareAndroidService" android:label="RetroShare Service" android:exported="true">
<!-- android:process=":qt" is needed to force the service to run on a separate process than the Activity --> <!-- android:exported="true" Added to be able to run the service from adb shell -->
<!-- android:process=":rs" is needed to force the service to run on a separate process than the Activity -->
<!-- Application arguments --> <!-- Application arguments -->
@ -114,6 +115,52 @@
<!-- Messages maps --> <!-- Messages maps -->
<!-- Background running -->
<meta-data android:name="android.app.background_running" android:value="true"/>
<!-- Background running -->
</service>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
<service android:process=":nf" android:name=".RetroShareAndroidNotifyService" android:label="RetroShare Notify Service" android:exported="true">
<!-- android:exported="true" Added to be able to run the service from adb shell -->
<!-- android:process=":nf" is needed to force the service to run on a separate process than the Activity -->
<!-- Application arguments -->
<!-- meta-data android:name="android.app.arguments" android:value="-service"/ -->
<!-- Application arguments -->
<!-- If you are using the same application (.so file) for activity and also for service, then you
need to use *android.app.arguments* to pass some arguments to your service in order to know which
one is which.
-->
<!-- Application to launch -->
<meta-data android:name="android.app.lib_name" android:value="retroshare-android-notify-service"/>
<!-- Application to launch -->
<!-- Ministro -->
<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"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Background running --> <!-- Background running -->
<meta-data android:name="android.app.background_running" android:value="true"/> <meta-data android:name="android.app.background_running" android:value="true"/>
<!-- Background running --> <!-- Background running -->

View file

@ -16,34 +16,30 @@
<task>generateDebugSources</task> <task>generateDebugSources</task>
</afterSyncTasks> </afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/../../../../qt5/qtbase/src/android/java/res" /> <option name="RES_FOLDER_RELATIVE_PATH" value="/../../../../../../../opt/Qt5.8.0/5.8/android_armv7/src/android/java/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../../qt5/qtbase/src/android/java/res;file://$MODULE_DIR$/res" /> <option name="RES_FOLDERS_RELATIVE_PATH" value="file:///opt/Qt5.8.0/5.8/android_armv7/src/android/java/res;file://$MODULE_DIR$/res" />
</configuration> </configuration>
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false"> <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/.build/intermediates/classes/debug" /> <output url="file://$MODULE_DIR$/.build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/.build/intermediates/classes/test/debug" /> <output-test url="file://$MODULE_DIR$/.build/intermediates/classes/test/debug" />
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$/../../../../qt5/qtbase/src/android/java/res">
<sourceFolder url="file://$MODULE_DIR$/../../../../qt5/qtbase/src/android/java/res" type="java-resource" />
</content>
<content url="file://$MODULE_DIR$/../../../../qt5/qtbase/src/android/java/src">
<sourceFolder url="file://$MODULE_DIR$/../../../../qt5/qtbase/src/android/java/src" isTestSource="false" />
</content>
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/r/debug" isTestSource="false" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/aidl/debug" isTestSource="false" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/rs/debug" isTestSource="false" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/res/rs/debug" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/res/generated/debug" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/res/rs/androidTest/debug" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/.build/generated/res/generated/androidTest/debug" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/.build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
@ -51,6 +47,7 @@
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
@ -58,6 +55,7 @@
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/assets" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/assets" type="java-resource" />
@ -65,6 +63,7 @@
<sourceFolder url="file://$MODULE_DIR$/aidl" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@ -72,6 +71,7 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
@ -79,18 +79,22 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/assets" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/incremental" /> <excludeFolder url="file://$MODULE_DIR$/.build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/manifests" /> <excludeFolder url="file://$MODULE_DIR$/.build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/mockable-android-18.jar" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/res" /> <excludeFolder url="file://$MODULE_DIR$/.build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/rs" /> <excludeFolder url="file://$MODULE_DIR$/.build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/.build/intermediates/symbols" /> <excludeFolder url="file://$MODULE_DIR$/.build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/.build/outputs" /> <excludeFolder url="file://$MODULE_DIR$/.build/outputs" />
</content> </content>
<orderEntry type="jdk" jdkName="Android API 18 Platform" jdkType="Android SDK" /> <content url="file:///opt/Qt5.8.0/5.8/android_armv7/src/android/java/res">
<sourceFolder url="file:///opt/Qt5.8.0/5.8/android_armv7/src/android/java/res" type="java-resource" />
</content>
<content url="file:///opt/Qt5.8.0/5.8/android_armv7/src/android/java/src">
<sourceFolder url="file:///opt/Qt5.8.0/5.8/android_armv7/src/android/java/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" scope="TEST" name="mockable-android-18" level="project" />
</component> </component>
</module> </module>

View file

@ -4,7 +4,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:1.1.0' classpath 'com.android.tools.build:gradle:2.2.3'
} }
} }

View file

@ -1,6 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013 #Fri Apr 07 17:55:25 CEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

View file

@ -1,6 +1,6 @@
/* /*
* RetroShare Android Service * RetroShare Android Service
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> * Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -28,9 +28,16 @@ public class AppUpdatedReceiver extends BroadcastReceiver
@Override @Override
public void onReceive(Context context, Intent intent) public void onReceive(Context context, Intent intent)
{ {
Log.i("AppUpdatedReceiver", "onReceive() Stopping RetroShareAndroidNotifyService After Update");
Intent nsIntent = new Intent(context, RetroShareAndroidNotifyService.class);
context.stopService(nsIntent);
Log.i("AppUpdatedReceiver", "onReceive() Restarting RetroShare Android Service After Update"); Log.i("AppUpdatedReceiver", "onReceive() Restarting RetroShare Android Service After Update");
Intent myIntent = new Intent(context, RetroShareAndroidService.class); Intent coreIntent = new Intent(context, RetroShareAndroidService.class);
context.stopService(myIntent); context.stopService(coreIntent);
context.startService(myIntent); context.startService(coreIntent);
Log.i("AppUpdatedReceiver", "onReceive() Starting RetroShareAndroidNotifyService After Update");
context.startService(nsIntent);
} }
} }

View file

@ -1,6 +1,6 @@
/* /*
* RetroShare Android Service * RetroShare Android Service
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> * Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -21,13 +21,19 @@ package org.retroshare.android.qml_app;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log;
public class BootCompletedReceiver extends BroadcastReceiver public class BootCompletedReceiver extends BroadcastReceiver
{ {
@Override @Override
public void onReceive(Context context, Intent intent) public void onReceive(Context context, Intent intent)
{ {
Intent myIntent = new Intent(context, RetroShareAndroidService.class); Log.i("BootCompletedReceiver", "onReceive() Starting RetroShareAndroidService on boot");
context.startService(myIntent); Intent coreIntent = new Intent(context, RetroShareAndroidService.class);
context.startService(coreIntent);
Log.i("BootCompletedReceiver", "onReceive() Starting RetroShareAndroidNotifyService on boot");
Intent nsIntent = new Intent(context, RetroShareAndroidNotifyService.class);
context.startService(nsIntent);
} }
} }

View file

@ -0,0 +1,23 @@
/*
* RetroShare Android Service
* Copyright (C) 2017 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.retroshare.android.qml_app;
import org.qtproject.qt5.android.bindings.QtService;
public class RetroShareAndroidNotifyService extends QtService {}

View file

@ -1,6 +1,6 @@
/* /*
* RetroShare Android QML App * RetroShare Android QML App
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> * Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -39,6 +39,14 @@ public class RetroShareQmlActivity extends QtActivity
} }
else Log.v("RetroShareQmlActivity", "onCreate(): RetroShareAndroidService already running"); else Log.v("RetroShareQmlActivity", "onCreate(): RetroShareAndroidService already running");
if (!isMyServiceRunning(RetroShareAndroidNotifyService.class))
{
Log.i("RetroShareQmlActivity", "onCreate(): RetroShareAndroidNotifyService is not running, let's start it by Intent");
Intent rsIntent = new Intent(this, RetroShareAndroidNotifyService.class);
startService(rsIntent);
}
else Log.v("RetroShareQmlActivity", "onCreate(): RetroShareAndroidNotifyService already running");
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }

View file

@ -20,5 +20,6 @@
<file>qml/icons/application-menu.png</file> <file>qml/icons/application-menu.png</file>
<file>qml/ContactSort.js</file> <file>qml/ContactSort.js</file>
<file>qml/icons/emblem-locked.png</file> <file>qml/icons/emblem-locked.png</file>
<file>qml/BusyOverlay.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -0,0 +1,44 @@
/*
* RetroShare Android QML App
* Copyright (C) 2017 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
import QtQuick.Controls 2.0
Rectangle
{
id: busyOverlay
property string message
enabled: false
anchors.fill: parent
BusyIndicator
{
running: true
anchors.centerIn: parent
}
Button
{
text: busyOverlay.message
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
}
}

View file

@ -76,7 +76,14 @@ Item
contactsView.own_gxs_id = json.data[0].gxs_id contactsView.own_gxs_id = json.data[0].gxs_id
contactsView.own_nick = json.data[0].name contactsView.own_nick = json.data[0].name
} }
else createIdentityDialog.visible = true else
{
var jsonData = { "name": mainWindow.pgp_name, "pgp_linked": false }
rsApi.request(
"/identity/create_identity",
JSON.stringify(jsonData),
refreshOwn)
}
} }
function refreshOwn() function refreshOwn()
{ {
@ -170,29 +177,6 @@ Item
text: "Open Chat as: " + contactsView.own_nick + " " + contactsView.own_gxs_id text: "Open Chat as: " + contactsView.own_nick + " " + contactsView.own_gxs_id
} }
Dialog
{
id: createIdentityDialog
visible: false
title: "You need to create a GXS identity to chat!"
standardButtons: StandardButton.Save
onAccepted: rsApi.request("/identity/create_identity", JSON.stringify({"name":identityNameTE.text, "pgp_linked": !psdnmCheckBox.checked }))
TextField
{
id: identityNameTE
width: 300
}
Row
{
anchors.top: identityNameTE.bottom
Text { text: "Pseudonymous: " }
CheckBox { id: psdnmCheckBox; checked: true; enabled: false }
}
}
Popup Popup
{ {
id: fingerPrintDialog id: fingerPrintDialog

View file

@ -24,7 +24,6 @@ Item
{ {
id: locationView id: locationView
state: "selectLocation" state: "selectLocation"
property var qParent
property bool attemptLogin: false property bool attemptLogin: false
property string password property string password
property string sslid property string sslid
@ -42,19 +41,26 @@ Item
{ {
name: "createLocation" name: "createLocation"
PropertyChanges { target: locationsListView; visible: false } PropertyChanges { target: locationsListView; visible: false }
PropertyChanges { target: bottomButton; visible: false } PropertyChanges { target: bottomButton; visible: false }
PropertyChanges PropertyChanges
{ {
target: loginView target: loginView
visible: true visible: true
buttonText: "Save" buttonText: qsTr("Save")
iconUrl: "qrc:/qml/icons/edit-image-face-detect.png"
suggestionText: qsTr("Create your profile")
onSubmit: onSubmit:
{ {
busyIndicator.running = true
var jsonData = { pgp_name: login, ssl_name: login, var jsonData = { pgp_name: login, ssl_name: login,
pgp_password: password } pgp_password: password }
rsApi.request("/control/create_location/", rsApi.request(
JSON.stringify(jsonData)) "/control/create_location/",
JSON.stringify(jsonData))
mainWindow.pgp_name = login
locationView.state = "selectLocation" locationView.state = "selectLocation"
bottomButton.enabled = false
bottomButton.text = "Creating profile..."
} }
} }
}, },
@ -62,11 +68,12 @@ Item
{ {
name: "login" name: "login"
PropertyChanges { target: locationsListView; visible: false } PropertyChanges { target: locationsListView; visible: false }
PropertyChanges { target: bottomButton; visible: false } PropertyChanges { target: bottomButton; visible: false }
PropertyChanges PropertyChanges
{ {
target: loginView target: loginView
visible: true visible: true
advancedMode: true
onSubmit: onSubmit:
{ {
locationView.password = password locationView.password = password
@ -88,9 +95,15 @@ Item
// There is only one location so we can jump selecting location // There is only one location so we can jump selecting location
var location = jsonData[0] var location = jsonData[0]
loginView.login = location.name loginView.login = location.name
mainWindow.pgp_name = location.name
locationView.sslid = location.peer_id locationView.sslid = location.peer_id
locationView.state = "login" locationView.state = "login"
} }
else if (jsonData.length === 0)
{
// The user haven't created a location yet
locationView.state = "createLocation"
}
else else
{ {
// There is more then one location to choose from // There is more then one location to choose from
@ -123,6 +136,7 @@ Item
loginView.login = text loginView.login = text
locationView.sslid = model.id locationView.sslid = model.id
locationView.state = "login" locationView.state = "login"
mainWindow.pgp_name = model.name
} }
} }
visible: false visible: false

View file

@ -1,6 +1,6 @@
/* /*
* RetroShare Android QML App * RetroShare Android QML App
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> * Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -19,49 +19,75 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
//import QtQml 2.2
Item Item
{ {
id: loginView id: loginView
property string buttonText: "Unlock" property string buttonText: qsTr("Unlock")
property string iconUrl: "qrc:/qml/icons/emblem-locked.png"
property string login property string login
property string password property bool loginPreset: false
property bool advancedMode: false
property string hardcodedPassword: "hardcoded default password"
property string password: advancedMode ? "" : hardcodedPassword
property string suggestionText
signal submit(string login, string password) signal submit(string login, string password)
Component.onCompleted: loginPreset = login.length > 0
ColumnLayout ColumnLayout
{ {
id: inputView id: inputView
width: parent.width width: parent.width
anchors.centerIn: parent anchors.centerIn: parent
Text
{
text: loginView.suggestionText
visible: loginView.suggestionText.length > 0
font.bold: true
Layout.alignment: Qt.AlignHCenter
}
Image Image
{ {
source: "qrc:/qml/icons/emblem-locked.png" source: loginView.iconUrl
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
} }
Text Text
{ {
text: "Login" text: qsTr("Name")
visible: loginView.login.length === 0 visible: !loginView.loginPreset
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
anchors.bottom: nameField.top anchors.bottom: nameField.top
anchors.bottomMargin: 5 anchors.bottomMargin: 5
} }
TextField TextField
{ {
id: nameField; id: nameField
text: loginView.login text: loginView.login
visible: loginView.login.length === 0 visible: !loginView.loginPreset
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
ToolTip
{
text: qsTr("Choose a descriptive name, one<br/>" +
"that your friends can recognize.",
"The linebreak is to make the text fit better in " +
"tooltip")
visible: nameField.activeFocus
timeout: 5000
}
} }
Text Text
{ {
id: passLabel id: passLabel
visible: loginView.advancedMode || loginView.loginPreset
text: nameField.visible ? text: nameField.visible ?
"Passphrase" : "Enter passphrase for " + loginView.login qsTr("Password") :
qsTr("Enter password for %1").arg(loginView.login)
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
anchors.bottom: passwordField.top anchors.bottom: passwordField.top
anchors.bottomMargin: 5 anchors.bottomMargin: 5
@ -69,18 +95,40 @@ Item
TextField TextField
{ {
id: passwordField id: passwordField
visible: loginView.advancedMode || loginView.loginPreset
text: loginView.password text: loginView.password
width: passLabel.width
echoMode: TextInput.Password echoMode: TextInput.Password
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
ToolTip
{
visible: passwordField.activeFocus
timeout: 5000
text: qsTr("Choose a strong password and don't forget it,<br/>"+
"there is no way to recover lost password.",
"The linebreak is to make the text fit better in " +
"tooltip")
}
} }
Button Row
{ {
id: bottomButton
text: loginView.buttonText
onClicked: loginView.submit(nameField.text, passwordField.text)
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
spacing: 3
Button
{
text: qsTr("Advanced...")
visible: !loginView.loginPreset
onClicked: loginView.advancedMode = !loginView.advancedMode
}
Button
{
id: bottomButton
text: loginView.buttonText
onClicked: loginView.submit(nameField.text, passwordField.text)
}
} }
} }
} }

View file

@ -28,6 +28,8 @@ ApplicationWindow
width: 400 width: 400
height: 400 height: 400
property string pgp_name
property var tokens: ({}) property var tokens: ({})
function registerToken(token, callback) function registerToken(token, callback)
{ {
@ -131,6 +133,8 @@ ApplicationWindow
} }
state: "core_down" state: "core_down"
initialItem: BusyOverlay { message: qsTr("Connecting to core...") }
states: [ states: [
State State
{ {
@ -152,6 +156,21 @@ ApplicationWindow
} }
}, },
State State
{
name: "waiting_startup"
PropertyChanges { target: stackView; enabled: false }
StateChangeScript
{
script:
{
console.log("StateChangeScript waiting_startup")
stackView.clear()
stackView.push("qrc:/qml/BusyOverlay.qml",
{ message: "Core initializing..."})
}
}
},
State
{ {
name: "running_ok" name: "running_ok"
PropertyChanges { target: stackView; enabled: true } PropertyChanges { target: stackView; enabled: true }
@ -172,16 +191,6 @@ ApplicationWindow
PropertyChanges { target: stackView; state: "running_ok" } PropertyChanges { target: stackView; state: "running_ok" }
} }
] ]
initialItem: Rectangle
{
color: "green"
Text
{
text: "Connecting to core..."
anchors.centerIn: parent
}
}
} }
LibresapiLocalClient LibresapiLocalClient

View file

@ -1,6 +1,6 @@
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
QT += qml quick QT += core network qml quick
CONFIG += c++11 CONFIG += c++11

View file

@ -18,6 +18,12 @@ no_retroshare_plugins:CONFIG -= retroshare_plugins
CONFIG *= no_retroshare_android_service CONFIG *= no_retroshare_android_service
retroshare_android_service:CONFIG -= no_retroshare_android_service retroshare_android_service:CONFIG -= no_retroshare_android_service
# To enable RetroShare-android-notify-service append the following
# assignation to qmake command line
# "CONFIG+=retroshare_android_notify_service"
CONFIG *= no_retroshare_android_notify_service
retroshare_android_notify_service:CONFIG -= no_retroshare_android_notify_service
# To enable RetroShare-QML-app append the following assignation to # To enable RetroShare-QML-app append the following assignation to
# qmake command line "CONFIG+=retroshare_qml_app" # qmake command line "CONFIG+=retroshare_qml_app"
CONFIG *= no_retroshare_qml_app CONFIG *= no_retroshare_qml_app
@ -86,6 +92,10 @@ android-g++ {
isEmpty(NATIVE_LIBS_TOOLCHAIN_PATH) { isEmpty(NATIVE_LIBS_TOOLCHAIN_PATH) {
NATIVE_LIBS_TOOLCHAIN_PATH = $$(NATIVE_LIBS_TOOLCHAIN_PATH) NATIVE_LIBS_TOOLCHAIN_PATH = $$(NATIVE_LIBS_TOOLCHAIN_PATH)
} }
retroshare_qml_app {
CONFIG -= no_retroshare_android_notify_service
CONFIG *= retroshare_android_notify_service
}
CONFIG *= no_libresapihttpserver no_sqlcipher upnp_libupnp CONFIG *= no_libresapihttpserver no_sqlcipher upnp_libupnp
CONFIG -= libresapihttpserver sqlcipher upnp_miniupnpc CONFIG -= libresapihttpserver sqlcipher upnp_miniupnpc
QT *= androidextras QT *= androidextras