summaryrefslogtreecommitdiffstats
path: root/voice-capabilities/guimetadata.h
blob: ae90cbaf2d18e4c841a365c8603e2ecd72820424 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * 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.
 */

#ifndef GUIMETADATA_H
#define GUIMETADATA_H

#include <QObject>
#include <QtQml/QQmlContext>

class MessageEngine;
class Message;

enum class MessageType;

class GuiMetadata : public QObject
{
	Q_OBJECT

	// Common to all template types
	Q_PROPERTY(QString type READ type)
	Q_PROPERTY(QString title READ title)
	Q_PROPERTY(QString subtitle READ subtitle)

	// BodyTemplate1/2
	Q_PROPERTY(QString bodyText READ bodyText)

	// BodyTemplate2
	Q_PROPERTY(QUrl bodyImageSmallUrl READ bodyImageSmallUrl)
	Q_PROPERTY(QUrl bodyImageMediumUrl READ bodyImageMediumUrl)
	Q_PROPERTY(QUrl bodyImageLargeUrl READ bodyImageLargeUrl)

	// WeatherTemplate
	Q_PROPERTY(QString weatherCurrentTemperature READ weatherCurrentTemperature)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconSmallUrl READ weatherCurrentWeatherIconSmallUrl)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconSmallDarkBgUrl READ weatherCurrentWeatherIconSmallDarkBgUrl)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconMediumUrl READ weatherCurrentWeatherIconMediumUrl)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconMediumDarkBgUrl READ weatherCurrentWeatherIconMediumDarkBgUrl)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconLargeUrl READ weatherCurrentWeatherIconLargeUrl)
	Q_PROPERTY(QUrl weatherCurrentWeatherIconLargeDarkBgUrl READ weatherCurrentWeatherIconLargeDarkBgUrl)

	Q_PROPERTY(QString weatherLowTemperature READ weatherLowTemperature)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowSmallUrl READ weatherLowTemperatureArrowSmallUrl)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowSmallDarkBgUrl READ weatherLowTemperatureArrowSmallDarkBgUrl)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowMediumUrl READ weatherLowTemperatureArrowMediumUrl)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowMediumDarkBgUrl READ weatherLowTemperatureArrowMediumDarkBgUrl)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowLargeUrl READ weatherLowTemperatureArrowLargeUrl)
	Q_PROPERTY(QUrl weatherLowTemperatureArrowLargeDarkBgUrl READ weatherLowTemperatureArrowLargeDarkBgUrl)

	Q_PROPERTY(QString weatherHighTemperature READ weatherHighTemperature)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowSmallUrl READ weatherHighTemperatureArrowSmallUrl)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowSmallDarkBgUrl READ weatherHighTemperatureArrowSmallDarkBgUrl)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowMediumUrl READ weatherHighTemperatureArrowMediumUrl)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowMediumDarkBgUrl READ weatherHighTemperatureArrowMediumDarkBgUrl)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowLargeUrl READ weatherHighTemperatureArrowLargeUrl)
	Q_PROPERTY(QUrl weatherHighTemperatureArrowLargeDarkBgUrl READ weatherHighTemperatureArrowLargeDarkBgUrl)
	// weatherForecast array ignored for now

