diff --git a/retroshare-qml-app/src/NativeCalls.cpp b/retroshare-qml-app/src/NativeCalls.cpp new file mode 120000 index 000000000..390f61db0 --- /dev/null +++ b/retroshare-qml-app/src/NativeCalls.cpp @@ -0,0 +1 @@ +android/src/NativeCalls.cpp \ No newline at end of file diff --git a/retroshare-qml-app/src/NativeCalls.h b/retroshare-qml-app/src/NativeCalls.h new file mode 120000 index 000000000..4b86f482f --- /dev/null +++ b/retroshare-qml-app/src/NativeCalls.h @@ -0,0 +1 @@ +android/src/org_retroshare_android_qml_app_jni_NativeCalls.h \ No newline at end of file diff --git a/retroshare-qml-app/src/android/AndroidManifest.xml b/retroshare-qml-app/src/android/AndroidManifest.xml index 42c2e3f93..f58c9b6ac 100644 --- a/retroshare-qml-app/src/android/AndroidManifest.xml +++ b/retroshare-qml-app/src/android/AndroidManifest.xml @@ -10,16 +10,24 @@ android:label="RetroShare QML" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:screenOrientation="unspecified" - android:launchMode="singleTop"> + android:launchMode="singleTask"> - - - + + + + + + + + + + diff --git a/retroshare-qml-app/src/android/src/NativeCalls.cpp b/retroshare-qml-app/src/android/src/NativeCalls.cpp new file mode 100644 index 000000000..368a34794 --- /dev/null +++ b/retroshare-qml-app/src/android/src/NativeCalls.cpp @@ -0,0 +1,46 @@ +/* + * RetroShare Android QML App + * 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 . + */ + +#include "NativeCalls.h" +#include "singletonqmlengine.h" + +#include +#include +#include +#include +#include + +JNIEXPORT void JNICALL +Java_org_retroshare_android_qml_1app_jni_NativeCalls_notifyIntentUri +(JNIEnv* env, jclass, jstring uri) +{ + const char *uriBytes = env->GetStringUTFChars(uri, NULL); + QString uriStr(uriBytes); + env->ReleaseStringUTFChars(uri, uriBytes); + + QQmlApplicationEngine& engine(SingletonQmlEngine::instance()); + QObject* rootObj = engine.rootObjects()[0]; + QQuickWindow* mainWindow = qobject_cast(rootObj); + + if(mainWindow) + { + QMetaObject::invokeMethod(mainWindow, "handleIntentUri", + Q_ARG(QVariant, uriStr)); + } + else qCritical() << __PRETTY_FUNCTION__ << "Root object is not a window!"; +} diff --git a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java index 1e3351be7..59f142044 100644 --- a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java +++ b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java @@ -26,6 +26,8 @@ import android.util.Log; import org.qtproject.qt5.android.bindings.QtActivity; +import org.retroshare.android.qml_app.jni.NativeCalls; + public class RetroShareQmlActivity extends QtActivity { @Override @@ -50,6 +52,18 @@ public class RetroShareQmlActivity extends QtActivity super.onCreate(savedInstanceState); } + @Override + public void onNewIntent(Intent intent) + { + super.onNewIntent(intent); + String uri = intent.getDataString(); + if (uri != null) + { + Log.d("RetroShareQmlActivity", "onNewIntent() " + uri); + NativeCalls.notifyIntentUri(uri); + } + } + private boolean isMyServiceRunning(Class serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); diff --git a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.class b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.class new file mode 100644 index 000000000..debcf7718 Binary files /dev/null and b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.class differ diff --git a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.java b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.java new file mode 100644 index 000000000..6866b7bb3 --- /dev/null +++ b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/jni/NativeCalls.java @@ -0,0 +1,24 @@ +/* + * RetroShare Android 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 . + */ + +package org.retroshare.android.qml_app.jni; + +public class NativeCalls +{ + public static native void notifyIntentUri(String uri); +} diff --git a/retroshare-qml-app/src/android/src/org_retroshare_android_qml_app_jni_NativeCalls.h b/retroshare-qml-app/src/android/src/org_retroshare_android_qml_app_jni_NativeCalls.h new file mode 100644 index 000000000..035742bfb --- /dev/null +++ b/retroshare-qml-app/src/android/src/org_retroshare_android_qml_app_jni_NativeCalls.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_retroshare_android_qml_app_jni_NativeCalls */ + +#ifndef _Included_org_retroshare_android_qml_app_jni_NativeCalls +#define _Included_org_retroshare_android_qml_app_jni_NativeCalls +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_retroshare_android_qml_app_jni_NativeCalls + * Method: notifyIntentUri + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_retroshare_android_qml_1app_jni_NativeCalls_notifyIntentUri + (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/retroshare-qml-app/src/libresapilocalclient.h b/retroshare-qml-app/src/libresapilocalclient.h index d7689ed12..ecc0459aa 100644 --- a/retroshare-qml-app/src/libresapilocalclient.h +++ b/retroshare-qml-app/src/libresapilocalclient.h @@ -1,6 +1,7 @@ +#pragma once /* * libresapi local socket client - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * Copyright (C) 2016 Manu Pineda * * This program is free software: you can redistribute it and/or modify @@ -17,9 +18,6 @@ * along with this program. If not, see . */ -#ifndef LIBRESAPILOCALCLIENT_H -#define LIBRESAPILOCALCLIENT_H - #include #include #include @@ -95,5 +93,3 @@ signals: void debugChanged(); #endif // QT_DEBUG }; - -#endif // LIBRESAPILOCALCLIENT_H diff --git a/retroshare-qml-app/src/main.cpp b/retroshare-qml-app/src/main.cpp index 1a525c9a7..388869beb 100644 --- a/retroshare-qml-app/src/main.cpp +++ b/retroshare-qml-app/src/main.cpp @@ -22,23 +22,15 @@ #include #include -#ifdef __ANDROID__ -# include -#endif - -#include -#include - #include "libresapilocalclient.h" #include "retroshare/rsinit.h" +#include "singletonqmlengine.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); - QQmlApplicationEngine engine; - /** When possible it is better to use +rsApi+ object directly instead of * multiple instances of +LibresapiLocalClient+ in Qml */ qmlRegisterType( @@ -51,6 +43,8 @@ int main(int argc, char *argv[]) LibresapiLocalClient rsApi; rsApi.openConnection(sockPath); + QQmlApplicationEngine& engine(SingletonQmlEngine::instance()); + #ifdef QT_DEBUG engine.rootContext()->setContextProperty("QT_DEBUG", true); #else @@ -61,9 +55,5 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty("rsApi", &rsApi); engine.load(QUrl(QLatin1String("qrc:/qml/main.qml"))); - QFileInfo fileInfo(sockPath); - qDebug() << "QML APP:" << sockPath << fileInfo.exists() - << fileInfo.lastModified().toString(); - return app.exec(); } diff --git a/retroshare-qml-app/src/qml.qrc b/retroshare-qml-app/src/qml.qrc index a747d851d..dff5a5eb3 100644 --- a/retroshare-qml-app/src/qml.qrc +++ b/retroshare-qml-app/src/qml.qrc @@ -21,5 +21,6 @@ qml/ContactSort.js qml/icons/emblem-locked.png qml/BusyOverlay.qml + qml/URI.js diff --git a/retroshare-qml-app/src/qml/URI.js b/retroshare-qml-app/src/qml/URI.js new file mode 100644 index 000000000..c7388124a --- /dev/null +++ b/retroshare-qml-app/src/qml/URI.js @@ -0,0 +1,69 @@ +/*! URI.js v1.18.10 http://medialize.github.io/URI.js/ */ +/* build contains: URI.js */ +/* + URI.js - Mutating URLs + + Version: 1.18.10 + + Author: Rodney Rehm + Web: http://medialize.github.io/URI.js/ + + Licensed under + MIT License http://www.opensource.org/licenses/mit-license + +*/ +(function(m,w){"object"===typeof module&&module.exports?module.exports=w(require("./punycode"),require("./IPv6"),require("./SecondLevelDomains")):"function"===typeof define&&define.amd?define(["./punycode","./IPv6","./SecondLevelDomains"],w):m.URI=w(m.punycode,m.IPv6,m.SecondLevelDomains,m)})(this,function(m,w,u,h){function d(a,b){var c=1<=arguments.length,g=2<=arguments.length;if(!(this instanceof d))return c?g?new d(a,b):new d(a):new d;if(void 0===a){if(c)throw new TypeError("undefined is not a valid argument for URI"); +a="undefined"!==typeof location?location.href+"":""}if(null===a&&c)throw new TypeError("null is not a valid argument for URI");this.href(a);return void 0!==b?this.absoluteTo(b):this}function r(a){return a.replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function v(a){return void 0===a?"Undefined":String(Object.prototype.toString.call(a)).slice(8,-1)}function l(a){return"Array"===v(a)}function E(a,b){var c={},d,f;if("RegExp"===v(b))c=null;else if(l(b))for(d=0,f=b.length;d]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u2018\u2019]))/ig;d.findUri={start:/\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi,end:/[\s\r\n]|$/,trim:/[`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u201e\u2018\u2019]+$/,parens:/(\([^\)]*\)|\[[^\]]*\]|\{[^}]*\}|<[^>]*>)/g};d.defaultPorts={http:"80",https:"443",ftp:"21", +gopher:"70",ws:"80",wss:"443"};d.invalid_hostname_characters=/[^a-zA-Z0-9\.-]/;d.domAttributes={a:"href",blockquote:"cite",link:"href",base:"href",script:"src",form:"action",img:"src",area:"href",iframe:"src",embed:"src",source:"src",track:"src",input:"src",audio:"src",video:"src"};d.getDomAttribute=function(a){if(a&&a.nodeName){var b=a.nodeName.toLowerCase();if("input"!==b||"image"===a.type)return d.domAttributes[b]}};d.encode=C;d.decode=decodeURIComponent;d.iso8859=function(){d.encode=escape;d.decode= +unescape};d.unicode=function(){d.encode=C;d.decode=decodeURIComponent};d.characters={pathname:{encode:{expression:/%(24|26|2B|2C|3B|3D|3A|40)/ig,map:{"%24":"$","%26":"&","%2B":"+","%2C":",","%3B":";","%3D":"=","%3A":":","%40":"@"}},decode:{expression:/[\/\?#]/g,map:{"/":"%2F","?":"%3F","#":"%23"}}},reserved:{encode:{expression:/%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,map:{"%3A":":","%2F":"/","%3F":"?","%23":"#","%5B":"[","%5D":"]","%40":"@","%21":"!","%24":"$","%26":"&","%27":"'", +"%28":"(","%29":")","%2A":"*","%2B":"+","%2C":",","%3B":";","%3D":"="}}},urnpath:{encode:{expression:/%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig,map:{"%21":"!","%24":"$","%27":"'","%28":"(","%29":")","%2A":"*","%2B":"+","%2C":",","%3B":";","%3D":"=","%40":"@"}},decode:{expression:/[\/\?#:]/g,map:{"/":"%2F","?":"%3F","#":"%23",":":"%3A"}}}};d.encodeQuery=function(a,b){var c=d.encode(a+"");void 0===b&&(b=d.escapeQuerySpace);return b?c.replace(/%20/g,"+"):c};d.decodeQuery=function(a,b){a+="";void 0===b&& +(b=d.escapeQuerySpace);try{return d.decode(b?a.replace(/\+/g,"%20"):a)}catch(c){return a}};var t={encode:"encode",decode:"decode"},y,D=function(a,b){return function(c){try{return d[b](c+"").replace(d.characters[a][b].expression,function(c){return d.characters[a][b].map[c]})}catch(g){return c}}};for(y in t)d[y+"PathSegment"]=D("pathname",t[y]),d[y+"UrnPathSegment"]=D("urnpath",t[y]);t=function(a,b,c){return function(g){var f;f=c?function(a){return d[b](d[c](a))}:d[b];g=(g+"").split(a);for(var e=0, +k=g.length;ed)return a.charAt(0)===b.charAt(0)&&"/"===a.charAt(0)?"/":"";if("/"!==a.charAt(d)||"/"!==b.charAt(d))d=a.substring(0,d).lastIndexOf("/");return a.substring(0,d+1)};d.withinString=function(a,b,c){c||(c={}); +var g=c.start||d.findUri.start,e=c.end||d.findUri.end,z=c.trim||d.findUri.trim,k=c.parens||d.findUri.parens,l=/[a-z0-9-]=["']?$/i;for(g.lastIndex=0;;){var h=g.exec(a);if(!h)break;var m=h.index;if(c.ignoreHtml){var p=a.slice(Math.max(m-3,0),m);if(p&&l.test(p))continue}for(var q=m+a.slice(m).search(e),p=a.slice(m,q),q=-1;;){var n=k.exec(p);if(!n)break;q=Math.max(q,n.index+n[0].length)}p=-1c.length)return this._parts.hostname;c=this._parts.hostname.length-this.tld(b).length-1;c=this._parts.hostname.lastIndexOf(".",c-1)+1;return this._parts.hostname.substring(c)||""}if(!a)throw new TypeError("cannot set domain empty");d.ensureValidHostname(a); +!this._parts.hostname||this.is("IP")?this._parts.hostname=a:(c=new RegExp(r(this.domain())+"$"),this._parts.hostname=this._parts.hostname.replace(c,a));this.build(!b);return this};e.tld=function(a,b){if(this._parts.urn)return void 0===a?"":this;"boolean"===typeof a&&(b=a,a=void 0);if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.lastIndexOf("."),c=this._parts.hostname.substring(c+1);return!0!==b&&u&&u.list[c.toLowerCase()]?u.get(this._parts.hostname)||c:c}if(a)if(a.match(/[^a-zA-Z0-9-]/))if(u&& +u.is(a))c=new RegExp(r(this.tld())+"$"),this._parts.hostname=this._parts.hostname.replace(c,a);else throw new TypeError('TLD "'+a+'" contains characters other than [A-Z0-9]');else{if(!this._parts.hostname||this.is("IP"))throw new ReferenceError("cannot set TLD on non-domain host");c=new RegExp(r(this.tld())+"$");this._parts.hostname=this._parts.hostname.replace(c,a)}else throw new TypeError("cannot set TLD empty");this.build(!b);return this};e.directory=function(a,b){if(this._parts.urn)return void 0=== +a?"":this;if(void 0===a||!0===a){if(!this._parts.path&&!this._parts.hostname)return"";if("/"===this._parts.path)return"/";var c=this._parts.path.length-this.filename().length-1,c=this._parts.path.substring(0,c)||(this._parts.hostname?"/":"");return a?d.decodePath(c):c}c=this._parts.path.length-this.filename().length;c=this._parts.path.substring(0,c);c=new RegExp("^"+r(c));this.is("relative")||(a||(a="/"),"/"!==a.charAt(0)&&(a="/"+a));a&&"/"!==a.charAt(a.length-1)&&(a+="/");a=d.recodePath(a);this._parts.path= +this._parts.path.replace(c,a);this.build(!b);return this};e.filename=function(a,b){if(this._parts.urn)return void 0===a?"":this;if("string"!==typeof a){if(!this._parts.path||"/"===this._parts.path)return"";var c=this._parts.path.lastIndexOf("/"),c=this._parts.path.substring(c+1);return a?d.decodePathSegment(c):c}c=!1;"/"===a.charAt(0)&&(a=a.substring(1));a.match(/\.?\//)&&(c=!0);var g=new RegExp(r(this.filename())+"$");a=d.recodePath(a);this._parts.path=this._parts.path.replace(g,a);c?this.normalizePath(b): +this.build(!b);return this};e.suffix=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";var c=this.filename(),g=c.lastIndexOf(".");if(-1===g)return"";c=c.substring(g+1);c=/^[a-z0-9%]+$/i.test(c)?c:"";return a?d.decodePathSegment(c):c}"."===a.charAt(0)&&(a=a.substring(1));if(c=this.suffix())g=a?new RegExp(r(c)+"$"):new RegExp(r("."+c)+"$");else{if(!a)return this;this._parts.path+="."+d.recodePath(a)}g&&(a=d.recodePath(a), +this._parts.path=this._parts.path.replace(g,a));this.build(!b);return this};e.segment=function(a,b,c){var d=this._parts.urn?":":"/",e=this.path(),h="/"===e.substring(0,1),e=e.split(d);void 0!==a&&"number"!==typeof a&&(c=b,b=a,a=void 0);if(void 0!==a&&"number"!==typeof a)throw Error('Bad segment "'+a+'", must be 0-based integer');h&&e.shift();0>a&&(a=Math.max(e.length+a,0));if(void 0===b)return void 0===a?e:e[a];if(null===a||void 0===e[a])if(l(b)){e=[];a=0;for(var k=b.length;a + * + * 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 + +struct SingletonQmlEngine +{ + static QQmlApplicationEngine& instance() + { + static QQmlApplicationEngine engine; + return engine; + } + +private: + SingletonQmlEngine(); +};