summaryrefslogtreecommitdiffstats
path: root/app/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'app/main.cpp')
-rw-r--r--app/main.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/app/main.cpp b/app/main.cpp
new file mode 100644
index 0000000..669341e
--- /dev/null
+++ b/app/main.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QtCore/QDebug>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QUrlQuery>
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlApplicationEngine>
+#include <QtQml/QQmlContext>
+#include <QtQml/qqml.h>
+#include <QQuickWindow>
+#include <QtQuickControls2/QQuickStyle>
+
+#include <json-c/json.h>
+#include <qlibwindowmanager.h>
+#include <qlibhomescreen.h>
+#include <guimetadata.h>
+#include "afbclient.h"
+#include <iostream>
+
+// Disable window activation at launch by default, but keep option
+// for potential debug use.
+#define HIDE_AT_LAUNCH
+
+bool check_template_supported(json_object *data)
+{
+ json_object *jtype = NULL;
+ json_object_object_get_ex(data, "type", &jtype);
+ if(!jtype) {
+ qWarning("render_template event missing type element");
+ return false;
+ }
+ const char *type_value = json_object_get_string(jtype);
+ if(!type_value) {
+ qWarning("render_template event type element not parsed");
+ return false;
+ }
+ // We only handle BodyTemplate[12] and WeatherTemplate, ignore
+ // others
+ if(!(strcmp(type_value, "BodyTemplate1") &&
+ strcmp(type_value, "BodyTemplate2") &&
+ strcmp(type_value, "WeatherTemplate")))
+ return true;
+
+ return false;
+}
+
+void async_event_cb(const char *event, json_object *data, void *closure)
+{
+ if(!data)
+ return;
+
+ if(!strcmp(event, "vshl-capabilities/setDestination")) {
+ // Slight hack here, there's currently no convenient place to hook up raising
+ // the navigation app when a route is set by Alexa, so do so here for now.
+ if(closure != nullptr) {
+ static_cast<QLibHomeScreen*>(closure)->showWindow("navigation", "normal");
+ }
+ } else if(!strcmp(event, "vshl-capabilities/render_template")) {
+ // Raise ourselves, the UI code will receive the event as well and render it
+ if(closure != nullptr) {
+ if(!check_template_supported(data)) {
+ qDebug() << "Unsupported template type, ignoring!";
+ return;
+ }
+ static_cast<QLibHomeScreen*>(closure)->showWindow("alexa-viewer", "on_screen");
+ }
+ } else if(!strcmp(event, "vshl-capabilities/clear_template")) {
+ // Hide ourselves
+ if(closure != nullptr) {
+ static_cast<QLibHomeScreen*>(closure)->hideWindow("alexa-viewer");
+ }
+ }
+}
+
+void subscribe_async_events(AfbClient &client)
+{
+ const char *vshl_capabilities_nav_events[] = {
+ "setDestination",
+ NULL,
+ };
+ const char **tmp = vshl_capabilities_nav_events;
+ json_object *args = json_object_new_object();
+ json_object *actions = json_object_new_array();
+ while (*tmp) {
+ json_object_array_add(actions, json_object_new_string(*tmp++));
+ }
+ json_object_object_add(args, "actions", actions);
+ if(json_object_array_length(actions)) {
+ client.subscribe("vshl-capabilities", args, "navigation/subscribe");
+ } else {
+ json_object_put(args);
+ }
+
+ // NOTE: Not subscribing to "clear_template", as it will be passed to
+ // the app QML to handle by the libqtappfw wrapper.
+ const char *vshl_capabilities_guimetadata_events[] = {
+ "render_template",
+ NULL,
+ };
+ tmp = vshl_capabilities_guimetadata_events;
+ args = json_object_new_object();
+ actions = json_object_new_array();
+ while (*tmp) {
+ json_object_array_add(actions, json_object_new_string(*tmp++));
+ }
+ json_object_object_add(args, "actions", actions);
+ if(json_object_array_length(actions)) {
+ client.subscribe("vshl-capabilities", args, "guimetadata/subscribe");
+ } else {
+ json_object_put(args);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ QString graphic_role = QString("on_screen");
+
+ QGuiApplication app(argc, argv);
+
+ QCommandLineParser parser;
+ parser.addPositionalArgument("port", app.translate("main", "port for binding"));
+ parser.addPositionalArgument("secret", app.translate("main", "secret for binding"));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.process(app);
+ QStringList positionalArguments = parser.positionalArguments();
+ QUrl bindingAddress;
+
+ int port = 0;
+ QString token;
+ if (positionalArguments.length() == 2) {
+ port = positionalArguments.takeFirst().toInt();
+ token = positionalArguments.takeFirst();
+ bindingAddress.setScheme(QStringLiteral("ws"));
+ bindingAddress.setHost(QStringLiteral("localhost"));
+ bindingAddress.setPort(port);
+ bindingAddress.setPath(QStringLiteral("/api"));
+ QUrlQuery query;
+ query.addQueryItem(QStringLiteral("token"), token);
+ bindingAddress.setQuery(query);
+ }
+
+ // QLibWM
+ QLibWindowmanager* qwmHandler = new QLibWindowmanager();
+ int res;
+ if((res = qwmHandler->init(port, token)) != 0){
+ qCritical("init qlibwm err(%d)", res);
+ return -1;
+ }
+ if((res = qwmHandler->requestSurface(graphic_role)) != 0) {
+ qCritical("requestSurface error(%d)", res);
+ return -1;
+ }
+ qwmHandler->set_event_handler(QLibWindowmanager::Event_SyncDraw,
+ [qwmHandler, &graphic_role](json_object *object) {
+ qwmHandler->endDraw(graphic_role);
+ });
+
+ // QLibHS
+ QLibHomeScreen* qhsHandler = new QLibHomeScreen();
+ qhsHandler->init(port, token.toStdString().c_str());
+ qhsHandler->set_event_handler(QLibHomeScreen::Event_ShowWindow,
+ [qwmHandler, &graphic_role](json_object *object){
+ qDebug("Surface %s got showWindow\n", graphic_role.toStdString().c_str());
+ qwmHandler->activateWindow(graphic_role, "on_screen");
+ });
+ qhsHandler->set_event_handler(QLibHomeScreen::Event_HideWindow,
+ [qwmHandler, &graphic_role](json_object *object){
+ qDebug("Surface %s got hideWindow\n", graphic_role.toStdString().c_str());
+ qwmHandler->deactivateWindow(graphic_role);
+ });
+
+ // Load qml
+ QQmlApplicationEngine engine;
+ QQmlContext *context = engine.rootContext();
+
+ context->setContextProperty("homescreen", qhsHandler);
+ context->setContextProperty("GuiMetadata", new GuiMetadata(bindingAddress, context));
+ engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));
+
+#ifndef HIDE_AT_LAUNCH
+ QObject *root = engine.rootObjects().first();
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
+ QObject::connect(window, SIGNAL(frameSwapped()), qwmHandler, SLOT(slotActivateWindow()));
+#endif
+ // Create app framework client to handle events when window is not visible
+ AfbClient client(port, token.toStdString());
+ client.set_event_callback(async_event_cb, (void*) qhsHandler);
+ subscribe_async_events(client);
+
+ return app.exec();
+}