public:
	explicit GuiMetadata(QUrl &url, QQmlContext *context, QObject * parent = Q_NULLPTR);
	virtual ~GuiMetadata();

	QString type() { return m_type; }
	QString title() { return m_title; }
	QString subtitle() { return m_subtitle; }

	// BodyTemplate1/2
	QString bodyText() { return m_bodyText; }

	// BodyTemplate2
	QUrl bodyImageSmallUrl() { return m_bodyImageSmallUrl; }
	QUrl bodyImageMediumUrl() { return m_bodyImageMediumUrl; }
	QUrl bodyImageLargeUrl() { return m_bodyImageLargeUrl; }

	// WeatherTemplate
	QString weatherCurrentTemperature() { return m_weatherCurrentTemperature; }
	QUrl weatherCurrentWeatherIconSmallUrl() { return m_weatherCurrentWeatherIconSmallUrl; }
	QUrl weatherCurrentWeatherIconSmallDarkBgUrl() { return m_weatherCurrentWeatherIconSmallDarkBgUrl; }
	QUrl weatherCurrentWeatherIconMediumUrl() { return m_weatherCurrentWeatherIconMediumUrl; }
	QUrl weatherCurrentWeatherIconMediumDarkBgUrl() { return m_weatherCurrentWeatherIconMediumDarkBgUrl; }
	QUrl weatherCurrentWeatherIconLargeUrl() { return m_weatherCurrentWeatherIconLargeUrl; }
	QUrl weatherCurrentWeatherIconLargeDarkBgUrl() { return m_weatherCurrentWeatherIconLargeDarkBgUrl; }

	QString weatherLowTemperature() { return m_weatherLowTemperature; }
	QUrl weatherLowTemperatureArrowSmallUrl() { return m_weatherLowTemperatureArrowSmallUrl; }
	QUrl weatherLowTemperatureArrowSmallDarkBgUrl() { return m_weatherLowTemperatureArrowSmallDarkBgUrl; }
	QUrl weatherLowTemperatureArrowMediumUrl() { return m_weatherLowTemperatureArrowMediumUrl; }
	QUrl weatherLowTemperatureArrowMediumDarkBgUrl() { return m_weatherLowTemperatureArrowMediumDarkBgUrl; }
	QUrl weatherLowTemperatureArrowLargeUrl() { return m_weatherLowTemperatureArrowLargeUrl; }
	QUrl weatherLowTemperatureArrowLargeDarkBgUrl() { return m_weatherLowTemperatureArrowLargeDarkBgUrl; }

	QString weatherHighTemperature() { return m_weatherHighTemperature; }
	QUrl weatherHighTemperatureArrowSmallUrl() { return m_weatherHighTemperatureArrowSmallUrl; }
	QUrl weatherHighTemperatureArrowSmallDarkBgUrl() { return m_weatherHighTemperatureArrowSmallDarkBgUrl; }
	QUrl weatherHighTemperatureArrowMediumUrl() { return m_weatherHighTemperatureArrowMediumUrl; }
	QUrl weatherHighTemperatureArrowMediumDarkBgUrl() { return m_weatherHighTemperatureArrowMediumDarkBgUrl; }
	QUrl weatherHighTemperatureArrowLargeUrl() { return m_weatherHighTemperatureArrowLargeUrl; }
	QUrl weatherHighTemperatureArrowLargeDarkBgUrl() { return m_weatherHighTemperatureArrowLargeDarkBgUrl; }

signals:
	void renderTemplate();
	void clearTemplate();

private:
	MessageEngine *m_mloop;
	QQmlContext *m_context;

	void clearMetadata();
	bool parseImageMetadata(QJsonObject &imageObj,
				QUrl &smallUrl, QUrl &mediumUrl, QUrl &largeUrl,
				QUrl *pSmallDarkBgUrl = NULL, QUrl *pMediumDarkBgUrl = NULL, QUrl *pLargeDarkBgUrl = NULL);

	bool updateMetadata(QJsonObject data);
	bool updateBodyMetadata(QJsonObject &data);
	bool updateWeatherMetadata(QJsonObject &data);

	void onConnected();
	void onDisconnected();
	void onMessageReceived(MessageType, Message*);

	const QStringList events {
		"render_template",
		"clear_template",
	};

	QString m_type = "";
	QString m_title = "";
	QString m_subtitle = "";

	// BodyTemplate1/2
	QString m_bodyText = "";

	// BodyTemplate2
	QUrl m_bodyImageSmallUrl = QString("");
	QUrl m_bodyImageMediumUrl = QString("");
	QUrl m_bodyImageLargeUrl = QString("");

	// WeatherTemplate
	QString m_weatherCurrentTemperature = "";
	QUrl m_weatherCurrentWeatherIconSmallUrl = QString("");
	QUrl m_weatherCurrentWeatherIconSmallDarkBgUrl = QString("");
	QUrl m_weatherCurrentWeatherIconMediumUrl = QString("");
	QUrl m_weatherCurrentWeatherIconMediumDarkBgUrl = QString("");
	QUrl m_weatherCurrentWeatherIconLargeUrl = QString("");
	QUrl m_weatherCurrentWeatherIconLargeDarkBgUrl = QString("");

	QString m_weatherLowTemperature = "";
	QUrl m_weatherLowTemperatureArrowSmallUrl = QString("");
	QUrl m_weatherLowTemperatureArrowSmallDarkBgUrl = QString("");
	QUrl m_weatherLowTemperatureArrowMediumUrl = QString("");
	QUrl m_weatherLowTemperatureArrowMediumDarkBgUrl = QString("");
	QUrl m_weatherLowTemperatureArrowLargeUrl = QString("");
	QUrl m_weatherLowTemperatureArrowLargeDarkBgUrl = QString("");

	QString m_weatherHighTemperature = "";
	QUrl m_weatherHighTemperatureArrowSmallUrl = QString("");
	QUrl m_weatherHighTemperatureArrowSmallDarkBgUrl = QString("");
	QUrl m_weatherHighTemperatureArrowMediumUrl = QString("");
	QUrl m_weatherHighTemperatureArrowMediumDarkBgUrl = QString("");
	QUrl m_weatherHighTemperatureArrowLargeUrl = QString("");
	QUrl m_weatherHighTemperatureArrowLargeDarkBgUrl = QString("");
};

