summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2018-10-08 18:22:12 +0200
committerDominik Holland <dominik.holland@pelagicore.com>2018-10-12 09:44:35 +0000
commita54b61a7b17c0dc94441dba10243f364a57bcbb6 (patch)
tree6d6e649faa4542456e54266f9aea7cf5dc28be8d
parent8ced28c4c8d96be151fbb646d9bf08265f29249b (diff)
Add support for Intents for both single- and multi-process mode
This commit adds support for Intents, aka. a loosely coupled IPC between arbitrary applications in the AM system. (please read https://wiki.qt.io/QtAppMan-Intents for same background information). The core implementation on both server and client side in this patch is not dependent on the AM itself (apart from the common-lib for convenience sake, but this dependency could easily be removed). There are 2 interfaces that are implemented in the manager-lib and launcher-lib that connect the Intent core to the actual AM and AM's qml runtime launcher. Missing features: - updating the list of intents on app installation and removal - support for background services in the AM itself - support for "file-handles" in the request and reply part - documentation - an example that is better focused on intents themselves Change-Id: Ia7cab2bb569fb2cdb8e5ab7e8167e477cff3068c Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com>
-rw-r--r--examples/applicationmanager/applicationmanager.pro1
-rw-r--r--examples/applicationmanager/hello-world/apps/hello-world.red/info.yaml1
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.blue/icon.pngbin0 -> 1133 bytes
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.blue/info.yaml15
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.blue/main.qml70
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.green/icon.pngbin0 -> 1105 bytes
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.green/info.yaml13
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.green/main.qml63
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.red/icon.pngbin0 -> 1027 bytes
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.red/info.yaml14
-rw-r--r--examples/applicationmanager/intents/apps/hello-world.red/main.qml75
-rw-r--r--examples/applicationmanager/intents/intents.pro26
-rw-r--r--examples/applicationmanager/intents/system-ui.qml93
-rw-r--r--src/application-lib/applicationinfo.cpp5
-rw-r--r--src/application-lib/applicationinfo.h2
-rw-r--r--src/application-lib/applicationinterface.h1
-rw-r--r--src/application-lib/yamlapplicationscanner.cpp2
-rw-r--r--src/common-lib/error.h2
-rw-r--r--src/common-lib/logging.cpp4
-rw-r--r--src/common-lib/logging.h1
-rw-r--r--src/dbus-lib/dbus-lib.pro1
-rw-r--r--src/dbus-lib/io.qt.applicationmanager.intentinterface.xml31
-rw-r--r--src/intent-client-lib/intent-client-lib.pro25
-rw-r--r--src/intent-client-lib/intentclient.cpp217
-rw-r--r--src/intent-client-lib/intentclient.h97
-rw-r--r--src/intent-client-lib/intentclientrequest.cpp189
-rw-r--r--src/intent-client-lib/intentclientrequest.h120
-rw-r--r--src/intent-client-lib/intentclientsysteminterface.cpp59
-rw-r--r--src/intent-client-lib/intentclientsysteminterface.h79
-rw-r--r--src/intent-client-lib/intenthandler.cpp89
-rw-r--r--src/intent-client-lib/intenthandler.h88
-rw-r--r--src/intent-server-lib/intent-server-lib.pro25
-rw-r--r--src/intent-server-lib/intent.cpp133
-rw-r--r--src/intent-server-lib/intent.h86
-rw-r--r--src/intent-server-lib/intentserver.cpp417
-rw-r--r--src/intent-server-lib/intentserver.h138
-rw-r--r--src/intent-server-lib/intentserverrequest.cpp121
-rw-r--r--src/intent-server-lib/intentserverrequest.h104
-rw-r--r--src/intent-server-lib/intentserversysteminterface.cpp68
-rw-r--r--src/intent-server-lib/intentserversysteminterface.h89
-rw-r--r--src/launcher-lib/intentclientdbusimplementation.cpp105
-rw-r--r--src/launcher-lib/intentclientdbusimplementation.h65
-rw-r--r--src/launcher-lib/launcher-lib.pro5
-rw-r--r--src/launcher-lib/qmlapplicationinterface.cpp22
-rw-r--r--src/launcher-lib/qmlapplicationinterface.h3
-rw-r--r--src/launchers/qml/main.cpp3
-rw-r--r--src/main-lib/main-lib.pro1
-rw-r--r--src/main-lib/main.cpp73
-rw-r--r--src/main-lib/main.h3
-rw-r--r--src/manager-lib/intentaminterface.cpp438
-rw-r--r--src/manager-lib/intentaminterface.h187
-rw-r--r--src/manager-lib/manager-lib.pro31
-rw-r--r--src/manager-lib/qmlinprocessapplicationinterface.cpp16
-rw-r--r--src/manager-lib/qmlinprocessapplicationinterface.h3
-rw-r--r--src/src.pro12
-rw-r--r--sync.profile2
56 files changed, 3518 insertions, 15 deletions
diff --git a/examples/applicationmanager/applicationmanager.pro b/examples/applicationmanager/applicationmanager.pro
index 4f173f0d..6b7b8034 100644
--- a/examples/applicationmanager/applicationmanager.pro
+++ b/examples/applicationmanager/applicationmanager.pro
@@ -7,6 +7,7 @@ SUBDIRS = \
monitor \
multi-views \
startup-plugin \
+ intents \
# remove the !headless and handle this in the example when we switch to the new configure system
!headless:SUBDIRS += \
diff --git a/examples/applicationmanager/hello-world/apps/hello-world.red/info.yaml b/examples/applicationmanager/hello-world/apps/hello-world.red/info.yaml
index fe0be9af..d6696c56 100644
--- a/examples/applicationmanager/hello-world/apps/hello-world.red/info.yaml
+++ b/examples/applicationmanager/hello-world/apps/hello-world.red/info.yaml
@@ -7,3 +7,4 @@ code: 'main.qml'
runtime: 'qml'
name:
en: 'Hello Red'
+capabilities: [ "foo" ]
diff --git a/examples/applicationmanager/intents/apps/hello-world.blue/icon.png b/examples/applicationmanager/intents/apps/hello-world.blue/icon.png
new file mode 100644
index 00000000..be6ffc57
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.blue/icon.png
Binary files differ
diff --git a/examples/applicationmanager/intents/apps/hello-world.blue/info.yaml b/examples/applicationmanager/intents/apps/hello-world.blue/info.yaml
new file mode 100644
index 00000000..876f2ed9
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.blue/info.yaml
@@ -0,0 +1,15 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'hello-world.blue'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'Hello Blue'
+
+intents:
+- id: io.qt.blue
+ requiredCapabilities: [ "foo" ]
+- id: io.qt.blue.private
+ visibility: private
diff --git a/examples/applicationmanager/intents/apps/hello-world.blue/main.qml b/examples/applicationmanager/intents/apps/hello-world.blue/main.qml
new file mode 100644
index 00000000..81ea5b22
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.blue/main.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ color: "blue"
+
+ Text {
+ anchors.centerIn: parent
+ text: "Hello World!"
+ }
+
+ IntentHandler {
+ intentIds: [ "io.qt.blue" ]
+ onReceivedRequest: {
+ request.sendReply({ "this": "is a result", "nested": { "a": 1, "b": 2 } })
+ }
+ }
+}
diff --git a/examples/applicationmanager/intents/apps/hello-world.green/icon.png b/examples/applicationmanager/intents/apps/hello-world.green/icon.png
new file mode 100644
index 00000000..b149340c
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.green/icon.png
Binary files differ
diff --git a/examples/applicationmanager/intents/apps/hello-world.green/info.yaml b/examples/applicationmanager/intents/apps/hello-world.green/info.yaml
new file mode 100644
index 00000000..4455d4b5
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.green/info.yaml
@@ -0,0 +1,13 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'hello-world.green'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'Hello Green'
+
+intents:
+ - id: io.qt.green
+ parameterMatch: { "url": "^image/.*$" }
diff --git a/examples/applicationmanager/intents/apps/hello-world.green/main.qml b/examples/applicationmanager/intents/apps/hello-world.green/main.qml
new file mode 100644
index 00000000..2c0dea9e
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.green/main.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ color: "Green"
+
+ Text {
+ anchors.centerIn: parent
+ text: "Hello World!"
+ }
+}
diff --git a/examples/applicationmanager/intents/apps/hello-world.red/icon.png b/examples/applicationmanager/intents/apps/hello-world.red/icon.png
new file mode 100644
index 00000000..04ca44dd
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.red/icon.png
Binary files differ
diff --git a/examples/applicationmanager/intents/apps/hello-world.red/info.yaml b/examples/applicationmanager/intents/apps/hello-world.red/info.yaml
new file mode 100644
index 00000000..2663f608
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.red/info.yaml
@@ -0,0 +1,14 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'hello-world.red'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'Hello Red'
+
+capabilities: 'foo'
+
+intents:
+- id: io.qt.red
diff --git a/examples/applicationmanager/intents/apps/hello-world.red/main.qml b/examples/applicationmanager/intents/apps/hello-world.red/main.qml
new file mode 100644
index 00000000..b1cce59b
--- /dev/null
+++ b/examples/applicationmanager/intents/apps/hello-world.red/main.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ color: "red"
+
+ Text {
+ anchors.fill: parent
+ text: "Hello World!"
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ var request = ApplicationInterface.createIntentRequest("io.qt.blue", { "hello": "world", "number": 42 })
+ request.onFinished.connect(function() {
+ console.warn("Request finished " + request.requestId
+ + (request.succeeded ? (" Result: " + JSON.stringify(request.result))
+ : (" Error: " + request.errorString)))
+ })
+ }
+ }
+ }
+}
diff --git a/examples/applicationmanager/intents/intents.pro b/examples/applicationmanager/intents/intents.pro
new file mode 100644
index 00000000..d519e1a0
--- /dev/null
+++ b/examples/applicationmanager/intents/intents.pro
@@ -0,0 +1,26 @@
+TEMPLATE = app
+CONFIG += am-systemui
+
+OTHER_FILES += \
+ *.qml \
+ apps/hello-world.blue/*.yaml \
+ apps/hello-world.blue/*.qml \
+ apps/hello-world.blue/*.png \
+ apps/hello-world.green/*.yaml \
+ apps/hello-world.green/*.qml \
+ apps/hello-world.green/*.png \
+ apps/hello-world.red/*.yaml \
+ apps/hello-world.red/*.qml \
+ apps/hello-world.red/*.png \
+
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/intents
+INSTALLS += target
+
+AM_COPY_DIRECTORIES += apps
+AM_COPY_FILES += system-ui.qml
+
+AM_DEFAULT_ARGS=--builtin-apps-manifest-dir $$target.path/apps $$target.path/system-ui.qml
+
+example_sources.path = $$target.path
+example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
+INSTALLS += example_sources
diff --git a/examples/applicationmanager/intents/system-ui.qml b/examples/applicationmanager/intents/system-ui.qml
new file mode 100644
index 00000000..9bca06a3
--- /dev/null
+++ b/examples/applicationmanager/intents/system-ui.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+Item {
+ width: 800
+ height: 600
+
+ // Show application names and icons
+ Column {
+ spacing: 20
+ Repeater {
+ model: ApplicationManager
+ Column {
+ Image {
+ source: model.icon
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.isRunning ? application.stop() : application.start()
+ }
+ }
+ Text {
+ font.pixelSize: 20
+ text: model.name
+ }
+ }
+ }
+ }
+
+ // Show windows
+ Column {
+ anchors.right: parent.right
+ Repeater {
+ model: WindowManager
+ WindowItem {
+ width: 600
+ height: 200
+ window: model.window
+ }
+ }
+ }
+}
diff --git a/src/application-lib/applicationinfo.cpp b/src/application-lib/applicationinfo.cpp
index 1ef41d79..90897c6d 100644
--- a/src/application-lib/applicationinfo.cpp
+++ b/src/application-lib/applicationinfo.cpp
@@ -330,6 +330,11 @@ QVariantMap ApplicationInfo::openGLConfiguration() const
return m_openGLConfiguration;
}
+QVariantList ApplicationInfo::intents() const
+{
+ return m_intents;
+}
+
void ApplicationInfo::setBuiltIn(bool builtIn)
{
m_builtIn = builtIn;
diff --git a/src/application-lib/applicationinfo.h b/src/application-lib/applicationinfo.h
index f4980c71..6f70f73c 100644
--- a/src/application-lib/applicationinfo.h
+++ b/src/application-lib/applicationinfo.h
@@ -125,6 +125,7 @@ public:
QStringList categories() const;
QString version() const;
QVariantMap openGLConfiguration() const;
+ QVariantList intents() const;
bool supportsApplicationInterface() const;
void setSupportsApplicationInterface(bool supportsAppInterface);
@@ -157,6 +158,7 @@ private:
QString m_version;
QVariantMap m_openGLConfiguration;
+ QVariantList m_intents;
// added by installer
QScopedPointer<InstallationReport> m_installationReport;
diff --git a/src/application-lib/applicationinterface.h b/src/application-lib/applicationinterface.h
index 0445a51a..8230a0a4 100644
--- a/src/application-lib/applicationinterface.h
+++ b/src/application-lib/applicationinterface.h
@@ -69,6 +69,7 @@ public:
#ifdef Q_QDOC
Q_INVOKABLE Notification *createNotification();
+ Q_INVOKABLE IntentRequest *createIntentRequest();
Q_INVOKABLE virtual void acknowledgeQuit() const;
#endif
Q_SCRIPTABLE virtual void finishedInitialization() = 0;
diff --git a/src/application-lib/yamlapplicationscanner.cpp b/src/application-lib/yamlapplicationscanner.cpp
index 3d0a3ae9..68e004e1 100644
--- a/src/application-lib/yamlapplicationscanner.cpp
+++ b/src/application-lib/yamlapplicationscanner.cpp
@@ -184,6 +184,8 @@ AbstractApplicationInfo *YamlApplicationScanner::scanInternal(const QString &fil
if (!validKeys.contains(it.key()))
throw Exception(Error::Parse, "the 'opengl' object contains the unsupported key '%1'").arg(it.key());
}
+ } else if (field == "intents") {
+ appInfo->m_intents = v.toList();
} else {
unknownField = true;
}
diff --git a/src/common-lib/error.h b/src/common-lib/error.h
index 3018f195..e6130b61 100644
--- a/src/common-lib/error.h
+++ b/src/common-lib/error.h
@@ -69,6 +69,8 @@ enum class Error {
MediumNotAvailable = 50,
WrongMedium = 51,
+
+ Intents = 60
};
QT_END_NAMESPACE_AM
diff --git a/src/common-lib/logging.cpp b/src/common-lib/logging.cpp
index 6788f170..dd8207f6 100644
--- a/src/common-lib/logging.cpp
+++ b/src/common-lib/logging.cpp
@@ -83,6 +83,7 @@ QT_BEGIN_NAMESPACE_AM
\li \c am.qml.ipc - QML IPC
\li \c am.notify - Notification sub-system
\li \c am.deployment - Deployment hints
+\li \c am.intent - Intent sub-system
\li \c general - General messages not part of any ApplicationManager sub-system
\endlist
//! [am-logging-categories]
@@ -96,8 +97,9 @@ QDLT_LOGGING_CATEGORY(LogWaylandDebug, "am.wayland.debug", "WAYL", "Wayland prot
QDLT_LOGGING_CATEGORY(LogQml, "am.qml", "QML", "QML messages")
QDLT_LOGGING_CATEGORY(LogQmlRuntime, "am.runtime.qml", "QMRT", "QML runtime")
QDLT_LOGGING_CATEGORY(LogQmlIpc, "am.qml.ipc", "QMIP", "QML IPC")
-QDLT_LOGGING_CATEGORY(LogNotifications, "am.notify", "NTFY", "Notification sub-system")
+QDLT_LOGGING_CATEGORY(LogNotifications, "am.notify", "NTFY", "Notifications sub-system")
QDLT_LOGGING_CATEGORY(LogDeployment, "am.deployment", "DPLM", "Deployment hints")
+QDLT_LOGGING_CATEGORY(LogIntents, "am.intent", "INTN", "Intents sub-system")
QDLT_LOGGING_CATEGORY(LogGeneral, "general", "GEN", "General messages not part of any ApplicationManager sub-system")
QDLT_FALLBACK_CATEGORY(LogGeneral)
diff --git a/src/common-lib/logging.h b/src/common-lib/logging.h
index 2acbb100..d0a0fc3f 100644
--- a/src/common-lib/logging.h
+++ b/src/common-lib/logging.h
@@ -55,6 +55,7 @@ Q_DECLARE_LOGGING_CATEGORY(LogNotifications)
Q_DECLARE_LOGGING_CATEGORY(LogQmlRuntime)
Q_DECLARE_LOGGING_CATEGORY(LogQmlIpc)
Q_DECLARE_LOGGING_CATEGORY(LogDeployment)
+Q_DECLARE_LOGGING_CATEGORY(LogIntents)
class Logging
{
diff --git a/src/dbus-lib/dbus-lib.pro b/src/dbus-lib/dbus-lib.pro
index 90cb1eda..cc39bf5b 100644
--- a/src/dbus-lib/dbus-lib.pro
+++ b/src/dbus-lib/dbus-lib.pro
@@ -48,6 +48,7 @@ OTHER_FILES = \
io.qt.applicationinstaller.xml \
io.qt.applicationmanager.applicationinterface.xml \
io.qt.applicationmanager.runtimeinterface.xml \
+ io.qt.applicationmanager.intentinterface.xml \
io.qt.applicationmanager.xml \
io.qt.windowmanager.xml \
org.freedesktop.notifications.xml \
diff --git a/src/dbus-lib/io.qt.applicationmanager.intentinterface.xml b/src/dbus-lib/io.qt.applicationmanager.intentinterface.xml
new file mode 100644
index 00000000..8b452eb0
--- /dev/null
+++ b/src/dbus-lib/io.qt.applicationmanager.intentinterface.xml
@@ -0,0 +1,31 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="io.qt.ApplicationManager.IntentInterface">
+ <method name="requestToSystem">
+ <arg type="s" direction="out"/>
+ <arg name="id" type="s" direction="in"/>
+ <arg name="applicationId" type="s" direction="in"/>
+ <arg name="parameters" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/>
+ </method>
+ <signal name="replyFromSystem">
+ <arg name="requestId" type="s" direction="out"/>
+ <arg name="error" type="b" direction="out"/>
+ <arg name="result" type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="QVariantMap"/>
+ </signal>
+ <signal name="requestToApplication">
+ <arg name="requestId" type="s" direction="out"/>
+ <arg name="id" type="s" direction="out"/>
+ <arg name="applicationId" type="s" direction="out"/>
+ <arg name="parameters" type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="QVariantMap"/>
+ </signal>
+ <method name="replyFromApplication">
+ <arg name="requestId" type="s" direction="in"/>
+ <arg name="error" type="b" direction="in"/>
+ <arg name="result" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMap"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/intent-client-lib/intent-client-lib.pro b/src/intent-client-lib/intent-client-lib.pro
new file mode 100644
index 00000000..e1dcabb4
--- /dev/null
+++ b/src/intent-client-lib/intent-client-lib.pro
@@ -0,0 +1,25 @@
+TEMPLATE = lib
+TARGET = QtAppManIntentClient
+MODULE = appman_intent_client
+
+load(am-config)
+
+QT = core network qml
+QT_FOR_PRIVATE *= \
+ appman_common-private \
+
+CONFIG *= static internal_module
+
+HEADERS += \
+ intenthandler.h \
+ intentclient.h \
+ intentclientrequest.h \
+ intentclientsysteminterface.h
+
+SOURCES += \
+ intenthandler.cpp \
+ intentclient.cpp \
+ intentclientrequest.cpp \
+ intentclientsysteminterface.cpp
+
+load(qt_module)
diff --git a/src/intent-client-lib/intentclient.cpp b/src/intent-client-lib/intentclient.cpp
new file mode 100644
index 00000000..21a33f06
--- /dev/null
+++ b/src/intent-client-lib/intentclient.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QScopedPointer>
+#include <qqml.h>
+#include <QQmlInfo>
+
+#include "intentclient.h"
+#include "intentclientsysteminterface.h"
+#include "intentclientrequest.h"
+#include "intenthandler.h"
+#include "logging.h"
+
+#include <exception>
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentClient *IntentClient::s_instance = nullptr;
+
+IntentClient *IntentClient::createInstance(IntentClientSystemInterface *systemInterface)
+{
+ if (Q_UNLIKELY(s_instance))
+ qFatal("IntentClient::createInstance() was called a second time.");
+ if (Q_UNLIKELY(!systemInterface))
+ qFatal("IntentClient::createInstance() was called without a systemInterface.");
+
+ QScopedPointer<IntentClient> ic(new IntentClient(systemInterface));
+ try {
+ systemInterface->initialize(ic.data());
+ } catch (const std::exception &exc) {
+ qCWarning(LogIntents) << "Failed to initialize IntentClient:" << exc.what();
+ return nullptr;
+ }
+
+ qmlRegisterUncreatableType<IntentClientRequest>("QtApplicationManager", 1, 0, "IntentRequest",
+ qSL("Cannot create objects of type IntentRequest"));
+ qmlRegisterType<IntentHandler>("QtApplicationManager", 1, 0, "IntentHandler");
+
+ return s_instance = ic.take();
+}
+
+IntentClient *IntentClient::instance()
+{
+ if (!s_instance)
+ qFatal("IntentClient::instance() was called before createInstance().");
+ return s_instance;
+}
+
+IntentClient::IntentClient(IntentClientSystemInterface *systemInterface, QObject *parent)
+ : QObject(parent)
+ , m_systemInterface(systemInterface)
+{
+ m_systemInterface->setParent(this);
+}
+
+IntentClient::~IntentClient()
+{
+ s_instance = nullptr;
+}
+
+void IntentClient::registerHandler(IntentHandler *handler)
+{
+ const QStringList intentIds = handler->intentIds();
+ for (auto intentId : intentIds) {
+ if (m_handlers.contains(intentId)) {
+ qmlWarning(handler) << "Double registration for intent" << intentId << "detected. "
+ "Only the handler that registered first will be active.";
+ } else {
+ m_handlers.insert(intentId, handler);
+ }
+ }
+}
+
+void IntentClient::unregisterHandler(IntentHandler *handler)
+{
+ const QStringList intentIds = handler->intentIds();
+ for (auto intentId : intentIds)
+ m_handlers.remove(intentId);
+}
+
+IntentClientRequest *IntentClient::requestToSystem(const QString &requestingApplicationId,
+ const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters)
+{
+ IntentClientRequest *ir = new IntentClientRequest(IntentClientRequest::Direction::ToSystem,
+ requestingApplicationId, QUuid(),
+ intentId, applicationId, parameters);
+
+ qCDebug(LogIntents) << "Application" << requestingApplicationId << "created an intent request for"
+ << intentId << "(application:" << applicationId << ")";
+ m_systemInterface->requestToSystem(ir);
+ return ir;
+}
+
+void IntentClient::requestToSystemFinished(IntentClientRequest *icr, const QUuid &newRequestId, bool error, const QString &errorMessage)
+{
+ if (error) {
+ icr->setErrorMessage(errorMessage);
+ icr->deleteLater();
+ } else if (newRequestId.isNull()) {
+ icr->setErrorMessage(qL1S("No matching Intent found in the system"));
+ icr->deleteLater();
+ } else {
+ icr->setRequestId(newRequestId);
+ m_waiting << icr;
+ }
+}
+
+void IntentClient::replyFromSystem(const QString &requestId, bool error, const QVariantMap &result)
+{
+ IntentClientRequest *icr = nullptr;
+ auto it = std::find_if(m_waiting.begin(), m_waiting.end(),
+ [requestId](IntentClientRequest *ir) -> bool {
+ return (ir->id() == requestId);
+});
+ if (it == m_waiting.cend()) {
+ qCWarning(LogIntents) << "IntentClient received an unexpected intent reply for request"
+ << requestId << " succeeded:" << error << "error:"
+ << result.value(qL1S("errorMessage")).toString() << "result:" << result;
+ return;
+ }
+ icr = *it;
+ m_waiting.erase(it);
+
+ if (error)
+ icr->setErrorMessage(result.value(qSL("errorMessage")).toString());
+ else
+ icr->setResult(result);
+ icr->deleteLater();
+
+ qCDebug(LogIntents) << "Application" << icr->requestingApplicationId() << "received an intent reply for"
+ << icr->intentId() << " succeeded:" << icr->succeeded() << "error:"
+ << icr->errorMessage() << "result:" << icr->result();
+}
+
+void IntentClient::requestToApplication(const QString &requestId, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters)
+{
+ //TODO: we should sanity check the applicationId
+ qCDebug(LogIntents) << "Incoming intent request" << requestId << " to application" << applicationId
+ << "for intent" << intentId << "parameters" << parameters;
+
+ IntentClientRequest *icr = new IntentClientRequest(IntentClientRequest::Direction::ToApplication,
+ QString(), requestId, intentId, applicationId,
+ parameters);
+
+ IntentHandler *handler = m_handlers.value(intentId);
+ if (handler) {
+ emit handler->receivedRequest(icr);
+ } else {
+ qCDebug(LogIntents) << "No Intent handler registered for intent" << intentId;
+ errorReplyFromApplication(icr, qSL("No matching IntentHandler found."));
+ }
+}
+
+void IntentClient::replyFromApplication(IntentClientRequest *icr, const QVariantMap &result)
+{
+ if (!icr || icr->m_direction != IntentClientRequest::Direction::ToApplication)
+ return;
+ icr->m_succeeded = true;
+ icr->m_result = result;
+
+ m_systemInterface->replyFromApplication(icr);
+ icr->deleteLater();
+}
+
+void IntentClient::errorReplyFromApplication(IntentClientRequest *icr, const QString &errorMessage)
+{
+ if (!icr || icr->m_direction != IntentClientRequest::Direction::ToApplication)
+ return;
+ icr->m_succeeded = false;
+ icr->m_result = QVariantMap{ { qSL("errorMessage"), errorMessage } };
+
+ m_systemInterface->replyFromApplication(icr);
+ icr->deleteLater();
+}
+
+QT_END_NAMESPACE_AM
+
diff --git a/src/intent-client-lib/intentclient.h b/src/intent-client-lib/intentclient.h
new file mode 100644
index 00000000..730647e1
--- /dev/null
+++ b/src/intent-client-lib/intentclient.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QString>
+#include <QVariantMap>
+#include <QList>
+#include <QMap>
+
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentHandler;
+class IntentClientRequest;
+class IntentClientSystemInterface;
+
+/* internal interface used by IntentRequest and IntentHandler */
+
+class IntentClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~IntentClient() override;
+ static IntentClient *createInstance(IntentClientSystemInterface *systemInterface);
+ static IntentClient *instance();
+
+ IntentClientRequest *requestToSystem(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters);
+ void replyFromApplication(IntentClientRequest *icr, const QVariantMap &result);
+ void errorReplyFromApplication(IntentClientRequest *icr, const QString &errorMessage);
+
+ void registerHandler(IntentHandler *handler);
+ void unregisterHandler(IntentHandler *handler);
+
+private:
+ void requestToSystemFinished(IntentClientRequest *icr, const QUuid &newRequestId,
+ bool error, const QString &errorMessage);
+ void replyFromSystem(const QString &requestId, bool error, const QVariantMap &result);
+
+ void requestToApplication(const QString &requestId, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters);
+
+private:
+ IntentClient(IntentClientSystemInterface *systemInterface, QObject *parent = nullptr);
+ Q_DISABLE_COPY(IntentClient)
+ static IntentClient *s_instance;
+
+ QList<IntentClientRequest *> m_waiting;
+ QMap<QString, IntentHandler *> m_handlers;
+
+ IntentClientSystemInterface *m_systemInterface;
+ friend class IntentClientSystemInterface;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-client-lib/intentclientrequest.cpp b/src/intent-client-lib/intentclientrequest.cpp
new file mode 100644
index 00000000..f4be4a90
--- /dev/null
+++ b/src/intent-client-lib/intentclientrequest.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intentclientrequest.h"
+#include "intentclient.h"
+
+#include <QQmlEngine>
+#include <QThread>
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentClientRequest *IntentClientRequest::create(const QString &requestingApplicationId,
+ const QString &intentId, const QVariantMap &parameters)
+{
+ return create(requestingApplicationId, intentId, QString(), parameters);
+}
+
+IntentClientRequest *IntentClientRequest::create(const QString &requestingApplicationId,
+ const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters)
+{
+ //TODO: check that parameters only contains basic datatypes. convertFromJSVariant() does most of
+ // this already, but doesn't bail out on unconvertible types (yet)
+
+ if (intentId.isEmpty())
+ return nullptr;
+ return IntentClient::instance()->requestToSystem(requestingApplicationId, intentId, applicationId, parameters);
+}
+
+QUuid IntentClientRequest::id() const
+{
+ return m_id;
+}
+
+IntentClientRequest::Direction IntentClientRequest::direction() const
+{
+ return m_direction;
+}
+
+QString IntentClientRequest::requestId() const
+{
+ return id().toString();
+}
+
+QString IntentClientRequest::intentId() const
+{
+ return m_intentId;
+}
+
+QString IntentClientRequest::applicationId() const
+{
+ return m_applicationId;
+}
+
+QString IntentClientRequest::requestingApplicationId() const
+{
+ return m_requestingApplicationId;
+}
+
+QVariantMap IntentClientRequest::parameters() const
+{
+ return m_parameters;
+}
+
+bool IntentClientRequest::succeeded() const
+{
+ return m_succeeded;
+}
+
+const QVariantMap IntentClientRequest::result() const
+{
+ return m_result;
+}
+
+QString IntentClientRequest::errorMessage() const
+{
+ return m_errorMessage;
+}
+
+void IntentClientRequest::sendReply(const QVariantMap &result)
+{
+ //TODO: check that result only contains basic datatypes. convertFromJSVariant() does most of
+ // this already, but doesn't bail out on unconvertible types (yet)
+
+ if (m_direction != Direction::ToApplication)
+ return;
+ IntentClient *ic = IntentClient::instance();
+
+ if (QThread::currentThread() != ic->thread()) {
+ ic->metaObject()->invokeMethod(ic, [this, ic, result]()
+ { ic->replyFromApplication(this, result); },
+ Qt::QueuedConnection);
+ } else {
+ ic->replyFromApplication(this, result);
+ }
+}
+
+void IntentClientRequest::sendErrorReply(const QString &errorMessage)
+{
+ if (m_direction != Direction::ToApplication)
+ return;
+ IntentClient *ic = IntentClient::instance();
+
+ if (QThread::currentThread() != ic->thread()) {
+ ic->metaObject()->invokeMethod(ic, [this, ic, errorMessage]()
+ { ic->errorReplyFromApplication(this, errorMessage); },
+ Qt::QueuedConnection);
+ } else {
+ ic->errorReplyFromApplication(this, errorMessage);
+ }
+}
+
+IntentClientRequest::IntentClientRequest(Direction direction, const QString &requestingApplicationId,
+ const QUuid &id, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters)
+ : QObject()
+ , m_direction(direction)
+ , m_id(id)
+ , m_intentId(intentId)
+ , m_requestingApplicationId(requestingApplicationId)
+ , m_applicationId(applicationId)
+ , m_parameters(parameters)
+{ }
+
+void IntentClientRequest::setRequestId(const QUuid &requestId)
+{
+ if (m_id != requestId) {
+ m_id = requestId;
+ emit requestIdChanged();
+ }
+}
+
+void IntentClientRequest::setResult(const QVariantMap &result)
+{
+ if (m_result != result) {
+ m_result = result;
+ m_succeeded = true;
+ emit finished();
+ }
+}
+
+void IntentClientRequest::setErrorMessage(const QString &errorMessage)
+{
+ if (m_errorMessage != errorMessage) {
+ m_errorMessage = errorMessage;
+ m_succeeded = false;
+ emit finished();
+ }
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-client-lib/intentclientrequest.h b/src/intent-client-lib/intentclientrequest.h
new file mode 100644
index 00000000..444cf39c
--- /dev/null
+++ b/src/intent-client-lib/intentclientrequest.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QDir>
+#include <QUuid>
+#include <QString>
+#include <QVariantMap>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentClient;
+
+class IntentClientRequest : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString requestId READ requestId NOTIFY requestIdChanged)
+ Q_PROPERTY(Direction direction READ direction CONSTANT)
+ Q_PROPERTY(QString intentId READ intentId CONSTANT)
+ Q_PROPERTY(QString applicationId READ applicationId CONSTANT)
+ Q_PROPERTY(QVariantMap parameters READ parameters CONSTANT)
+ Q_PROPERTY(bool succeeded READ succeeded NOTIFY finished)
+ Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY finished)
+ Q_PROPERTY(QVariantMap result READ result NOTIFY finished)
+
+public:
+ enum class Direction { ToSystem, ToApplication };
+ Q_ENUM(Direction)
+
+ static IntentClientRequest *create(const QString &requestingApplicationId, const QString &intentId, const QVariantMap &parameters);
+ static IntentClientRequest *create(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QVariantMap &parameters);
+
+ QUuid id() const;
+ Direction direction() const;
+ QString requestId() const;
+ QString intentId() const;
+ QString applicationId() const;
+ QString requestingApplicationId() const;
+ QVariantMap parameters() const;
+
+ const QVariantMap result() const;
+ bool succeeded() const;
+ QString errorMessage() const;
+
+ Q_INVOKABLE void sendReply(const QVariantMap &result);
+ Q_INVOKABLE void sendErrorReply(const QString &errorMessage);
+
+signals:
+ void requestIdChanged();
+ void finished();
+
+private:
+ IntentClientRequest(Direction direction, const QString &requestingApplicationId, const QUuid &id,
+ const QString &intentId, const QString &applicationId, const QVariantMap &parameters);
+
+ void setRequestId(const QUuid &requestId);
+ void setResult(const QVariantMap &result);
+ void setErrorMessage(const QString &errorMessage);
+
+ Direction m_direction;
+ QUuid m_id;
+ QString m_intentId;
+ QString m_requestingApplicationId;
+ QString m_applicationId;
+ QVariantMap m_parameters;
+ QVariantMap m_result;
+ QString m_errorMessage;
+ bool m_requestSent = false;
+ bool m_replyReceived = false;
+ bool m_succeeded = false;
+
+ Q_DISABLE_COPY(IntentClientRequest)
+
+ friend class IntentClient;
+};
+
+QT_END_NAMESPACE_AM
+
+Q_DECLARE_METATYPE(QtAM::IntentClientRequest *)
diff --git a/src/intent-client-lib/intentclientsysteminterface.cpp b/src/intent-client-lib/intentclientsysteminterface.cpp
new file mode 100644
index 00000000..ee2329d6
--- /dev/null
+++ b/src/intent-client-lib/intentclientsysteminterface.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intentclientsysteminterface.h"
+#include "intentclient.h"
+#include "intentclientrequest.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+void IntentClientSystemInterface::initialize(IntentClient *intentClient)
+{
+ m_ic = intentClient;
+ connect(this, &IntentClientSystemInterface::requestToSystemFinished,
+ m_ic, &IntentClient::requestToSystemFinished);
+ connect(this, &IntentClientSystemInterface::replyFromSystem,
+ m_ic, &IntentClient::replyFromSystem);
+ connect(this, &IntentClientSystemInterface::requestToApplication,
+ m_ic, &IntentClient::requestToApplication);
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-client-lib/intentclientsysteminterface.h b/src/intent-client-lib/intentclientsysteminterface.h
new file mode 100644
index 00000000..a140c190
--- /dev/null
+++ b/src/intent-client-lib/intentclientsysteminterface.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QUuid>
+#include <QVariantMap>
+#include <QtAppManCommon/global.h>
+
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentClient;
+class IntentClientRequest;
+
+class IntentClientSystemInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual ~IntentClientSystemInterface() = default;
+
+ virtual void initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false);
+
+ virtual void requestToSystem(IntentClientRequest *icr) = 0;
+ virtual void replyFromApplication(IntentClientRequest *icr) = 0;
+
+signals:
+ void requestToSystemFinished(IntentClientRequest *icr, const QUuid &newRequestId,
+ bool error, const QString &errorMessage);
+ void replyFromSystem(const QString &requestId, bool error, const QVariantMap &result);
+
+ void requestToApplication(const QString &requestId, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters);
+
+protected:
+ IntentClient *m_ic = nullptr;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-client-lib/intenthandler.cpp b/src/intent-client-lib/intenthandler.cpp
new file mode 100644
index 00000000..a11f3471
--- /dev/null
+++ b/src/intent-client-lib/intenthandler.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intenthandler.h"
+#include "intentclient.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentHandler::IntentHandler(QObject *parent)
+ : QObject(parent)
+{ }
+
+IntentHandler::IntentHandler(const QString &intentId, QObject *parent)
+ : QObject(parent)
+ , m_intentIds(intentId)
+{ }
+
+IntentHandler::IntentHandler(const QStringList &intentIds, QObject *parent)
+ : QObject(parent)
+ , m_intentIds(intentIds)
+
+{ }
+
+IntentHandler::~IntentHandler()
+{
+ if (auto ie = IntentClient::instance())
+ ie->unregisterHandler(this);
+}
+
+QStringList IntentHandler::intentIds() const
+{
+ return m_intentIds;
+}
+
+void IntentHandler::setIntentIds(const QStringList &intentIds)
+{
+ if (intentIds != m_intentIds) {
+ m_intentIds = intentIds;
+ emit intentIdsChanged(m_intentIds);
+ }
+}
+
+void IntentHandler::componentComplete()
+{
+ IntentClient::instance()->registerHandler(this);
+}
+
+void IntentHandler::classBegin()
+{ }
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-client-lib/intenthandler.h b/src/intent-client-lib/intenthandler.h
new file mode 100644
index 00000000..3a57a3de
--- /dev/null
+++ b/src/intent-client-lib/intenthandler.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QQmlParserStatus>
+#include <QUuid>
+#include <QString>
+#include <QStringList>
+#include <QVariantMap>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentClientRequest;
+
+class IntentHandler : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QStringList intentIds READ intentIds WRITE setIntentIds NOTIFY intentIdsChanged)
+
+public:
+ IntentHandler(QObject *parent = nullptr);
+ IntentHandler(const QString &intentId, QObject *parent = nullptr);
+ IntentHandler(const QStringList &intentIds, QObject *parent = nullptr);
+ ~IntentHandler() override;
+
+ QStringList intentIds() const;
+ void setIntentIds(const QStringList &intentId);
+
+signals:
+ void intentIdsChanged(const QStringList &intentId);
+
+ void receivedRequest(QtAM::IntentClientRequest *request);
+
+protected:
+ void componentComplete() override;
+ void classBegin() override;
+
+private:
+ Q_DISABLE_COPY(IntentHandler)
+
+ QStringList m_intentIds;
+};
+
+QT_END_NAMESPACE_AM
+
+Q_DECLARE_METATYPE(QtAM::IntentHandler *)
diff --git a/src/intent-server-lib/intent-server-lib.pro b/src/intent-server-lib/intent-server-lib.pro
new file mode 100644
index 00000000..5dadab01
--- /dev/null
+++ b/src/intent-server-lib/intent-server-lib.pro
@@ -0,0 +1,25 @@
+TEMPLATE = lib
+TARGET = QtAppManIntentServer
+MODULE = appman_intent_server
+
+load(am-config)
+
+QT = core network qml
+QT_FOR_PRIVATE *= \
+ appman_common-private \
+
+CONFIG *= static internal_module
+
+HEADERS += \
+ intent.h \
+ intentserver.h \
+ intentserverrequest.h \
+ intentserversysteminterface.h
+
+SOURCES += \
+ intent.cpp \
+ intentserver.cpp \
+ intentserverrequest.cpp \
+ intentserversysteminterface.cpp
+
+load(qt_module)
diff --git a/src/intent-server-lib/intent.cpp b/src/intent-server-lib/intent.cpp
new file mode 100644
index 00000000..fedb998e
--- /dev/null
+++ b/src/intent-server-lib/intent.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intent.h"
+
+#include <QRegularExpression>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE_AM
+
+QString Intent::id() const
+{
+ return m_id;
+}
+
+Intent::Visibility Intent::visibility() const
+{
+ return m_visibility;
+}
+
+QStringList Intent::requiredCapabilities() const
+{
+ return m_requiredCapabilities;
+}
+
+QVariantMap Intent::parameterMatch() const
+{
+ return m_parameterMatch;
+}
+
+QString Intent::applicationId() const
+{
+ return m_applicationId;
+}
+
+QString Intent::backgroundServiceId() const
+{
+ return m_backgroundServiceId;
+}
+
+bool Intent::checkParameterMatch(const QVariantMap &parameters) const
+{
+ QMapIterator<QString, QVariant> rit(m_parameterMatch);
+ while (rit.hasNext()) {
+ rit.next();
+ const QString &paramName = rit.key();
+ auto pit = parameters.find(paramName);
+ if (pit == parameters.cend())
+ return false;
+
+ const QVariant requiredValue = rit.value();
+ const QVariant actualValue = pit.value();
+
+ switch (requiredValue.type()) {
+ case QVariant::String: {
+ QRegularExpression regexp(requiredValue.toString());
+ auto match = regexp.match(actualValue.toString());
+ if (!match.hasMatch())
+ return false;
+ break;
+ }
+ case QVariant::List: {
+ bool foundMatch = false;
+ const QVariantList rvlist = requiredValue.toList();
+ for (const QVariant &rv2 : rvlist) {
+ if (actualValue.canConvert(rv2.type()) && actualValue == rv2) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (!foundMatch)
+ return false;
+ break;
+ }
+ default: {
+ if (requiredValue != actualValue)
+ return false;
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+Intent::Intent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
+ const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
+ : m_id(id)
+ , m_visibility(visibility)
+ , m_requiredCapabilities(capabilities)
+ , m_parameterMatch(parameterMatch)
+ , m_applicationId(applicationId)
+ , m_backgroundServiceId(backgroundHandlerId)
+{ }
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h
new file mode 100644
index 00000000..24250615
--- /dev/null
+++ b/src/intent-server-lib/intent.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QString>
+#include <QStringList>
+#include <QVariantMap>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class Intent
+{
+public:
+ enum Visibility {
+ Public,
+ Hidden,
+ Private
+ };
+
+ QString id() const;
+ Visibility visibility() const;
+ QStringList requiredCapabilities() const;
+ QVariantMap parameterMatch() const;
+
+ QString applicationId() const;
+ QString backgroundServiceId() const;
+
+ bool checkParameterMatch(const QVariantMap &parameters) const;
+
+private:
+ Intent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch = QVariantMap());
+
+ QString m_id;
+ Visibility m_visibility = Private;
+ QStringList m_requiredCapabilities;
+ QVariantMap m_parameterMatch;
+
+ QString m_applicationId;
+ QString m_backgroundServiceId;
+
+ friend class IntentServer;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserver.cpp b/src/intent-server-lib/intentserver.cpp
new file mode 100644
index 00000000..285e0770
--- /dev/null
+++ b/src/intent-server-lib/intentserver.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intentserver.h"
+#include "intentserversysteminterface.h"
+#include "intentserverrequest.h"
+#include <QtAppManCommon/logging.h>
+
+#include <algorithm>
+
+#include <QRegularExpression>
+#include <QUuid>
+#include <QTimer>
+#include <QDebug>
+
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentServer *IntentServer::s_instance = nullptr;
+
+IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemInterface)
+{
+ if (Q_UNLIKELY(s_instance))
+ qFatal("IntentServer::createInstance() was called a second time.");
+ if (Q_UNLIKELY(!systemInterface))
+ qFatal("IntentServer::createInstance() was called without a systemInterface.");
+
+ QScopedPointer<IntentServer> is(new IntentServer(systemInterface));
+ systemInterface->initialize(is.data());
+
+ qmlRegisterSingletonType<IntentServer>("QtApplicationManager", 1, 0, "IntentManager",
+ &IntentServer::instanceForQml);
+ return s_instance = is.take();
+}
+
+IntentServer *IntentServer::instance()
+{
+ if (!s_instance)
+ qFatal("IntentServer::instance() was called before createInstance().");
+ return s_instance;
+}
+
+QObject *IntentServer::instanceForQml(QQmlEngine *, QJSEngine *)
+{
+ QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
+ return instance();
+}
+
+
+IntentServer::IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent)
+ : QObject(parent)
+ , m_systemInterface(systemInterface)
+{
+ m_systemInterface->setParent(this);
+}
+
+IntentServer::~IntentServer()
+{
+ s_instance = nullptr;
+}
+
+bool IntentServer::addApplication(const QString &applicationId)
+{
+ if (m_knownApplications.contains(applicationId))
+ return false;
+ m_knownApplications << applicationId;
+ return true;
+}
+
+bool IntentServer::addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId)
+{
+ if (!m_knownApplications.contains(applicationId))
+ return false;
+ const QStringList services = m_knownBackgroundServices.value(applicationId);
+ if (services.contains(backgroundServiceId))
+ return false;
+ m_knownBackgroundServices[applicationId].append(backgroundServiceId);
+ return true;
+}
+
+const Intent *IntentServer::addIntent(const QString &id, const QString &applicationId, const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
+{
+ return addIntent(id, applicationId, QString(), capabilities, visibility, parameterMatch);
+}
+
+const Intent *IntentServer::addIntent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId, const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
+{
+ if (id.isEmpty()
+ || !m_knownApplications.contains(applicationId)
+ || find(id, applicationId)
+ || (!backgroundHandlerId.isEmpty()
+ && !m_knownBackgroundServices[applicationId].contains(backgroundHandlerId))) {
+ return nullptr;
+ }
+
+ auto intent = new Intent(id, applicationId, backgroundHandlerId, capabilities, visibility,
+ parameterMatch);
+ m_intents << intent;
+ emit intentAdded(intent);
+ return intent;
+}
+
+void IntentServer::removeIntent(const Intent *intent)
+{
+ if (intent) {
+ int pos = m_intents.indexOf(intent);
+
+ if (pos >= 0) {
+ m_intents.removeAt(pos);
+ emit intentRemoved(intent);
+ }
+ }
+}
+
+QVector<const Intent *> IntentServer::all() const
+{
+ return m_intents;
+}
+
+QVector<const Intent *> IntentServer::filterByIntentId(const QString &intentId, const QVariantMap &parameters) const
+{
+ QVector<const Intent *> result;
+ std::copy_if(m_intents.cbegin(), m_intents.cend(), std::back_inserter(result),
+ [intentId, parameters](const Intent *intent) -> bool {
+ return (intent->id() == intentId) && intent->checkParameterMatch(parameters);
+
+ });
+ return result;
+}
+
+QVector<const Intent *> IntentServer::filterByApplicationId(const QString &applicationId, const QVariantMap &parameters) const
+{
+ QVector<const Intent *> result;
+ std::copy_if(m_intents.cbegin(), m_intents.cend(), std::back_inserter(result),
+ [applicationId, parameters](const Intent *intent) -> bool {
+ return (intent->applicationId() == applicationId) && intent->checkParameterMatch(parameters);
+
+ });
+ return result;
+}
+
+const Intent *IntentServer::find(const QString &intentId, const QString &applicationId, const QVariantMap &parameters) const
+{
+ auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
+ [intentId, applicationId, parameters](const Intent *intent) -> bool {
+ return (intent->applicationId() == applicationId) && (intent->id() == intentId)
+ && intent->checkParameterMatch(parameters);
+ });
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+
+void IntentServer::triggerRequestQueue()
+{
+ QTimer::singleShot(0, this, &IntentServer::processRequestQueue);
+}
+
+void IntentServer::enqueueRequest(IntentServerRequest *irs)
+{
+ qCDebug(LogIntents) << "Enqueueing Intent request:" << irs << irs->id() << irs->state() << m_requestQueue.size();
+ m_requestQueue.enqueue(irs);
+ triggerRequestQueue();
+}
+
+void IntentServer::processRequestQueue()
+{
+ if (m_requestQueue.isEmpty())
+ return;
+
+ IntentServerRequest *irs = m_requestQueue.takeFirst();
+
+ qCDebug(LogIntents) << "Processing intent request" << irs << irs->id() << "in state" << irs->state() << m_requestQueue.size();
+
+ if (irs->state() == IntentServerRequest::State::ReceivedRequest) { // step 1) disambiguate
+ if (!irs->m_actualIntent) {
+ // not disambiguated yet
+
+ if (!isSignalConnected(QMetaMethod::fromSignal(&IntentServer::disambiguationRequest))) {
+ // If the System-UI does not react to the signal, then just use the first match.
+ irs->m_actualIntent = irs->m_intents.first();
+ } else {
+ m_disambiguationQueue.enqueue(irs);
+ irs->setState(IntentServerRequest::State::WaitingForDisambiguation);
+ emit disambiguationRequest(irs->id(), irs->m_intents.first()->id(), irs->m_intents, irs->m_parameters);
+ }
+ }
+ if (irs->intent()) {
+ qCDebug(LogIntents) << "No disambiguation necessary/required for intent" << irs->intent()->id();
+ irs->setState(IntentServerRequest::State::Disambiguated);
+ }
+ }
+
+ if (irs->state() == IntentServerRequest::State::Disambiguated) { // step 2) start app
+ auto handlerIPC = m_systemInterface->findClientIpc(irs->intent()->applicationId());
+ if (!handlerIPC) {
+ qCDebug(LogIntents) << "Intent target app" << irs->intent()->applicationId() << "is not running";
+ m_startingAppQueue.enqueue(irs);
+ irs->setState(IntentServerRequest::State::WaitingForApplicationStart);
+ m_systemInterface->startApplication(irs->intent()->applicationId());
+ } else {
+ qCDebug(LogIntents) << "Intent target app" << irs->intent()->applicationId() << "is already running";
+ irs->setState(IntentServerRequest::State::StartedApplication);
+ }
+ }
+
+ if (irs->state() == IntentServerRequest::State::StartedApplication) { // step 3) send request out
+ auto clientIPC = m_systemInterface->findClientIpc(irs->intent()->applicationId());
+ if (!clientIPC) {
+ qCWarning(LogIntents) << "Could not find an IPC connection for application"
+ << irs->intent()->applicationId() << "to forward the intent request"
+ << irs->id();
+ irs->requestFailed(qSL("No IPC channel to reach target application."));
+ } else {
+ qCDebug(LogIntents) << "Sending intent request to application" << irs->intent()->applicationId();
+ m_sentToAppQueue.enqueue(irs);
+ m_systemInterface->requestToApplication(clientIPC, irs);
+ irs->setState(IntentServerRequest::State::WaitingForReplyFromApplication);
+ }
+ }
+
+ if (irs->state() == IntentServerRequest::State::ReceivedReplyFromApplication) { // step 5) send reply to requesting app
+ auto clientIPC = m_systemInterface->findClientIpc(irs->m_requestingAppId);
+ if (!clientIPC) {
+ qCWarning(LogIntents) << "Could not find an IPC connection for application"
+ << irs->m_requestingAppId << "to forward the Intent reply"
+ << irs->id();
+ } else {
+ qCDebug(LogIntents) << "Forwarding intent reply" << irs->id() << "to requesting application"
+ << irs->m_requestingAppId;
+ m_systemInterface->replyFromSystem(clientIPC, irs);
+ }
+ QTimer::singleShot(0, this, [irs]() { delete irs; }); // aka deleteLater for non-QObject
+ irs = nullptr;
+ }
+
+ triggerRequestQueue();
+}
+
+void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent *intent)
+{
+ IntentServerRequest *irs = nullptr;
+ for (int i = 0; i < m_disambiguationQueue.size(); ++i) {
+ if (m_disambiguationQueue.at(i)->id() == requestId) {
+ irs = m_disambiguationQueue.takeAt(i);
+ break;
+ }
+ }
+
+ if (!irs) {
+ qmlWarning(this) << "Got a disambiguation acknowledge for intent" << requestId
+ << "but no disambiguation was expected for this intent";
+ } else {
+ if (irs->m_intents.contains(intent)) {
+ irs->m_actualIntent = intent;
+ irs->setState(IntentServerRequest::State::Disambiguated);
+ } else {
+ qCWarning(LogIntents) << "IntentServer::acknowledgeDisambiguationRequest for intent"
+ << requestId << "tried to disambiguate to the intent"
+ << (intent ? intent->id() : qSL("<null>"))
+ << "which was not in the list of available disambiguations";
+
+ irs->requestFailed(qSL("Failed to disambiguate"));
+ }
+ enqueueRequest(irs);
+ }
+}
+
+void IntentServer::applicationWasStarted(const QString &applicationId)
+{
+ // check if any intent request is waiting for this app to start
+ bool foundOne = false;
+ for (int i = 0; i < m_startingAppQueue.size(); ++i) {
+ auto irs = m_startingAppQueue.at(i);
+ if (irs->intent()->applicationId() == applicationId) {
+ qCDebug(LogIntents) << "Intent request" << irs->intent()->id()
+ << "can now be forwarded to application" << applicationId;
+
+ irs->setState(IntentServerRequest::State::StartedApplication);
+ m_requestQueue << m_startingAppQueue.takeAt(i);
+ foundOne = true;
+ }
+ }
+ if (foundOne)
+ triggerRequestQueue();
+}
+
+void IntentServer::replyFromApplication(const QString &replyingApplicationId, const QString &requestId, bool error, const QVariantMap &result)
+{
+ IntentServerRequest *irs = nullptr;
+ for (int i = 0; i < m_sentToAppQueue.size(); ++i) {
+ if (m_sentToAppQueue.at(i)->id() == requestId) {
+ irs = m_sentToAppQueue.takeAt(i);
+ break;
+ }
+ }
+
+ if (!irs) {
+ qCWarning(LogIntents) << "Got a reply for intent" << requestId << "from application"
+ << replyingApplicationId << "but no reply was expected for this intent";
+ } else {
+ if (irs->intent()->applicationId() != replyingApplicationId) {
+ qCWarning(LogIntents) << "Got a reply for intent" << irs->id() << "from application"
+ << replyingApplicationId << "but expected a reply from"
+ << irs->intent()->applicationId() << "instead";
+ irs->requestFailed(qSL("Request reply received from wrong application"));
+ } else {
+ QString errorMessage;
+ if (error) {
+ errorMessage = result.value(qSL("errorMessage")).toString();
+ qCDebug(LogIntents) << "Got an error reply for intent" << irs->id() << "from application"
+ << replyingApplicationId << ":" << errorMessage;
+ irs->requestFailed(errorMessage);
+ } else {
+ qCDebug(LogIntents) << "Got a reply for intent" << irs->id() << "from application"
+ << replyingApplicationId << ":" << result;
+ irs->requestSucceeded(result);
+ }
+ }
+ enqueueRequest(irs);
+ }
+}
+
+IntentServerRequest *IntentServer::requestToSystem(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QVariantMap &parameters)
+{
+ qCDebug(LogIntents) << "Incoming intent request" << intentId << "from application"
+ << requestingApplicationId << "to application" << applicationId;
+
+ QVector<const Intent *> intents;
+ if (applicationId.isEmpty())
+ intents = filterByIntentId(intentId, parameters);
+ else if (const Intent *intent = find(intentId, applicationId, parameters))
+ intents << intent;
+
+ if (intents.isEmpty()) {
+ qCWarning(LogIntents) << "Unknown intent" << intentId << "was requested from application"
+ << requestingApplicationId;
+ return nullptr;
+ }
+
+ // filter on visibility and capabilities
+ //TODO: move this part to a separate filter() function?
+ for (auto it = intents.begin(); it != intents.end(); ) {
+ const Intent *intent = *it;
+ bool keep = true;
+
+ if ((intent->visibility() == Intent::Private)
+ && (intent->applicationId() != requestingApplicationId)) {
+ qCDebug(LogIntents) << "Not considering" << intent->id() << "/" << intent->applicationId()
+ << "due to private visibility";
+ keep = false;
+ }
+ else if (!intent->requiredCapabilities().isEmpty()
+ && !m_systemInterface->checkApplicationCapabilities(requestingApplicationId,
+ intent->requiredCapabilities())) {
+ qCDebug(LogIntents) << "Not considering" << intent->id() << "/" << intent->applicationId()
+ << "due to missing capabilities";
+ keep = false;
+ }
+ if (!keep)
+ intents.erase(it);
+ else
+ ++it;
+ }
+
+ if (intents.isEmpty()) {
+ qCWarning(LogIntents) << "Inaccessible intent" << intentId << "was requested from application"
+ << requestingApplicationId;
+ return nullptr;
+ }
+
+ auto irs = new IntentServerRequest(true, requestingApplicationId, intents, parameters);
+ enqueueRequest(irs);
+ return irs;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserver.h b/src/intent-server-lib/intentserver.h
new file mode 100644
index 00000000..2333be08
--- /dev/null
+++ b/src/intent-server-lib/intentserver.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QVariantMap>
+#include <QVector>
+#include <QUuid>
+#include <QQueue>
+#include <QtAppManCommon/global.h>
+#include <QtAppManIntentServer/intent.h>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+QT_FORWARD_DECLARE_CLASS(QQmlEngine)
+QT_FORWARD_DECLARE_CLASS(QJSEngine)
+
+
+QT_BEGIN_NAMESPACE_AM
+
+class AbstractRuntime;
+class IntentServerRequest;
+class IntentServerSystemInterface;
+
+class IntentServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~IntentServer() override;
+ static IntentServer *createInstance(IntentServerSystemInterface *systemInterface);
+ static IntentServer *instance();
+ static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *);
+
+ Q_INVOKABLE QVector<const Intent *> all() const;
+ Q_INVOKABLE QVector<const Intent *> filterByIntentId(const QString &intentId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE QVector<const Intent *> filterByApplicationId(const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE const Intent *find(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+
+
+ bool addApplication(const QString &applicationId);
+ bool addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId);
+
+ const Intent *addIntent(const QString &id, const QString &applicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch = QVariantMap());
+
+ const Intent *addIntent(const QString &id, const QString &applicationId,
+ const QString &backgroundHandlerId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch = QVariantMap());
+
+ void removeIntent(const Intent *intent);
+
+signals:
+ void intentAdded(const Intent *intent);
+ void intentRemoved(const Intent *intent);
+
+ void disambiguationRequest(const QUuid &requestId, const QString &intentId,
+ const QVector<const Intent *> &intents, const QVariantMap &parameters);
+
+
+public slots:
+ void acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent *intent);
+
+private:
+ void applicationWasStarted(const QString &applicationId);
+ void replyFromApplication(const QString &replyingApplicationId, const QString &requestId,
+ bool error, const QVariantMap &result);
+ IntentServerRequest *requestToSystem(const QString &requestingApplicationId, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters);
+
+ void triggerRequestQueue();
+ void enqueueRequest(IntentServerRequest *irs);
+ void processRequestQueue();
+
+private:
+ IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent = nullptr);
+ Q_DISABLE_COPY(IntentServer)
+ static IntentServer *s_instance;
+
+ QStringList m_knownApplications;
+ QMap<QString, QStringList> m_knownBackgroundServices;
+
+ QQueue<IntentServerRequest *> m_requestQueue;
+
+ QQueue<IntentServerRequest *> m_disambiguationQueue;
+ QQueue<IntentServerRequest *> m_startingAppQueue;
+ QQueue<IntentServerRequest *> m_sentToAppQueue;
+
+ QVector<const Intent *> m_intents;
+
+ IntentServerSystemInterface *m_systemInterface;
+ friend class IntentServerSystemInterface;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserverrequest.cpp b/src/intent-server-lib/intentserverrequest.cpp
new file mode 100644
index 00000000..df71a93f
--- /dev/null
+++ b/src/intent-server-lib/intentserverrequest.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDebug>
+#include "intentserverrequest.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentServerRequest::IntentServerRequest(bool external, const QString &requestingAppId,
+ const QVector<const Intent *> &intents,
+ const QVariantMap &parameters)
+ : m_id(QUuid::createUuid())
+ , m_state(State::ReceivedRequest)
+ , m_external(external)
+ , m_requestingAppId(requestingAppId)
+ , m_intents(intents)
+ , m_parameters(parameters)
+ , m_actualIntent(intents.size() == 1 ? intents.first() : nullptr)
+{ }
+
+IntentServerRequest::State IntentServerRequest::state() const
+{
+ return m_state;
+}
+
+QUuid IntentServerRequest::id() const
+{
+ return m_id;
+}
+
+const Intent *IntentServerRequest::intent() const
+{
+ return m_actualIntent;
+}
+
+QVariantMap IntentServerRequest::parameters() const
+{
+ return m_parameters;
+}
+
+bool IntentServerRequest::isWaiting() const
+{
+ switch (state()) {
+ case State::WaitingForDisambiguation:
+ case State::WaitingForApplicationStart:
+ case State::WaitingForReplyFromApplication:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IntentServerRequest::hasSucceeded() const
+{
+ return m_succeeded;
+}
+
+QVariantMap IntentServerRequest::result() const
+{
+ return m_result;
+}
+
+void IntentServerRequest::requestFailed(const QString &errorMessage)
+{
+ m_succeeded = false;
+ m_result.clear();
+ m_result[qSL("errorMessage")] = errorMessage;
+ m_state = State::ReceivedReplyFromApplication;
+}
+
+void IntentServerRequest::requestSucceeded(const QVariantMap &result)
+{
+ m_succeeded = true;
+ m_result = result;
+ m_state = State::ReceivedReplyFromApplication;
+}
+
+void IntentServerRequest::setState(IntentServerRequest::State newState)
+{
+ m_state = newState;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserverrequest.h b/src/intent-server-lib/intentserverrequest.h
new file mode 100644
index 00000000..d523adde
--- /dev/null
+++ b/src/intent-server-lib/intentserverrequest.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QString>
+#include <QVariantMap>
+#include <QUuid>
+#include <QVector>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentServer;
+class Intent;
+
+class IntentServerRequest
+{
+ Q_GADGET
+
+public:
+ IntentServerRequest(bool external, const QString &requestingAppId, const QVector<const Intent *> &intents,
+ const QVariantMap &parameters);
+
+ enum class State {
+ ReceivedRequest,
+ WaitingForDisambiguation,
+ Disambiguated,
+ WaitingForApplicationStart,
+ StartedApplication,
+ WaitingForReplyFromApplication,
+ ReceivedReplyFromApplication,
+ };
+
+ Q_ENUM(State)
+
+ State state() const;
+ QUuid id() const;
+ const QtAM::Intent *intent() const;
+ QVariantMap parameters() const;
+ bool isWaiting() const;
+ bool hasSucceeded() const;
+ QVariantMap result() const;
+
+ void requestFailed(const QString &errorMessage);
+ void requestSucceeded(const QVariantMap &result);
+
+private:
+ void setState(State newState);
+
+private:
+ QUuid m_id;
+ State m_state;
+ bool m_external;
+ bool m_succeeded = false;
+ QString m_requestingAppId;
+ QVector<const Intent *> m_intents;
+ QVariantMap m_parameters;
+ QVariantMap m_result;
+ const Intent *m_actualIntent;
+
+ friend class IntentServer;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserversysteminterface.cpp b/src/intent-server-lib/intentserversysteminterface.cpp
new file mode 100644
index 00000000..bc8310ac
--- /dev/null
+++ b/src/intent-server-lib/intentserversysteminterface.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "intentserversysteminterface.h"
+#include "intentserver.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+void IntentServerSystemInterface::initialize(IntentServer *intentServer)
+{
+ m_is = intentServer;
+
+ connect(this, &IntentServerSystemInterface::replyFromApplication,
+ m_is, &IntentServer::replyFromApplication);
+ connect(this, &IntentServerSystemInterface::applicationWasStarted,
+ m_is, &IntentServer::applicationWasStarted);
+}
+
+IntentServer *IntentServerSystemInterface::intentServer() const
+{
+ return m_is;
+}
+
+IntentServerRequest *IntentServerSystemInterface::requestToSystem(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QVariantMap &parameters)
+{
+ // not possible to do via signal, due to return value
+ return m_is->requestToSystem(requestingApplicationId, intentId, applicationId, parameters);
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserversysteminterface.h b/src/intent-server-lib/intentserversysteminterface.h
new file mode 100644
index 00000000..f75cb7e2
--- /dev/null
+++ b/src/intent-server-lib/intentserversysteminterface.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QVariantMap>
+#include <QString>
+#include <QStringList>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentServer;
+class IntentServerRequest;
+
+class IntentServerSystemInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual ~IntentServerSystemInterface() = default;
+
+ virtual void initialize(IntentServer *intentServer);
+ IntentServer *intentServer() const;
+
+ class IpcConnection;
+ virtual IpcConnection *findClientIpc(const QString &appId) = 0;
+
+ virtual void startApplication(const QString &appId) = 0;
+
+
+ virtual bool checkApplicationCapabilities(const QString &applicationId,
+ const QStringList &requiredCapabilities) = 0;
+
+ IntentServerRequest *requestToSystem(const QString &requestingApplicationId, const QString &intentId,
+ const QString &applicationId, const QVariantMap &parameters);
+ virtual void replyFromSystem(IpcConnection *clientIPC, IntentServerRequest *irs) = 0;
+
+ virtual void requestToApplication(IpcConnection *clientIPC, IntentServerRequest *irs) = 0;
+
+signals:
+ void applicationWasStarted(const QString &appId);
+ void replyFromApplication(const QString &replyingApplicationId, const QString &requestId,
+ bool error, const QVariantMap &result);
+
+private:
+ IntentServer *m_is = nullptr;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/launcher-lib/intentclientdbusimplementation.cpp b/src/launcher-lib/intentclientdbusimplementation.cpp
new file mode 100644
index 00000000..39141c6c
--- /dev/null
+++ b/src/launcher-lib/intentclientdbusimplementation.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDBusConnection>
+#include <QDBusPendingReply>
+#include <QDBusPendingCallWatcher>
+#include "dbus-utilities.h"
+#include "intentclient.h"
+#include "intentclientrequest.h"
+#include "intentclientdbusimplementation.h"
+
+#include "intentinterface_interface.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+IntentClientDBusImplementation::IntentClientDBusImplementation(const QString &dbusName)
+ : IntentClientSystemInterface()
+ , m_dbusName(dbusName)
+{ }
+
+void IntentClientDBusImplementation::initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ IntentClientSystemInterface::initialize(intentClient);
+
+ m_dbusInterface = new IoQtApplicationManagerIntentInterfaceInterface(
+ QString(), qSL("/IntentManager"), QDBusConnection(m_dbusName), intentClient);
+
+ if (!m_dbusInterface->isValid())
+ throw std::logic_error("Could not connect to the /IntentManager object on the P2P D-Bus");
+
+ connect(m_dbusInterface, &IoQtApplicationManagerIntentInterfaceInterface::replyFromSystem,
+ intentClient, [this](const QString &requestId, bool error, const QVariantMap &result) {
+ emit replyFromSystem(requestId, error, convertFromDBusVariant(result).toMap());
+ });
+
+ connect(m_dbusInterface, &IoQtApplicationManagerIntentInterfaceInterface::requestToApplication,
+ intentClient, [this](const QString &requestId, const QString &id,
+ const QString &applicationId, const QVariantMap &parameters) {
+ emit requestToApplication(requestId, id, applicationId, convertFromDBusVariant(parameters).toMap());
+ });
+}
+
+void IntentClientDBusImplementation::requestToSystem(IntentClientRequest *icr)
+{
+ QDBusPendingReply<QString> reply =
+ m_dbusInterface->requestToSystem(icr->intentId(), icr->applicationId(),
+ convertFromJSVariant(icr->parameters()).toMap());
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, icr);
+ connect(watcher, &QDBusPendingCallWatcher::finished, icr, [this, watcher, icr]() {
+ watcher->deleteLater();
+
+ QDBusPendingReply<QString> reply = *watcher;
+ emit requestToSystemFinished(icr, QUuid::fromString(reply.argumentAt<0>()),
+ reply.isError(), reply.error().message());
+ });
+}
+
+void IntentClientDBusImplementation::replyFromApplication(IntentClientRequest *icr)
+{
+ m_dbusInterface->replyFromApplication(icr->id().toString(), !icr->succeeded(),
+ convertFromJSVariant(icr->result()).toMap());
+
+ //TODO: should we wait for the call completion - how/why would we report a possible failure?
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/launcher-lib/intentclientdbusimplementation.h b/src/launcher-lib/intentclientdbusimplementation.h
new file mode 100644
index 00000000..529d937f
--- /dev/null
+++ b/src/launcher-lib/intentclientdbusimplementation.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManIntentClient/intentclientsysteminterface.h>
+
+class IoQtApplicationManagerIntentInterfaceInterface;
+
+QT_BEGIN_NAMESPACE_AM
+
+class IntentClientDBusImplementation : public IntentClientSystemInterface
+{
+public:
+ IntentClientDBusImplementation(const QString &dbusName);
+
+ void initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false) override;
+
+ void requestToSystem(IntentClientRequest *icr) override;
+ void replyFromApplication(IntentClientRequest *icr) override;
+
+private:
+ IoQtApplicationManagerIntentInterfaceInterface *m_dbusInterface;
+ QString m_dbusName;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/launcher-lib/launcher-lib.pro b/src/launcher-lib/launcher-lib.pro
index 15421752..f0f8dcb8 100644
--- a/src/launcher-lib/launcher-lib.pro
+++ b/src/launcher-lib/launcher-lib.pro
@@ -12,15 +12,19 @@ QT_FOR_PRIVATE *= \
appman_shared_main-private \
appman_application-private \
appman_notification-private \
+ appman_intent_client-private \
CONFIG *= static internal_module
+DBUS_INTERFACES += ../dbus-lib/io.qt.applicationmanager.intentinterface.xml
+
SOURCES += \
qmlapplicationinterface.cpp \
ipcwrapperobject.cpp \
qmlapplicationinterfaceextension.cpp \
qmlnotification.cpp \
launchermain.cpp \
+ intentclientdbusimplementation.cpp
!headless:SOURCES += \
applicationmanagerwindow.cpp \
@@ -41,6 +45,7 @@ HEADERS += \
qmlapplicationinterfaceextension.h \
qmlnotification.h \
launchermain.h \
+ intentclientdbusimplementation.h
!headless:HEADERS += \
applicationmanagerwindow_p.h
diff --git a/src/launcher-lib/qmlapplicationinterface.cpp b/src/launcher-lib/qmlapplicationinterface.cpp
index 428708c6..a48a5e3b 100644
--- a/src/launcher-lib/qmlapplicationinterface.cpp
+++ b/src/launcher-lib/qmlapplicationinterface.cpp
@@ -43,6 +43,7 @@
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusReply>
+#include <QQmlEngine>
#include <QDebug>
#include <QPointer>
#include <QCoreApplication>
@@ -55,6 +56,9 @@
#include "notification.h"
#include "ipcwrapperobject.h"
#include "utilities.h"
+#include "intentclient.h"
+#include "intentclientrequest.h"
+#include "intentclientdbusimplementation.h"
QT_BEGIN_NAMESPACE_AM
@@ -144,6 +148,12 @@ bool QmlApplicationInterface::initialize()
QmlApplicationInterfaceExtension::initialize(m_connection);
+ auto intentClientDBusInterface = new IntentClientDBusImplementation(m_connection.name());
+ if (!IntentClient::createInstance(intentClientDBusInterface)) {
+ qCritical("ERROR: could not connect to the application manager's IntentInterface on the P2P D-Bus");
+ return false;
+ }
+
if (ok)
finishedInitialization();
return ok;
@@ -198,6 +208,18 @@ QVariantMap QmlApplicationInterface::applicationProperties() const
return m_applicationProperties;
}
+IntentClientRequest *QmlApplicationInterface::createIntentRequest(const QString &intentId, const QVariantMap &parameters)
+{
+ return createIntentRequest(intentId, QString(), parameters);
+}
+
+IntentClientRequest *QmlApplicationInterface::createIntentRequest(const QString &intentId, const QString &applicationId, const QVariantMap &parameters)
+{
+ auto req = IntentClientRequest::create(this->applicationId(), intentId, applicationId, parameters);
+ QQmlEngine::setObjectOwnership(req, QQmlEngine::CppOwnership);
+ return req;
+}
+
uint QmlApplicationInterface::notificationShow(QmlNotification *n)
{
if (n && m_notifyIf && m_notifyIf->isValid()) {
diff --git a/src/launcher-lib/qmlapplicationinterface.h b/src/launcher-lib/qmlapplicationinterface.h
index 2a4b923c..bd7d7738 100644
--- a/src/launcher-lib/qmlapplicationinterface.h
+++ b/src/launcher-lib/qmlapplicationinterface.h
@@ -55,6 +55,7 @@ QT_BEGIN_NAMESPACE_AM
class QmlNotification;
class Notification;
+class IntentClientRequest;
class Controller;
class QmlApplicationInterfaceExtension;
@@ -76,6 +77,8 @@ public:
QVariantMap systemProperties() const override;
QVariantMap applicationProperties() const override;
Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Notification *) createNotification();
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(IntentClientRequest *) createIntentRequest(const QString &intentId, const QVariantMap &parameters);
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(IntentClientRequest *) createIntentRequest(const QString &intentId, const QString &applicationId, const QVariantMap &parameters);
Q_INVOKABLE void acknowledgeQuit() const;
Q_INVOKABLE void finishedInitialization() override;
diff --git a/src/launchers/qml/main.cpp b/src/launchers/qml/main.cpp
index 993da379..7ed18027 100644
--- a/src/launchers/qml/main.cpp
+++ b/src/launchers/qml/main.cpp
@@ -279,7 +279,8 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
connect(m_applicationInterface, &QmlApplicationInterface::startApplication,
this, &Controller::startApplication);
if (!m_applicationInterface->initialize())
- throw Exception("Could not connect to the application manager's interface on the peer D-Bus");
+ throw Exception("Could not connect to the application manager's ApplicationInterface on the peer D-Bus");
+
} else {
QTimer::singleShot(0, [this, directLoad]() {
QFileInfo fi(directLoad);
diff --git a/src/main-lib/main-lib.pro b/src/main-lib/main-lib.pro
index 0211e242..d8087850 100644
--- a/src/main-lib/main-lib.pro
+++ b/src/main-lib/main-lib.pro
@@ -18,6 +18,7 @@ QT *= \
appman_notification-private \
appman_monitor-private \
appman_shared_main-private \
+ appman_intent_server-private \
!headless:QT *= appman_window-private
!disable-external-dbus-interfaces:qtHaveModule(dbus):QT *= dbus appman_dbus-private
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index 76833b7c..977ab980 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -115,6 +115,8 @@
#include "qml-utilities.h"
#include "dbus-utilities.h"
#include "package.h"
+#include "intentserver.h"
+#include "intentaminterface.h"
#if !defined(AM_HEADLESS)
# include "windowmanager.h"
@@ -168,6 +170,7 @@ Main::~Main()
delete m_engine;
+ delete m_intentServer;
delete m_notificationManager;
# if !defined(AM_HEADLESS)
delete m_windowManager;
@@ -456,6 +459,72 @@ void Main::loadApplicationDatabase(const QString &databasePath, bool recreateDat
StartupTimer::instance()->checkpoint("after application database loading");
}
+void Main::setupIntents() Q_DECL_NOEXCEPT_EXPR(false)
+{
+ qCDebug(LogSystem) << "Registering intents:";
+
+ const auto apps = m_applicationManager->applications();
+ for (const AbstractApplication *app : apps) {
+ if (app->isAlias())
+ continue;
+ const ApplicationInfo *info = app->nonAliasedInfo();
+ QSet<QString> intentIds;
+
+ const auto intents = info->intents();
+
+ if (!intents.isEmpty())
+ m_intentServer->addApplication(app->id());
+
+ for (const auto &intent : intents) {
+ /* example:
+ id: io.qt.shareImage
+ handledBy: main
+ visibility: public*|private
+ requiredCapabilities: [ a, b ]
+ parameterMatch:
+ mimeType: "^image/.*\.png$"
+ */
+ const QVariantMap map = intent.toMap();
+ const QString id = map[qSL("id")].toString();
+ Intent::Visibility visibility = Intent::Public;
+ const QString visibilityStr = map[qSL("visibility")].toString();
+ QString handledBy = map[qSL("handledBy")].toString();
+ const QStringList capabilities = map[qSL("requiredCapabilities")].toStringList();
+ const QVariantMap parameterMatch = map[qSL("parameterMatch")].toMap(); // do we really need that?
+
+ if (id.isEmpty())
+ throw Exception(Error::Intents, "intents need to have an id (app %1)").arg(app->id());
+ if (intentIds.contains(id))
+ throw Exception(Error::Intents, "found two intent handlers for %2 (app %1)").arg(app->id()).arg(id);
+ intentIds << id;
+
+ if (visibilityStr == qL1S("private"))
+ visibility = Intent::Private;
+ else if (visibilityStr == qL1S("hidden"))
+ visibility = Intent::Hidden;
+ else if (!visibilityStr.isEmpty() && (visibilityStr != qL1S("public"))) {
+ throw Exception(Error::Intents, "intent visibilty %3 is invalid (intent %2, app %1)")
+ .arg(app->id()).arg(id).arg(visibilityStr);
+ }
+
+ if (handledBy == qL1S("main"))
+ handledBy.clear();
+ // we do not support bg services yet
+ if (!handledBy.isEmpty()) {
+ throw Exception(Error::Intents, "service background handlers for intent are not supported yet (intent %2, app %1)")
+ .arg(app->id()).arg(id).arg(visibilityStr);
+ }
+
+ qCDebug(LogSystem).nospace().noquote() << " * " << id << " [app: " << app->id() << "]";
+
+ if (!m_intentServer->addIntent(id, app->id(), handledBy, capabilities,
+ visibility, parameterMatch)) {
+ throw Exception(Error::Intents, "could not add intent %2 for app %1").arg(app->id()).arg(id);
+ }
+ }
+ }
+}
+
void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration,
int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad,
const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false)
@@ -490,6 +559,10 @@ void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelect
StartupTimer::instance()->checkpoint("after ApplicationManager instantiation");
+ m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance();
+ setupIntents();
+ StartupTimer::instance()->checkpoint("after IntentManager instantiation");
+
m_notificationManager = NotificationManager::createInstance();
StartupTimer::instance()->checkpoint("after NotificationManager instantiation");
diff --git a/src/main-lib/main.h b/src/main-lib/main.h
index f324ed4c..1935f904 100644
--- a/src/main-lib/main.h
+++ b/src/main-lib/main.h
@@ -77,6 +77,7 @@ class ApplicationDatabase;
class ApplicationManager;
class ApplicationInstaller;
class NotificationManager;
+class IntentServer;
class WindowManager;
class QuickLauncher;
class SystemMonitor;
@@ -116,6 +117,7 @@ protected:
void setupInstallationLocations(const QVariantList &installationLocations);
void loadApplicationDatabase(const QString &databasePath, bool recreateDatabase,
const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false);
+ void setupIntents() Q_DECL_NOEXCEPT_EXPR(false);
void setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration,
int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad,
const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false);
@@ -166,6 +168,7 @@ private:
ApplicationIPCManager *m_applicationIPCManager = nullptr;
ApplicationInstaller *m_applicationInstaller = nullptr;
NotificationManager *m_notificationManager = nullptr;
+ IntentServer *m_intentServer = nullptr;
WindowManager *m_windowManager = nullptr;
QuickLauncher *m_quickLauncher = nullptr;
QVector<StartupInterface *> m_startupPlugins;
diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp
new file mode 100644
index 00000000..66410c6d
--- /dev/null
+++ b/src/manager-lib/intentaminterface.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#if defined(AM_MULTI_PROCESS)
+# include <QDBusMessage>
+# include <QDBusConnection>
+# include <QDBusPendingCallWatcher>
+# include <QDBusPendingReply>
+
+# include "io.qt.applicationmanager.intentinterface_adaptor.h"
+# include "dbus-utilities.h"
+# include "nativeruntime.h"
+#endif
+#include <QDebug>
+#include <QTimer>
+
+#include "logging.h"
+#include "runtimefactory.h"
+#include "intentserver.h"
+#include "intentclient.h"
+#include "intentserverrequest.h"
+#include "intentclientrequest.h"
+#include "intentaminterface.h"
+#include "qmlinprocessruntime.h"
+#include "application.h"
+#include "applicationmanager.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentAMImplementation vvv
+
+
+IntentServer *IntentAMImplementation::createIntentServerAndClientInstance()
+{
+ auto intentServerAMInterface = new IntentServerAMImplementation;
+ auto intentClientAMInterface = new IntentClientAMImplementation(intentServerAMInterface);
+ auto intentServer = IntentServer::createInstance(intentServerAMInterface);
+ auto intentClient = IntentClient::createInstance(intentClientAMInterface);
+
+ // this way, deleting the server (the return value of this factory function) will get rid
+ // of both client and server as well as both their AM interfaces
+ intentClient->setParent(intentServer);
+ return intentServer;
+}
+
+
+// ^^^ IntentAMImplementation ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentServerAMImplementation vvv
+
+
+void IntentServerAMImplementation::setIntentClientSystemInterface(IntentClientSystemInterface *iface)
+{
+ m_icsi = iface;
+}
+
+IntentClientSystemInterface *IntentServerAMImplementation::intentClientSystemInterface() const
+{
+ return m_icsi;
+}
+
+void IntentServerAMImplementation::initialize(IntentServer *intentManager)
+{
+ IntentServerSystemInterface::initialize(intentManager);
+
+ // The IntentManager itself doesn't know about the p2p D-Bus or the AM itself, so we need to
+ // wire it up to both interfaces from the outside
+ connect(&ApplicationManager::instance()->internalSignals, &ApplicationManagerInternalSignals::newRuntimeCreated,
+ intentServer(), [this](AbstractRuntime *runtime) {
+#if defined(AM_MULTI_PROCESS)
+ if (NativeRuntime *nativeRuntime = qobject_cast<NativeRuntime *>(runtime)) {
+ connect(nativeRuntime, &NativeRuntime::applicationConnectedToPeerDBus,
+ intentServer(), [this](const QDBusConnection &connection, Application *application) {
+ qCDebug(LogIntents) << "IntentManager: applicationConnectedToPeerDBus"
+ << (application ? application->id() : qSL("<launcher>"));
+
+ IntentServerDBusIpcConnection::create(connection, application, this);
+ });
+
+ connect(nativeRuntime, &NativeRuntime::applicationReadyOnPeerDBus,
+ intentServer(), [](const QDBusConnection &connection, Application *application) {
+ auto peer = IntentServerDBusIpcConnection::find(connection);
+
+ if (!peer) {
+ qCWarning(LogIntents) << "IntentManager: applicationReadyOnPeerDBus() was emitted, "
+ "but no previous applicationConnectedToPeerDBus() was seen";
+ return;
+ }
+ peer->setReady(application);
+ });
+
+ connect(nativeRuntime, &NativeRuntime::applicationDisconnectedFromPeerDBus,
+ intentServer(), [](const QDBusConnection &connection, Application *) {
+ delete IntentServerDBusIpcConnection::find(connection);
+ });
+ } else
+#endif // defined(AM_MULTI_PROCESS)
+ if (QmlInProcessRuntime *qmlRuntime = qobject_cast<QmlInProcessRuntime *>(runtime)) {
+ connect(qmlRuntime, &QmlInProcessRuntime::stateChanged,
+ intentServer(), [this, qmlRuntime](Am::RunState newState) {
+ if (newState == Am::Running)
+ IntentServerInProcessIpcConnection::create(qmlRuntime->application(), this);
+ else if (newState == Am::NotRunning)
+ delete IntentServerIpcConnection::find(qmlRuntime->application()->id());
+ });
+ }
+ });
+}
+
+bool IntentServerAMImplementation::checkApplicationCapabilities(const QString &applicationId,
+ const QStringList &requiredCapabilities)
+{
+ const auto app = ApplicationManager::instance()->application(applicationId);
+ if (!app)
+ return false;
+
+ auto capabilities = app->capabilities();
+ for (auto cap : requiredCapabilities) {
+ if (!capabilities.contains(cap))
+ return false;
+ }
+ return true;
+}
+
+IntentServerSystemInterface::IpcConnection *IntentServerAMImplementation::findClientIpc(const QString &appId)
+{
+ const auto app = ApplicationManager::instance()->application(appId);
+ if (!app)
+ return nullptr;
+ auto peer = IntentServerIpcConnection::find(appId);
+ return (peer && peer->isReady()) ? reinterpret_cast<IpcConnection *>(peer) : nullptr;
+}
+
+void IntentServerAMImplementation::startApplication(const QString &appId)
+{
+ ApplicationManager::instance()->startApplication(appId);
+}
+
+void IntentServerAMImplementation::requestToApplication(IntentServerSystemInterface::IpcConnection *clientIPC,
+ IntentServerRequest *irs)
+{
+ reinterpret_cast<IntentServerIpcConnection *>(clientIPC)->requestToApplication(irs);
+}
+
+void IntentServerAMImplementation::replyFromSystem(IntentServerSystemInterface::IpcConnection *clientIPC,
+ IntentServerRequest *irs)
+{
+ reinterpret_cast<IntentServerIpcConnection *>(clientIPC)->replyFromSystem(irs);
+}
+
+
+// ^^^ IntentServerAMImplementation ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentClientAMImplementation vvv
+
+
+IntentClientAMImplementation::IntentClientAMImplementation(IntentServerAMImplementation *serverInterface)
+ : IntentClientSystemInterface()
+ , m_issi(serverInterface)
+{
+ serverInterface->setIntentClientSystemInterface(this);
+}
+
+void IntentClientAMImplementation::initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false)
+{
+ IntentClientSystemInterface::initialize(intentClient);
+}
+
+void IntentClientAMImplementation::requestToSystem(IntentClientRequest *icr)
+{
+ IntentServerRequest *isr = m_issi->requestToSystem(icr->requestingApplicationId(), icr->intentId(),
+ icr->applicationId(), icr->parameters());
+
+ QUuid requestId = isr ? isr->id() : QUuid();
+
+ QTimer::singleShot(0, m_ic, [icr, requestId, this]() {
+ emit requestToSystemFinished(icr, requestId, requestId.isNull(),
+ requestId.isNull() ? qSL("Failed") : QString());
+ });
+}
+
+void IntentClientAMImplementation::replyFromApplication(IntentClientRequest *icr)
+{
+ emit m_issi->replyFromApplication(icr->applicationId(), icr->requestId(), !icr->succeeded(),
+ icr->result());
+}
+
+
+// ^^^ IntentClientAMImplementation ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentServerIpcConnection vvv
+
+
+QList<IntentServerIpcConnection *> IntentServerIpcConnection::s_allPeers;
+
+IntentServerIpcConnection::IntentServerIpcConnection(bool inProcess, Application *application,
+ IntentServerAMImplementation *iface)
+ : QObject()
+ , m_application(application)
+ , m_interface(iface)
+ , m_inprocess(inProcess)
+{
+ connect(this, &IntentServerIpcConnection::applicationIsReady,
+ m_interface, &IntentServerSystemInterface::applicationWasStarted);
+}
+
+IntentServerIpcConnection::~IntentServerIpcConnection()
+{ }
+
+bool IntentServerIpcConnection::isReady() const
+{
+ return m_ready;
+}
+
+void IntentServerIpcConnection::setReady(Application *application)
+{
+ if (m_ready)
+ return;
+ m_application = application;
+ m_ready = true;
+ emit applicationIsReady(application->id());
+}
+
+IntentServerIpcConnection *IntentServerIpcConnection::find(const QString &appId)
+{
+ for (auto peer : qAsConst(s_allPeers)) {
+ if (peer->m_application->id() == appId)
+ return peer;
+ }
+ return nullptr;
+}
+
+
+Application *IntentServerIpcConnection::application() const
+{
+ return m_application;
+}
+
+bool IntentServerIpcConnection::isInProcess() const
+{
+ return m_inprocess;
+}
+
+
+// ^^^ IntentServerIpcConnection ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentServerInProcessIpcConnection vvv
+
+
+IntentServerInProcessIpcConnection::IntentServerInProcessIpcConnection(Application *application,
+ IntentServerAMImplementation *iface)
+ : IntentServerIpcConnection(true /*inProcess*/, application, iface)
+{ }
+
+IntentServerInProcessIpcConnection::~IntentServerInProcessIpcConnection()
+{ }
+
+IntentServerInProcessIpcConnection *IntentServerInProcessIpcConnection::create(Application *application,
+ IntentServerAMImplementation *iface)
+{
+ auto peer = new IntentServerInProcessIpcConnection(application, iface);
+ QTimer::singleShot(0, peer, [peer, application]() { peer->setReady(application); });
+ s_allPeers << peer;
+ return peer;
+}
+
+void IntentServerInProcessIpcConnection::requestToApplication(IntentServerRequest *irs)
+{
+ // we need decouple the server/client interface at this point to have a consistent
+ // behavior in single- and multi-process mode
+ QTimer::singleShot(0, this, [this, irs]() {
+ auto clientInterface = m_interface->intentClientSystemInterface();
+ emit clientInterface->requestToApplication(irs->id().toString(), irs->intent()->id(),
+ irs->intent()->applicationId(), irs->parameters());
+ });
+}
+
+void IntentServerInProcessIpcConnection::replyFromSystem(IntentServerRequest *irs)
+{
+ // we need decouple the server/client interface at this point to have a consistent
+ // behavior in single- and multi-process mode
+ QTimer::singleShot(0, this, [this, irs]() {
+ auto clientInterface = m_interface->intentClientSystemInterface();
+ emit clientInterface->replyFromSystem(irs->id().toString(), !irs->hasSucceeded(), irs->result());
+ });
+}
+
+
+// ^^^ IntentServerInProcessIpcConnection ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentServerDBusIpcConnection vvv
+
+#if defined(AM_MULTI_PROCESS)
+
+IntentServerDBusIpcConnection::IntentServerDBusIpcConnection(QDBusConnection connection,
+ Application *application,
+ IntentServerAMImplementation *iface)
+ : IntentServerIpcConnection(false /*!inProcess*/, application, iface)
+{
+ m_connectionName = connection.name();
+ m_adaptor = new IntentInterfaceAdaptor(this);
+ connection.registerObject(qSL("/IntentManager"), this, QDBusConnection::ExportAdaptors);
+}
+
+IntentServerDBusIpcConnection::~IntentServerDBusIpcConnection()
+{
+ QDBusConnection(m_connectionName).unregisterObject(qSL("/IntentManager"));
+ s_allPeers.removeOne(this);
+}
+
+IntentServerDBusIpcConnection *IntentServerDBusIpcConnection::create(QDBusConnection connection,
+ Application *application,
+ IntentServerAMImplementation *iface)
+{
+ auto peer = new IntentServerDBusIpcConnection(connection, application, iface);
+ s_allPeers << peer;
+ return peer;
+}
+
+IntentServerDBusIpcConnection *IntentServerDBusIpcConnection::find(QDBusConnection connection)
+{
+ QString connectionName = connection.name();
+
+ for (auto peer : qAsConst(s_allPeers)) {
+ if (peer->isInProcess())
+ continue;
+ auto dbusPeer = static_cast<IntentServerDBusIpcConnection *>(peer);
+ if (dbusPeer->m_connectionName == connectionName)
+ return dbusPeer;
+ }
+ return nullptr;
+}
+
+void IntentServerDBusIpcConnection::requestToApplication(IntentServerRequest *irs)
+{
+ emit m_adaptor->requestToApplication(irs->id().toString(), irs->intent()->id(),
+ irs->intent()->applicationId(),
+ convertFromJSVariant(irs->parameters()).toMap());
+}
+
+void IntentServerDBusIpcConnection::replyFromSystem(IntentServerRequest *irs)
+{
+ emit m_adaptor->replyFromSystem(irs->id().toString(), !irs->hasSucceeded(),
+ convertFromJSVariant(irs->result()).toMap());
+}
+
+QString IntentServerDBusIpcConnection::requestToSystem(const QString &intentId,
+ const QString &applicationId,
+ const QVariantMap &parameters)
+{
+ auto requestingApplicationId = application() ? application()->id() : QString();
+ auto irs = m_interface->requestToSystem(requestingApplicationId, intentId, applicationId,
+ convertFromDBusVariant(parameters).toMap());
+ return irs ? irs->id().toString() : QString();
+}
+
+void IntentServerDBusIpcConnection::replyFromApplication(const QString &requestId, bool error,
+ const QVariantMap &result)
+{
+ emit m_interface->replyFromApplication(application()->id(), requestId, error,
+ convertFromDBusVariant(result).toMap());
+}
+
+#endif // defined(AM_MULTI_PROCESS)
+
+QT_END_NAMESPACE_AM
+
+
+// ^^^ IntentServerDBusIpcConnection ^^^
+//////////////////////////////////////////////////////////////////////////
+// vvv IntentInterfaceAdaptor vvv
+
+#if defined(AM_MULTI_PROCESS)
+
+IntentInterfaceAdaptor::IntentInterfaceAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{ }
+
+IntentInterfaceAdaptor::~IntentInterfaceAdaptor()
+{ }
+
+void IntentInterfaceAdaptor::replyFromApplication(const QString &requestId, bool error,
+ const QVariantMap &result)
+{
+ auto peer = static_cast<QtAM::IntentServerDBusIpcConnection *>(parent());
+ peer->replyFromApplication(requestId, error, result);
+}
+
+QString IntentInterfaceAdaptor::requestToSystem(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters)
+{
+ auto peer = static_cast<QtAM::IntentServerDBusIpcConnection *>(parent());
+ return peer->requestToSystem(intentId, applicationId, parameters);
+}
+
+#endif // defined(AM_MULTI_PROCESS)
+
+// ^^^ IntentInterfaceAdaptor ^^^
+//////////////////////////////////////////////////////////////////////////
diff --git a/src/manager-lib/intentaminterface.h b/src/manager-lib/intentaminterface.h
new file mode 100644
index 00000000..fd590670
--- /dev/null
+++ b/src/manager-lib/intentaminterface.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QVector>
+#include <QString>
+#include <QVariantMap>
+#include <QList>
+#if defined(AM_MULTI_PROCESS)
+# include <QDBusConnection>
+# include <QDBusContext>
+#endif
+#include <QtAppManCommon/global.h>
+#include <QtAppManIntentServer/intentserversysteminterface.h>
+#include <QtAppManIntentClient/intentclientsysteminterface.h>
+
+class IntentInterfaceAdaptor;
+
+QT_BEGIN_NAMESPACE_AM
+
+class Application;
+class IntentServerRequest;
+
+namespace IntentAMImplementation {
+IntentServer *createIntentServerAndClientInstance();
+}
+
+// the server side
+class IntentServerAMImplementation : public IntentServerSystemInterface
+{
+ Q_OBJECT
+
+public:
+ void setIntentClientSystemInterface(IntentClientSystemInterface *iface);
+ IntentClientSystemInterface *intentClientSystemInterface() const;
+
+ void initialize(IntentServer *intentManager) override;
+
+ bool checkApplicationCapabilities(const QString &applicationId,
+ const QStringList &requiredCapabilities) override;
+
+ IpcConnection *findClientIpc(const QString &appId) override;
+
+ void startApplication(const QString &appId) override;
+ void requestToApplication(IpcConnection *clientIPC, IntentServerRequest *irs) override;
+ void replyFromSystem(IpcConnection *clientIPC, IntentServerRequest *irs) override;
+
+private:
+ IntentClientSystemInterface *m_icsi = nullptr;
+};
+
+// the in-process client side
+class IntentClientAMImplementation : public IntentClientSystemInterface
+{
+public:
+ IntentClientAMImplementation(IntentServerAMImplementation *serverInterface);
+
+ void initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false) override;
+
+ void requestToSystem(IntentClientRequest *icr) override;
+ void replyFromApplication(IntentClientRequest *icr) override;
+
+private:
+ IntentServerSystemInterface *m_issi;
+};
+
+// each instance represents one server->client connection
+class IntentServerIpcConnection : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~IntentServerIpcConnection() override;
+
+ static IntentServerIpcConnection *find(const QString &appId);
+
+ Application *application() const;
+ bool isInProcess() const;
+
+ bool isReady() const;
+ void setReady(Application *application);
+
+ virtual void replyFromSystem(IntentServerRequest *irs) = 0;
+ virtual void requestToApplication(IntentServerRequest *irs) = 0;
+
+signals:
+ void applicationIsReady(const QString &applicationId);
+
+protected:
+ IntentServerIpcConnection(bool inProcess, Application *application, IntentServerAMImplementation *iface);
+
+ Application *m_application;
+ IntentServerAMImplementation *m_interface;
+ bool m_inprocess = true;
+ bool m_ready = false;
+
+ static QList<IntentServerIpcConnection *> s_allPeers;
+};
+
+// ... derived for in-process clients
+class IntentServerInProcessIpcConnection : public IntentServerIpcConnection
+{
+ Q_OBJECT
+
+public:
+ static IntentServerInProcessIpcConnection *create(Application *application, IntentServerAMImplementation *iface);
+
+ ~IntentServerInProcessIpcConnection() override;
+
+ void replyFromSystem(IntentServerRequest *irs) override;
+ void requestToApplication(IntentServerRequest *irs) override;
+
+private:
+ IntentServerInProcessIpcConnection(Application *application, IntentServerAMImplementation *iface);
+};
+
+#if defined(AM_MULTI_PROCESS)
+
+// ... derived for P2P DBus clients
+class IntentServerDBusIpcConnection : public IntentServerIpcConnection, public QDBusContext
+{
+ Q_OBJECT
+
+public:
+ static IntentServerDBusIpcConnection *create(QDBusConnection connection, Application *application,
+ IntentServerAMImplementation *iface);
+ static IntentServerDBusIpcConnection *find(QDBusConnection connection);
+
+ ~IntentServerDBusIpcConnection() override;
+
+ QString requestToSystem(const QString &intentId, const QString &applicationId, const QVariantMap &parameters);
+ void replyFromSystem(IntentServerRequest *irs) override;
+ void requestToApplication(IntentServerRequest *irs) override;
+ void replyFromApplication(const QString &requestId, bool error, const QVariantMap &result);
+
+
+private:
+ IntentServerDBusIpcConnection(QDBusConnection connection, Application *application,
+ IntentServerAMImplementation *iface);
+
+ QString m_connectionName;
+ ::IntentInterfaceAdaptor *m_adaptor = nullptr;
+};
+
+#endif // defined(AM_MULTI_PROCESS)
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/manager-lib.pro b/src/manager-lib/manager-lib.pro
index 1eeb00ed..ccc7ab7b 100644
--- a/src/manager-lib/manager-lib.pro
+++ b/src/manager-lib/manager-lib.pro
@@ -6,17 +6,33 @@ load(am-config)
QT = core network qml
!headless:QT *= gui gui-private quick qml-private quick-private
-qtHaveModule(dbus):QT *= dbus
QT_FOR_PRIVATE *= \
appman_common-private \
appman_application-private \
appman_notification-private \
appman_plugininterfaces-private \
+ appman_intent_server-private \
+ appman_intent_client-private \
CONFIG *= static internal_module
multi-process {
- LIBS += -ldl
+ QT *= dbus
+ LIBS *= -ldl
+
+ HEADERS += \
+ nativeruntime.h \
+ nativeruntime_p.h \
+ processcontainer.h \
+
+ SOURCES += \
+ nativeruntime.cpp \
+ processcontainer.cpp \
+
+ CONFIG = dbus-adaptors-xml $$CONFIG
+
+ ADAPTORS_XML = \
+ ../dbus-lib/io.qt.applicationmanager.intentinterface.xml
}
HEADERS += \
@@ -38,6 +54,7 @@ HEADERS += \
systemreader.h \
debugwrapper.h \
amnamespace.h \
+ intentaminterface.h
linux:HEADERS += \
sysfsreader.h \
@@ -46,11 +63,6 @@ linux:HEADERS += \
fakeapplicationmanagerwindow.h \
inprocesssurfaceitem.h
-multi-process:HEADERS += \
- nativeruntime.h \
- nativeruntime_p.h \
- processcontainer.h \
-
qtHaveModule(qml):HEADERS += \
qmlinprocessruntime.h \
qmlinprocessapplicationinterface.h \
@@ -71,6 +83,7 @@ SOURCES += \
applicationipcinterface.cpp \
systemreader.cpp \
debugwrapper.cpp \
+ intentaminterface.cpp
linux:SOURCES += \
sysfsreader.cpp \
@@ -79,10 +92,6 @@ linux:SOURCES += \
fakeapplicationmanagerwindow.cpp \
inprocesssurfaceitem.cpp
-multi-process:SOURCES += \
- nativeruntime.cpp \
- processcontainer.cpp \
-
qtHaveModule(qml):SOURCES += \
qmlinprocessruntime.cpp \
qmlinprocessapplicationinterface.cpp \
diff --git a/src/manager-lib/qmlinprocessapplicationinterface.cpp b/src/manager-lib/qmlinprocessapplicationinterface.cpp
index cd9a4d93..38bf8b23 100644
--- a/src/manager-lib/qmlinprocessapplicationinterface.cpp
+++ b/src/manager-lib/qmlinprocessapplicationinterface.cpp
@@ -50,6 +50,7 @@
#include "notificationmanager.h"
#include "applicationipcmanager.h"
#include "applicationipcinterface.h"
+#include "intentclientrequest.h"
QT_BEGIN_NAMESPACE_AM
@@ -112,6 +113,21 @@ QVariantMap QmlInProcessApplicationInterface::applicationProperties() const
return QVariantMap();
}
+IntentClientRequest *QmlInProcessApplicationInterface::createIntentRequest(const QString &intentId,
+ const QVariantMap &parameters)
+{
+ return createIntentRequest(intentId, QString(), parameters);
+}
+
+IntentClientRequest *QmlInProcessApplicationInterface::createIntentRequest(const QString &intentId,
+ const QString &applicationId,
+ const QVariantMap &parameters)
+{
+ auto req = IntentClientRequest::create(this->applicationId(), intentId, applicationId, parameters);
+ QQmlEngine::setObjectOwnership(req, QQmlEngine::CppOwnership);
+ return req;
+}
+
void QmlInProcessApplicationInterface::acknowledgeQuit()
{
emit quitAcknowledged();
diff --git a/src/manager-lib/qmlinprocessapplicationinterface.h b/src/manager-lib/qmlinprocessapplicationinterface.h
index 5f5b0c7d..72154e4b 100644
--- a/src/manager-lib/qmlinprocessapplicationinterface.h
+++ b/src/manager-lib/qmlinprocessapplicationinterface.h
@@ -51,6 +51,7 @@
QT_BEGIN_NAMESPACE_AM
class QmlInProcessRuntime;
+class IntentClientRequest;
class QmlInProcessNotification : public Notification // clazy:exclude=missing-qobject-macro
{
@@ -90,6 +91,8 @@ public:
QVariantMap applicationProperties() const override;
Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Notification *) createNotification();
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(IntentClientRequest *) createIntentRequest(const QString &intentId, const QVariantMap &parameters);
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(IntentClientRequest *) createIntentRequest(const QString &intentId, const QString &applicationId, const QVariantMap &parameters);
Q_INVOKABLE void acknowledgeQuit();
void finishedInitialization() override;
diff --git a/src/src.pro b/src/src.pro
index 6cef2941..67c1008d 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -20,7 +20,7 @@ package_lib.subdir = package-lib
package_lib.depends = crypto_lib application_lib
manager_lib.subdir = manager-lib
-manager_lib.depends = application_lib notification_lib plugin_interfaces
+manager_lib.depends = application_lib notification_lib intent_server_lib intent_client_lib plugin_interfaces
installer_lib.subdir = installer-lib
installer_lib.depends = package_lib manager_lib
@@ -34,8 +34,14 @@ monitor_lib.depends = manager_lib window_lib
shared_main_lib.subdir = shared-main-lib
shared_main_lib.depends = common_lib
+intent_server_lib.subdir = intent-server-lib
+intent_server_lib.depends = common_lib
+
+intent_client_lib.subdir = intent-client-lib
+intent_client_lib.depends = common_lib
+
launcher_lib.subdir = launcher-lib
-launcher_lib.depends = application_lib notification_lib shared_main_lib
+launcher_lib.depends = application_lib notification_lib shared_main_lib intent_client_lib
main_lib.subdir = main-lib
main_lib.depends = shared_main_lib manager_lib installer_lib window_lib monitor_lib
@@ -85,6 +91,8 @@ SUBDIRS = \
window_lib \
monitor_lib \
shared_main_lib \
+ intent_server_lib \
+ intent_client_lib \
main_lib \
tools_appman \
# Although the testrunner is in tools we don't want to build it with tools-only
diff --git a/sync.profile b/sync.profile
index 16369812..142d3f44 100644
--- a/sync.profile
+++ b/sync.profile
@@ -13,6 +13,8 @@
"QtAppManPluginInterfaces" => "$basedir/src/plugin-interfaces",
"QtAppManMonitor" => "$basedir/src/monitor-lib",
"QtAppManDBus" => "$basedir/src/dbus-lib",
+ "QtAppManIntentServer" => "$basedir/src/intent-server-lib",
+ "QtAppManIntentClient" => "$basedir/src/intent-client-lib",
);
%moduleheaders = ( # restrict the module headers to those found in relative path
);