#endif // GUIMETADATA_H
t;, 2 * --indent, "", this->f); } }; thread_local int ScopeTrace::indent = 0; #endif /* called when wsj1 receives a method invocation */ void onCall(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg) { TRACE(); UNUSED(closure); UNUSED(verb); UNUSED(api); UNUSED(msg); } /* called when wsj1 receives an event */ void onEvent(void *closure, const char *event, afb_wsj1_msg *msg) { TRACE(); // check API name in event if (0 != strncmp(wmAPI, event, strlen(wmAPI))) { HMI_ERROR("libwm", "Unknown event: %s", event); return; } json_object *val; if (json_object_object_get_ex(afb_wsj1_msg_object_j(msg), "data", &val)) { reinterpret_cast<LibWindowmanager::Impl *>(closure)->event(event, val); } else { HMI_ERROR("libwm", "Not found key \"data\""); } } /* called when wsj1 hangsup */ void onHangup(void *closure, afb_wsj1 *wsj1) { TRACE(); UNUSED(closure); UNUSED(wsj1); HMI_ERROR("libwm", "Hangup, the WindowManager vanished"); } constexpr struct afb_wsj1_itf itf = { onHangup, onCall, onEvent, }; } // namespace /** * @class LibWindowmanager::Impl::Impl */ LibWindowmanager::Impl::Impl() : wsj1{}, loop{}, labels(), handlers() { TRACE(); } LibWindowmanager::Impl::~Impl() { TRACE(); afb_wsj1_unref(wsj1); sd_event_unref(loop); } int LibWindowmanager::Impl::init(int port, char const *token) { TRACE(); HMI_DEBUG("libwm", "called"); char *uribuf = nullptr; int rc = -1; if (this->loop != nullptr && this->wsj1 != nullptr) { HMI_ERROR("libwm", "LibWindowmanager instance is already initialized!"); rc = -EALREADY; goto fail; } if (token == nullptr) { HMI_ERROR("libwm", "Token is invalid"); rc = -EINVAL; goto fail; } if (port < 1 || port > 0xffff) { HMI_ERROR("libwm", "Port is invalid"); rc = -EINVAL; goto fail; } /* get the default event loop */ rc = sd_event_default(&this->loop); if (rc < 0) { HMI_ERROR("libwm", "Connection to default event loop failed: %s", strerror(-rc)); goto fail; } asprintf(&uribuf, "ws://localhost:%d/api?token=%s", port, token); /* connect the websocket wsj1 to the uri given by the first argument */ this->wsj1 = afb_ws_client_connect_wsj1( this->loop, uribuf, const_cast<struct afb_wsj1_itf *>(&itf), this); if (this->wsj1 == nullptr) { sd_event_unref(this->loop); this->loop = nullptr; HMI_ERROR("libwm", "Connection to %s failed: %m", uribuf); rc = -errno; goto fail; } this->runEventLoop(); return 0; fail: return rc; } int LibWindowmanager::Impl::requestSurface(json_object *object) { TRACE(); HMI_DEBUG("libwm", "called"); json_object *val; const char *tmp_label; if (json_object_object_get_ex(object, this->kKeyDrawingName, &val)) { tmp_label = json_object_get_string(val); } else { HMI_DEBUG("libwm", "Not found key \"%s\"", this->kKeyDrawingName); return -EINVAL; } // DrawingName in "object" is overwrited in api_call("RequestSurface") // So it is neccesary to copy it. const char *label = std::string(tmp_label).c_str(); if (this->labels.find(label) != this->labels.end()) { HMI_ERROR("libwm", "Surface label already known!"); return -EINVAL; } // Store application name first // because it may not return from setenv HMI_DEBUG("libwm", "Insert application name: %s\n", label); this->labels.insert(this->labels.end(), label); int rc = -1; /* send the request */ int rc2 = this->api_call("RequestSurface", object, [&rc](bool ok, json_object *j) { if (ok) { json_object *val; if (json_object_object_get_ex(j, "response", &val)) { rc = json_object_get_int(val); } else { HMI_ERROR("libwm", "Not found key \"response\""); rc = -EINVAL; return; } } else { HMI_ERROR("libwm", "Could not get surface ID from WM: %s", j != nullptr ? json_object_to_json_string_ext( j, JSON_C_TO_STRING_PRETTY) : "no-info"); rc = -EINVAL; } }); if (rc2 < 0) { rc = rc2; } if (rc < 0) { HMI_ERROR("libwm", "Erase application name: %s", label); this->labels.erase(label); } return rc; } int LibWindowmanager::Impl::requestSurfaceXDG(json_object *object) { TRACE(); HMI_DEBUG("libwm", "called"); json_object *val; const char *tmp_label; if (json_object_object_get_ex(object, this->kKeyDrawingName, &val)) { tmp_label = json_object_get_string(val); } else { HMI_DEBUG("libwm", "Not found key \"%s\"", this->kKeyDrawingName); return -EINVAL; } // DrawingName in "object" is overwrited in api_call("RequestSurface") // So it is neccesary to copy it. const char *label = std::string(tmp_label).c_str(); if (this->labels.find(label) != this->labels.end()) { HMI_ERROR("libwm", "Surface label already known!"); return -EINVAL; } // Store application name first // because it may not return from setenv HMI_DEBUG("libwm", "Insert application name: %s\n", label); this->labels.insert(this->labels.end(), label); /* send the request */ int rc = this->api_call("RequestSurfaceXDG", object, [](bool ok, json_object *j) { if (!ok) { HMI_ERROR("libwm", "Could not get surface ID from WM: %s", j != nullptr ? json_object_to_json_string_ext( j, JSON_C_TO_STRING_PRETTY) : "no-info"); } }); if (rc != 0) { HMI_ERROR("libwm", "Erase application name: %s", label); this->labels.erase(label); } return rc; } int LibWindowmanager::Impl::activateSurface(json_object *object) { TRACE(); HMI_DEBUG("libwm", "called"); return this->api_call("ActivateSurface", object, [](bool ok, json_object *j) { if (!ok) { HMI_ERROR("libwm", "API Call activate_surface() failed: %s", j != nullptr ? json_object_to_json_string_ext( j, JSON_C_TO_STRING_PRETTY) : "no-info"); } }); } int LibWindowmanager::Impl::deactivateSurface(json_object *object) { TRACE(); HMI_DEBUG("libwm", "called"); return this->api_call("DeactivateSurface", object, [](bool ok, json_object *j) { if (!ok) { HMI_ERROR("libwm", "API Call deactivate_surface() failed: %s", j != nullptr ? json_object_to_json_string_ext( j, JSON_C_TO_STRING_PRETTY) : "no-info"); } }); } int LibWindowmanager::Impl::endDraw(json_object *object) { TRACE(); HMI_DEBUG("libwm", "called"); return this->api_call("EndDraw", object, [](bool ok, json_object *j) { if (!ok) { HMI_ERROR("libwm", "API Call endDraw() failed: %s", j != nullptr ? json_object_to_json_string_ext( j, JSON_C_TO_STRING_PRETTY) : "no-info"); } }); } static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg) { } void LibWindowmanager::Impl::set_event_handler(enum EventType et, handler_fun func) { TRACE(); HMI_DEBUG("libwm", "called"); // Subscribe event struct json_object* j = json_object_new_object(); json_object_object_add(j, "event", json_object_new_int(et)); int ret = afb_wsj1_call_j(this->wsj1, wmAPI, "wm_subscribe", j, _on_reply_static, this); if (0 > ret) { HMI_ERROR("libwm", "Failed to subscribe event: %s", kListEventName[et].c_str()); } // Set event handler if (et >= Event_Active && et <= Event_FlushDraw) { this->handlers[et] = std::move(func); } } namespace { std::pair<bool, LibWindowmanager::EventType> make_event_type(char const *et) { // Event have the form "$API/$EVENT", just try to find the first / and // get on with it. char const *et2 = strchr(et, '/'); if (et2 != nullptr) { et = et2 + 1; } #define ET(N, A) \ do { \ if (strcasecmp(et, N) == 0) \ return std::pair<bool, LibWindowmanager::EventType>( \ true, CONCAT(LibWindowmanager::Event_, A)); \ } while (false) ET("active", Active); ET("inactive", Inactive); ET("visible", Visible); ET("invisible", Invisible); ET("syncdraw", SyncDraw); ET("flushdraw", FlushDraw); #undef ET return std::pair<bool, LibWindowmanager::EventType>(false, LibWindowmanager::Event_Active); } } // namespace /// object will be json_object_put int LibWindowmanager::Impl::api_call( const char *verb, json_object *object, const std::function<void(bool, json_object *)> &onReply) { TRACE(); int rc = 0; if (0 == strcmp("RequestSurface", verb)) { // We need to wrap the actual onReply call once in order to // *look* like a normal functions pointer (std::functions<> // with captures cannot convert to function pointers). // Alternatively we could setup a local struct and use it as // closure, but I think it is cleaner this way. int call_rc = 0; std::atomic<bool> returned{}; returned.store(false, std::memory_order_relaxed); std::function<void(bool, json_object *)> wrappedOnReply = [&returned, &call_rc, &onReply](bool ok, json_object *j) { TRACEN(wrappedOnReply); call_rc = ok ? 0 : -EINVAL; // We know it failed, but there may be an explanation in the // json object. { TRACEN(onReply); onReply(ok, j); } returned.store(true, std::memory_order_release); }; // make the actual call, use wrappedOnReply as closure rc = afb_wsj1_call_j( this->wsj1, wmAPI, verb, object, [](void *closure, afb_wsj1_msg *msg) { TRACEN(callClosure); auto *onReply = reinterpret_cast<std::function<void(bool, json_object *)> *>( closure); (*onReply)(!(afb_wsj1_msg_is_reply_ok(msg) == 0), afb_wsj1_msg_object_j(msg)); }, &wrappedOnReply); if (0 == rc) { // We need to wait until "returned" got set, this is necessary // if events get triggered by the call (and would be dispatched before // the actual call-reply). while (!returned.load(std::memory_order_consume)) { sd_event_run(loop, 16); } // return the actual API call result rc = call_rc; } } else { rc = afb_wsj1_call_j(this->wsj1, wmAPI, verb, object, _on_reply_static, this); } if (rc < 0) { HMI_ERROR("libwm", "calling %s/%s(%s) failed: %m", wmAPI, verb, json_object_to_json_string_ext(object, JSON_C_TO_STRING_PRETTY)); // Call the reply handler regardless with a NULL json_object* onReply(false, nullptr); } return rc; } void LibWindowmanager::Impl::event(char const *et, json_object *object) { TRACE(); auto oet = make_event_type(et); if (!oet.first) { HMI_ERROR("libwm", "Unknown event type string '%s'", et); return; } auto i = this->handlers.find(oet.second); if (i != this->handlers.end()) { json_object *val; const char *label; if (json_object_object_get_ex(object, this->kKeyDrawingName, &val)) { label = json_object_get_string(val); } else { HMI_ERROR("libwm", "Not found key \"%s\"\n", this->kKeyDrawingName); return; } if (this->labels.find(label) != this->labels.end()) { i->second(object); } } } static void *event_loop_run(void *args){ struct sd_event* loop = (struct sd_event*)(args); for(;;) sd_event_run(loop, 30000000); } int LibWindowmanager::Impl::runEventLoop() { if(this->wsj1 && this->loop) { pthread_t thread_id; int ret = pthread_create(&thread_id, NULL, event_loop_run, this->loop); if(ret != 0) { printf("Cannot run eventloop due to error:%d", errno); return -1; } else return thread_id; } else { printf("Connecting is not established yet"); return -1; } } /** * @class LibWindowmanager */ int LibWindowmanager::init(int port, char const *token) { return this->d->init(port, token); } int LibWindowmanager::requestSurface(json_object *object) { return this->d->requestSurface(object); } int LibWindowmanager::requestSurfaceXDG(json_object *object) { return this->d->requestSurfaceXDG(object); } int LibWindowmanager::activateSurface(json_object *object) { return this->d->activateSurface(object); } int LibWindowmanager::deactivateSurface(json_object *object) { return this->d->deactivateSurface(object); } int LibWindowmanager::endDraw(json_object *object) { return this->d->endDraw(object); } void LibWindowmanager::set_event_handler(enum EventType et, handler_fun f) { return this->d->set_event_handler(et, std::move(f)); } LibWindowmanager::LibWindowmanager() : d(new Impl) {} LibWindowmanager::~LibWindowmanager() { delete d; }