summaryrefslogtreecommitdiffstats
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/appinfo.cpp219
-rw-r--r--app/src/appinfo.h96
-rw-r--r--app/src/config.h49
-rw-r--r--app/src/hmi-debug.h89
-rw-r--r--app/src/httpclient.cpp281
-rw-r--r--app/src/httpclient.h63
-rw-r--r--app/src/main.cpp147
-rw-r--r--app/src/nativeappmodel.cpp180
-rw-r--r--app/src/nativeappmodel.h63
-rw-r--r--app/src/serverappmodel.cpp339
-rw-r--r--app/src/serverappmodel.h92
-rw-r--r--app/src/src.pri17
12 files changed, 1635 insertions, 0 deletions
diff --git a/app/src/appinfo.cpp b/app/src/appinfo.cpp
new file mode 100644
index 0000000..bf51ba4
--- /dev/null
+++ b/app/src/appinfo.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "appinfo.h"
+#include <QFileInfo>
+#include "config.h"
+#include "hmi-debug.h"
+
+class AppInfo::Private : public QSharedData {
+ public:
+ Private();
+ Private(const Private& other);
+
+ QString id;
+ QString version;
+ int width;
+ int height;
+ QString name;
+ QString description;
+ QString shortname;
+ QString author;
+ QString iconPath;
+ AppState state;
+ qreal progress;
+
+ QString serverid;
+ QString wgtpath;
+ QString filename;
+ QString categoryid;
+ QString categoryname;
+ QString deviceid;
+ QString devicename;
+ double createdtime;
+};
+
+AppInfo::Private::Private() : width(-1), height(-1) {}
+
+AppInfo::Private::Private(const Private& other)
+ : QSharedData(other),
+ id(other.id),
+ version(other.version),
+ width(other.width),
+ height(other.height),
+ name(other.name),
+ description(other.description),
+ shortname(other.shortname),
+ author(other.author),
+ iconPath(other.iconPath),
+ state(other.state),
+ progress(other.progress),
+ serverid(other.serverid),
+ wgtpath(other.wgtpath),
+ filename(other.filename),
+ categoryid(other.categoryid),
+ categoryname(other.categoryname),
+ deviceid(other.deviceid),
+ devicename(other.devicename),
+ createdtime(other.createdtime) {}
+
+AppInfo::AppInfo() : d(new Private) {}
+
+AppInfo::AppInfo(const QString& icon, const QString& name, const QString& id)
+ : d(new Private) {
+ d->iconPath = icon;
+ d->name = name;
+ d->id = id;
+}
+
+AppInfo::AppInfo(const AppInfo& other) : d(other.d) {}
+
+AppInfo::~AppInfo() {}
+
+AppInfo& AppInfo::operator=(const AppInfo& other) {
+ d = other.d;
+ return *this;
+}
+
+bool AppInfo::operator==(const AppInfo& other) {
+ return d->id == other.id();
+}
+
+QString AppInfo::id() const {
+ return d->id;
+}
+
+QString AppInfo::version() const {
+ return d->version;
+}
+
+int AppInfo::width() const {
+ return d->width;
+}
+
+int AppInfo::height() const {
+ return d->height;
+}
+
+QString AppInfo::name() const {
+ return d->name;
+}
+
+QString AppInfo::description() const {
+ return d->description;
+}
+
+QString AppInfo::shortname() const {
+ return d->shortname;
+}
+
+QString AppInfo::author() const {
+ return d->author;
+}
+
+QString AppInfo::iconPath() const {
+ return d->iconPath;
+}
+
+AppInfo::AppState AppInfo::state() const {
+ return d->state;
+}
+
+qreal AppInfo::progress() const {
+ return d->progress;
+}
+
+QString AppInfo::serverId() const {
+ return d->serverid;
+}
+QString AppInfo::wgtPath() const {
+ return d->wgtpath;
+}
+QString AppInfo::fileName() const {
+ return d->filename;
+}
+
+QString AppInfo::categoryId() const {
+ return d->categoryid;
+}
+QString AppInfo::categoryName() const {
+ return d->categoryname;
+}
+QString AppInfo::deviceId() const {
+ return d->deviceid;
+}
+QString AppInfo::deviceName() const {
+ return d->devicename;
+}
+double AppInfo::createdTime() const {
+ return d->createdtime;
+}
+
+void AppInfo::setState(const AppState state) {
+ d->state = state;
+}
+void AppInfo::setState(const int state) {
+ d->state = (enum AppState)state;
+}
+
+void AppInfo::setProgress(const qreal progress) {
+ d->progress = progress;
+}
+
+void AppInfo::read(const QJsonObject& json) {
+ d->id = json["id"].toString();
+ d->version = json["version"].toString();
+ d->width = json["width"].toInt();
+ d->height = json["height"].toInt();
+ d->name = json["name"].toString();
+ d->description = json["description"].toString();
+ d->shortname = json["shortname"].toString();
+ d->author = json["author"].toString();
+ d->iconPath = json["icon"].toString();
+ QFileInfo fi(d->iconPath);
+ if (!fi.isFile()) {
+ d->iconPath = "";
+ }
+
+ d->state = Launch;
+}
+
+void AppInfo::readFromServer(const QJsonObject& json) {
+ d->name = json["appName"].toString();
+ d->description = json["appAbstract"].toString();
+ d->version = json["versionName"].toString();
+ d->id = json["appIdCustom"].toString() + "@" + d->version;
+ d->serverid = json["appId"].toString();
+ d->wgtpath = json["verFilePath"].toString();
+ d->filename = json["verFilePath"].toString().section('/', -1);
+ d->author = json["developerName"].toString();
+ d->categoryid = json["typeId"].toString();
+ d->categoryname = json["typeName"].toString();
+ d->deviceid = json["appDeviceTypeId"].toString();
+ d->devicename = json["appDeviceTypeName"].toString();
+ d->createdtime = json["updateDate"].toDouble();
+ d->iconPath = json["imagePath"].toString();
+
+ if (json["imagePath"].toString().isEmpty()) {
+ d->iconPath = "";
+ } else {
+ d->iconPath = getIconUrl(json["imagePath"].toString());
+ }
+ d->state = Install;
+ d->progress = 0.0;
+}
diff --git a/app/src/appinfo.h b/app/src/appinfo.h
new file mode 100644
index 0000000..fc5fc53
--- /dev/null
+++ b/app/src/appinfo.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 APPINFO_H
+#define APPINFO_H
+
+#include <QtCore/QJsonObject>
+#include <QtCore/QObject>
+#include <QtCore/QSharedDataPointer>
+
+class AppInfo {
+ Q_GADGET
+ Q_PROPERTY(QString id READ id)
+ Q_PROPERTY(QString version READ version)
+ Q_PROPERTY(int width READ width)
+ Q_PROPERTY(int height READ height)
+ Q_PROPERTY(QString name READ name)
+ Q_PROPERTY(QString description READ description)
+ Q_PROPERTY(QString shortname READ shortname)
+ Q_PROPERTY(QString author READ author)
+ Q_PROPERTY(QString iconPath READ iconPath)
+ Q_PROPERTY(AppState state READ state WRITE setState)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress)
+ Q_PROPERTY(QString serverid READ serverId)
+ Q_PROPERTY(QString wgtpath READ wgtPath)
+ Q_PROPERTY(QString filename READ fileName)
+ Q_PROPERTY(QString categoryid READ categoryId)
+ Q_PROPERTY(QString categoryname READ categoryName)
+ Q_PROPERTY(QString deviceid READ deviceId)
+ Q_PROPERTY(QString devicename READ deviceName)
+ Q_PROPERTY(double createdtime READ createdTime)
+ public:
+ enum AppState { Install = 0, Update, Launch, Downloading, Installing };
+ Q_ENUM(AppState)
+
+ AppInfo();
+ AppInfo(const QString& icon, const QString& name, const QString& id);
+ AppInfo(const AppInfo& other);
+ virtual ~AppInfo();
+ AppInfo& operator=(const AppInfo& other);
+ bool operator==(const AppInfo& other);
+ void swap(AppInfo& other) { qSwap(d, other.d); }
+
+ QString id() const;
+ QString version() const;
+ int width() const;
+ int height() const;
+ QString name() const;
+ QString description() const;
+ QString shortname() const;
+ QString author() const;
+ QString iconPath() const;
+ AppState state() const;
+ qreal progress() const;
+
+ QString serverId() const;
+ QString wgtPath() const;
+ QString fileName() const;
+ QString categoryId() const;
+ QString categoryName() const;
+ QString deviceId() const;
+ QString deviceName() const;
+ double createdTime() const;
+
+ void setState(const AppState state);
+ void setState(const int state);
+ void setProgress(const qreal progress);
+
+ void read(const QJsonObject& json);
+ void readFromServer(const QJsonObject& json);
+
+ private:
+ class Private;
+ QSharedDataPointer<Private> d;
+};
+
+Q_DECLARE_SHARED(AppInfo)
+Q_DECLARE_METATYPE(AppInfo)
+Q_DECLARE_METATYPE(QList<AppInfo>)
+
+#endif // APPINFO_H
diff --git a/app/src/config.h b/app/src/config.h
new file mode 100644
index 0000000..5f66a6a
--- /dev/null
+++ b/app/src/config.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 CONFIG_H
+#define CONFIG_H
+
+// server url config
+#define SERVER_DOMAIN "warehouse.tmc-tokai.jp"
+
+#define SERVER_DOMAIN_SERVICE QString("%1/webservice").arg(SERVER_DOMAIN)
+
+#define SERVER_BASE_URL "/api/v1/app"
+#define SERVER_API_LIST "/collection"
+
+#define getURL(api) \
+ QString("http://%1%2%3").arg(SERVER_DOMAIN_SERVICE, SERVER_BASE_URL, api)
+#define getUrlWithPage(api, offset, limit) \
+ getURL(api).append( \
+ QString("?sort=createDate&order=desc&offset=%1&limit=%2") \
+ .arg(QString::number(offset), QString::number(limit)))
+
+//#define getWgtUrl(path, typeId, appId) \
+// QString("http://%1%2/file/%3/%4/%5") \
+// .arg(SERVER_DOMAIN_SERVICE, SERVER_BASE_URL, path, typeId, appId)
+#define getWgtUrl(path) \
+ QString("http://%1%2/file?filePath=%3") \
+ .arg(SERVER_DOMAIN_SERVICE, SERVER_BASE_URL, path)
+
+#define getIconUrl(path) QString("http://%1%2").arg(SERVER_DOMAIN, path)
+
+// server app page config
+#define PAGE_SIZE 20
+
+#define getDownloadFilePath(filename) QString("/tmp/%1").arg(filename)
+
+#endif // !CONFIG_H
diff --git a/app/src/hmi-debug.h b/app/src/hmi-debug.h
new file mode 100644
index 0000000..1ec8ffb
--- /dev/null
+++ b/app/src/hmi-debug.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 __HMI_DEBUG_H__
+#define __HMI_DEBUG_H__
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+enum LOG_LEVEL {
+ LOG_LEVEL_NONE = 0,
+ LOG_LEVEL_ERROR,
+ LOG_LEVEL_WARNING,
+ LOG_LEVEL_NOTICE,
+ LOG_LEVEL_INFO,
+ LOG_LEVEL_DEBUG,
+ LOG_LEVEL_MAX = LOG_LEVEL_DEBUG
+};
+
+#define __FILENAME__ \
+ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define HMI_ERROR(prefix, args, ...) \
+ _HMI_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, prefix, \
+ args, ##__VA_ARGS__)
+#define HMI_WARNING(prefix, args, ...) \
+ _HMI_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, prefix, \
+ args, ##__VA_ARGS__)
+#define HMI_NOTICE(prefix, args, ...) \
+ _HMI_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, prefix, \
+ args, ##__VA_ARGS__)
+#define HMI_INFO(prefix, args, ...) \
+ _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, prefix, args, \
+ ##__VA_ARGS__)
+#define HMI_DEBUG(prefix, args, ...) \
+ _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, prefix, \
+ args, ##__VA_ARGS__)
+
+static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING",
+ "NOTICE", "INFO", "DEBUG"};
+
+static void _HMI_LOG(enum LOG_LEVEL level,
+ const char* file,
+ const char* func,
+ const int line,
+ const char* prefix,
+ const char* log,
+ ...) {
+ const int log_level = (getenv("USE_HMI_DEBUG") == NULL)
+ ? LOG_LEVEL_ERROR
+ : atoi(getenv("USE_HMI_DEBUG"));
+ if (log_level < level) {
+ return;
+ }
+
+ char* message;
+ struct timespec tp;
+ unsigned int time;
+
+ clock_gettime(CLOCK_REALTIME, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ va_list args;
+ va_start(args, log);
+ if (log == NULL || vasprintf(&message, log, args) < 0)
+ message = NULL;
+ fprintf(stderr, "[%10.3f] [%s %s] [%s, %s(), Line:%d] >>> %s \n",
+ time / 1000.0, prefix, ERROR_FLAG[level], file, func, line, message);
+ va_end(args);
+ free(message);
+}
+
+#endif //__HMI_DEBUG_H__
diff --git a/app/src/httpclient.cpp b/app/src/httpclient.cpp
new file mode 100644
index 0000000..c9bad50
--- /dev/null
+++ b/app/src/httpclient.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "httpclient.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QHash>
+#include <QHttpMultiPart>
+#include <QHttpPart>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QUrlQuery>
+
+class HttpClientPrivate {
+ public:
+ HttpClientPrivate(const QString& url);
+
+ QString url;
+ QUrlQuery params;
+ QHash<QString, QString> headers;
+ QNetworkAccessManager* manager;
+
+ bool debug;
+
+ enum HttpMethod { GET, POST, PUT, DELETE };
+
+ static QNetworkAccessManager* getManager(HttpClientPrivate* d,
+ bool* internal);
+
+ static QNetworkRequest createRequest(HttpClientPrivate* d, HttpMethod method);
+
+ static void get(HttpClientPrivate* d,
+ HttpMethod method,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ const char* encoding);
+
+ static QString readReply(QNetworkReply* reply,
+ const char* encoding = "UTF-8");
+
+ static void handleFinish(bool debug,
+ const QString& successMessage,
+ const QString& errorMessage,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ QNetworkReply* reply,
+ QNetworkAccessManager* manager);
+};
+
+HttpClientPrivate::HttpClientPrivate(const QString& url)
+ : url(url), manager(NULL), debug(false) {}
+
+HttpClient::HttpClient(const QString& url) : d(new HttpClientPrivate(url)) {}
+
+HttpClient::~HttpClient() {
+ delete d;
+}
+
+HttpClient& HttpClient::manager(QNetworkAccessManager* manager) {
+ d->manager = manager;
+ return *this;
+}
+
+HttpClient& HttpClient::debug(bool debug) {
+ d->debug = debug;
+ return *this;
+}
+
+HttpClient& HttpClient::param(const QString& name, const QString& value) {
+ d->params.addQueryItem(name, value);
+ return *this;
+}
+
+HttpClient& HttpClient::header(const QString& header, const QString& value) {
+ d->headers[header] = value;
+ return *this;
+}
+
+void HttpClient::get(std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ const char* encoding) {
+ HttpClientPrivate::get(d, HttpClientPrivate::GET, successHandler,
+ errorHandler, encoding);
+}
+
+void HttpClient::download(
+ const QString& savePath,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ std::function<void(const qint64, const qint64)> progressHandler) {
+ bool debug = d->debug;
+ QFile* file = new QFile(savePath);
+
+ if (file->open(QIODevice::WriteOnly)) {
+ download(
+ [=](const QByteArray& data) { file->write(data); },
+ [=](const QString&) {
+ file->flush();
+ file->close();
+ file->deleteLater();
+
+ if (debug) {
+ qDebug().noquote()
+ << QString("download finished, save to: %1").arg(savePath);
+ }
+
+ if (NULL != successHandler) {
+ successHandler(
+ QString("download finished, save to: %1").arg(savePath));
+ }
+ },
+ errorHandler, progressHandler);
+ } else {
+ if (debug) {
+ qDebug().noquote() << QString("open file error: %1").arg(savePath);
+ }
+
+ if (NULL != errorHandler) {
+ errorHandler(QString("open file error: %1").arg(savePath));
+ }
+ }
+}
+
+void HttpClient::download(
+ std::function<void(const QByteArray&)> readyRead,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ std::function<void(const qint64, const qint64)> progressHandler) {
+ bool debug = d->debug;
+ bool internal;
+
+ QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal);
+ QNetworkRequest request =
+ HttpClientPrivate::createRequest(d, HttpClientPrivate::GET);
+ QNetworkReply* reply = manager->get(request);
+
+ QObject::connect(reply, &QNetworkReply::readyRead,
+ [=] { readyRead(reply->readAll()); });
+
+ QObject::connect(reply, &QNetworkReply::finished, [=] {
+ QString successMessage = "download finished";
+ QString errorMessage = reply->errorString();
+ HttpClientPrivate::handleFinish(debug, successMessage, errorMessage,
+ successHandler, errorHandler, reply,
+ internal ? manager : NULL);
+ });
+
+ QObject::connect(reply, &QNetworkReply::downloadProgress,
+ [=](qint64 bytesReceived, qint64 bytesTotal) {
+ if (NULL != progressHandler) {
+ progressHandler(bytesReceived, bytesTotal);
+ }
+ });
+}
+
+void HttpClientPrivate::get(HttpClientPrivate* d,
+ HttpMethod method,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ const char* encoding) {
+ bool internal;
+
+ QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal);
+ QNetworkRequest request =
+ HttpClientPrivate::createRequest(d, HttpClientPrivate::GET);
+ QNetworkReply* reply = NULL;
+
+ switch (method) {
+ case HttpClientPrivate::GET:
+ reply = manager->get(request);
+ break;
+
+ default:
+ break;
+ }
+
+ QObject::connect(reply, &QNetworkReply::finished, [=] {
+ QString successMessage = HttpClientPrivate::readReply(reply, encoding);
+ QString errorMessage = reply->errorString();
+ HttpClientPrivate::handleFinish(d->debug, successMessage, errorMessage,
+ successHandler, errorHandler, reply,
+ internal ? manager : NULL);
+ });
+}
+
+QNetworkAccessManager* HttpClientPrivate::getManager(HttpClientPrivate* d,
+ bool* internal) {
+ *internal = d->manager == NULL;
+ return *internal ? new QNetworkAccessManager() : d->manager;
+}
+
+QNetworkRequest HttpClientPrivate::createRequest(HttpClientPrivate* d,
+ HttpMethod method) {
+ if (!d->params.isEmpty()) {
+ d->url += "?" + d->params.toString(QUrl::FullyEncoded);
+ }
+
+ if (d->debug) {
+ qDebug().noquote() << "url:" << d->url;
+
+ QList<QPair<QString, QString> > paramItems = d->params.queryItems();
+ for (int i = 0; i < paramItems.size(); ++i) {
+ QString name = paramItems.at(i).first;
+ QString value = paramItems.at(i).second;
+ if (0 == i) {
+ qDebug().noquote() << QString("params: %1=%2").arg(name).arg(value);
+ } else {
+ qDebug().noquote() << QString(" %1=%2").arg(name).arg(value);
+ }
+ }
+ }
+
+ QNetworkRequest request(QUrl(d->url));
+ QHashIterator<QString, QString> iter(d->headers);
+ while (iter.hasNext()) {
+ iter.next();
+ request.setRawHeader(iter.key().toUtf8(), iter.value().toUtf8());
+ }
+
+ return request;
+}
+
+QString HttpClientPrivate::readReply(QNetworkReply* reply,
+ const char* encoding) {
+ QTextStream in(reply);
+ QString result;
+ in.setCodec(encoding);
+
+ while (!in.atEnd()) {
+ result += in.readLine();
+ }
+
+ return result;
+}
+
+void HttpClientPrivate::handleFinish(
+ bool debug,
+ const QString& successMessage,
+ const QString& errorMessage,
+ std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler,
+ QNetworkReply* reply,
+ QNetworkAccessManager* manager) {
+ if (reply->error() == QNetworkReply::NoError) {
+ if (debug) {
+ qDebug().noquote()
+ << QString("request successed: %1").arg(successMessage);
+ }
+
+ if (NULL != successHandler) {
+ successHandler(successMessage);
+ }
+ } else {
+ if (debug) {
+ qDebug().noquote() << QString("request failed: %1").arg(errorMessage);
+ }
+
+ if (NULL != errorHandler) {
+ errorHandler(errorMessage);
+ }
+ }
+
+ reply->deleteLater();
+ if (NULL != manager) {
+ manager->deleteLater();
+ }
+}
diff --git a/app/src/httpclient.h b/app/src/httpclient.h
new file mode 100644
index 0000000..88dbbb1
--- /dev/null
+++ b/app/src/httpclient.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 HTTPCLIENT_H
+#define HTTPCLIENT_H
+
+#include <functional>
+#include <QtGlobal>
+
+class QString;
+class QByteArray;
+class QNetworkRequest;
+class QNetworkReply;
+class QNetworkAccessManager;
+class HttpClientPrivate;
+
+class HttpClient {
+ public:
+ HttpClient(const QString& url);
+ ~HttpClient();
+
+ HttpClient& manager(QNetworkAccessManager* manager);
+
+ HttpClient& debug(bool debug);
+
+ HttpClient& param(const QString& name, const QString& value);
+
+ HttpClient& header(const QString& header, const QString& value);
+
+ void get(std::function<void(const QString&)> successHandler,
+ std::function<void(const QString&)> errorHandler = NULL,
+ const char* encoding = "UTF-8");
+
+ void download(
+ const QString& savePath,
+ std::function<void(const QString&)> successHandler = NULL,
+ std::function<void(const QString&)> errorHandler = NULL,
+ std::function<void(const qint64, const qint64)> progressHandler = NULL);
+
+ void download(
+ std::function<void(const QByteArray&)> readyRead,
+ std::function<void(const QString&)> successHandler = NULL,
+ std::function<void(const QString&)> errorHandler = NULL,
+ std::function<void(const qint64, const qint64)> progressHandler = NULL);
+
+ private:
+ HttpClientPrivate* d;
+};
+
+#endif // !HTTPCLIENT_H
diff --git a/app/src/main.cpp b/app/src/main.cpp
new file mode 100644
index 0000000..986ebc1
--- /dev/null
+++ b/app/src/main.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <QtQml/qqml.h>
+#include <qlibwindowmanager.h>
+#include <QQuickWindow>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QUrlQuery>
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlApplicationEngine>
+#include <QtQml/QQmlContext>
+#include <QtQuickControls2/QQuickStyle>
+#include "afm_user_daemon_proxy.h"
+#include "nativeappmodel.h"
+#include "qlibhomescreen.h"
+#include "serverappmodel.h"
+
+org::AGL::afm::user* afm_user_daemon_proxy;
+
+namespace {
+
+struct Cleanup {
+ static inline void cleanup(org::AGL::afm::user* p) {
+ delete p;
+ afm_user_daemon_proxy = Q_NULLPTR;
+ }
+};
+
+void noOutput(QtMsgType, const QMessageLogContext&, const QString&) {}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ QString role = QString("warehouse");
+ QGuiApplication app(argc, argv);
+
+ // use launch process
+ QScopedPointer<org::AGL::afm::user, Cleanup> afm_user_daemon_proxy(
+ new org::AGL::afm::user("org.AGL.afm.user", "/org/AGL/afm/user",
+ QDBusConnection::sessionBus(), 0));
+ ::afm_user_daemon_proxy = afm_user_daemon_proxy.data();
+
+ app.setApplicationName("warehouse");
+
+ QQuickStyle::setStyle("AGL");
+
+ QQmlApplicationEngine engine;
+ QQmlContext* context = engine.rootContext();
+
+ 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();
+
+ if (positionalArguments.length() == 2) {
+ int port = positionalArguments.takeFirst().toInt();
+ QString secret = positionalArguments.takeFirst();
+ QUrl bindingAddress;
+ bindingAddress.setScheme(QStringLiteral("ws"));
+ bindingAddress.setHost(QStringLiteral("localhost"));
+ bindingAddress.setPort(port);
+ bindingAddress.setPath(QStringLiteral("/api"));
+ QUrlQuery query;
+ query.addQueryItem(QStringLiteral("token"), secret);
+ bindingAddress.setQuery(query);
+
+ std::string token = secret.toStdString();
+
+ // import C++ class to QML
+ qmlRegisterType<NativeAppModel>("NativeAppModel", 1, 0, "NativeAppModel");
+ qmlRegisterType<ServerAppModel>("ServerAppModel", 1, 0, "ServerAppModel");
+
+ QLibHomeScreen* homescreenHandler = new QLibHomeScreen();
+ QLibWindowmanager* qwm = new QLibWindowmanager();
+
+ // WindowManager
+ if (qwm->init(port, secret) != 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ AGLScreenInfo screenInfo(qwm->get_scale_factor());
+
+ // Request a surface as described in layers.json windowmanager’s file
+ if (qwm->requestSurface(role) != 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ // Create an event callback against an event type. Here a lambda is
+ // called when SyncDraw event occurs
+ qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw,
+ [qwm, role](json_object* object) {
+ fprintf(stderr, "Surface got syncDraw!\n");
+
+ qwm->endDraw(role);
+ });
+
+ // HomeScreen
+ homescreenHandler->init(port, token.c_str());
+ // Set the event handler for Event_TapShortcut which will activate the
+ // surface for windowmanager
+ homescreenHandler->set_event_handler(
+ QLibHomeScreen::Event_TapShortcut, [qwm, role](json_object* object) {
+ qDebug("Surface warehouse got tapShortcut.\n");
+ struct json_object *obj_param = nullptr, *obj_area = nullptr;
+ if(json_object_object_get_ex(object, "parameter", &obj_param)
+ && json_object_object_get_ex(obj_param, "area", &obj_area)) {
+ qwm->activateWindow(role.toStdString().c_str(), json_object_get_string(obj_area));
+ }
+ else {
+ qwm->activateWindow(role.toStdString().c_str(), "normal");
+ }
+ });
+
+ context->setContextProperty(QStringLiteral("homescreenHandler"),
+ homescreenHandler);
+ context->setContextProperty(QStringLiteral("screenInfo"), &screenInfo);
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ QObject* root = engine.rootObjects().first();
+
+ QQuickWindow* window = qobject_cast<QQuickWindow*>(root);
+ QObject::connect(window, SIGNAL(frameSwapped()), qwm,
+ SLOT(slotActivateSurface()));
+ }
+ return app.exec();
+}
diff --git a/app/src/nativeappmodel.cpp b/app/src/nativeappmodel.cpp
new file mode 100644
index 0000000..7cd06b2
--- /dev/null
+++ b/app/src/nativeappmodel.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "nativeappmodel.h"
+#include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusReply>
+#include "afm_user_daemon_proxy.h"
+#include "httpclient.h"
+
+#include "hmi-debug.h"
+
+extern org::AGL::afm::user* afm_user_daemon_proxy;
+
+class NativeAppModel::Private {
+ public:
+ Private();
+
+ void getApps();
+
+ QList<AppInfo> data;
+};
+
+NativeAppModel::Private::Private() {
+ // this->getApps();
+}
+
+void NativeAppModel::Private::getApps() {
+ QString apps = afm_user_daemon_proxy->runnables(QStringLiteral(""));
+ QJsonDocument japps = QJsonDocument::fromJson(apps.toUtf8());
+ for (auto const& app : japps.array()) {
+ QJsonObject const& jso = app.toObject();
+
+ AppInfo appinfo;
+ appinfo.read(jso);
+
+ this->data.append(appinfo);
+ }
+}
+
+NativeAppModel::NativeAppModel(QObject* parent)
+ : QAbstractListModel(parent), d(new Private()) {
+ connect(afm_user_daemon_proxy, &org::AGL::afm::user::changed, this,
+ &NativeAppModel::appChanged);
+}
+
+NativeAppModel::~NativeAppModel() {
+ delete this->d;
+}
+
+int NativeAppModel::rowCount(const QModelIndex& parent) const {
+ if (parent.isValid())
+ return 0;
+
+ return this->d->data.count();
+}
+
+QVariant NativeAppModel::data(const QModelIndex& index, int role) const {
+ QVariant ret;
+ if (!index.isValid())
+ return ret;
+
+ switch (role) {
+ case IconRole:
+ ret = this->d->data[index.row()].iconPath();
+ break;
+ case NameRole:
+ ret = this->d->data[index.row()].name();
+ break;
+ case IdRole:
+ ret = this->d->data[index.row()].id();
+ break;
+ case VersionRole:
+ ret = this->d->data[index.row()].version();
+ break;
+ case DescriptionRole:
+ ret = this->d->data[index.row()].description();
+ break;
+ case ShortNameRole:
+ ret = this->d->data[index.row()].shortname();
+ break;
+ case AuthorRole:
+ ret = this->d->data[index.row()].author();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+QHash<int, QByteArray> NativeAppModel::roleNames() const {
+ QHash<int, QByteArray> roles;
+ roles[IconRole] = "icon";
+ roles[NameRole] = "name";
+ roles[IdRole] = "id";
+ roles[VersionRole] = "version";
+ roles[DescriptionRole] = "description";
+ roles[ShortNameRole] = "shortname";
+ roles[AuthorRole] = "author";
+ return roles;
+}
+
+QString NativeAppModel::id(int i) const {
+ return data(index(i), IdRole).toString();
+}
+
+QString NativeAppModel::name(int i) const {
+ return data(index(i), NameRole).toString();
+}
+
+void NativeAppModel::appChanged(const QString& info) {
+ this->refresh();
+}
+
+int NativeAppModel::launch(const QString& application) {
+ int result = -1;
+ HMI_DEBUG("launch", "ApplicationLauncher launch %s.",
+ application.toStdString().c_str());
+
+ result = afm_user_daemon_proxy->start(application).value().toInt();
+ HMI_DEBUG("launch", "ApplicationLauncher pid: %d.", result);
+
+ return result;
+}
+
+void NativeAppModel::uninstall(int index) {
+ const QString& id = this->d->data[index].id();
+ QStringList list = id.split("@");
+ QString& name = list[0];
+
+ //afm_user_daemon_proxy->terminate(id);
+
+ QString result = afm_user_daemon_proxy->uninstall(id);
+
+ if (result == "null") {
+ QString pathName = "~/app-data/" + name + "/";
+
+ if(!name.isEmpty()){
+ QString cmd = "rm -r " + pathName;
+ qDebug() <<"CMD:"<< cmd;
+ system(cmd.toStdString().c_str());
+ }
+
+ pathName = "/var/local/lib/afm/applications/" + name + "/";
+ QFileInfo file(pathName);
+ if(file.isDir() && !name.isEmpty())
+ {
+ QString cmd = "rm -r " + pathName;
+ qDebug() <<"CMD:"<< cmd;
+ system(cmd.toStdString().c_str());
+ }
+
+ beginRemoveRows(QModelIndex(), index, index);
+ this->d->data.removeAt(index);
+ endRemoveRows();
+ }
+}
+
+void NativeAppModel::refresh() {
+ beginResetModel();
+ this->d->data.clear();
+ this->d->getApps();
+ endResetModel();
+ emit applistChanged(this->d->data);
+}
diff --git a/app/src/nativeappmodel.h b/app/src/nativeappmodel.h
new file mode 100644
index 0000000..b7c93e6
--- /dev/null
+++ b/app/src/nativeappmodel.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 NATIVEAPPMODE_H
+#define NATIVEAPPMODE_H
+
+#include <QtCore/QAbstractListModel>
+#include "appinfo.h"
+
+class NativeAppModel : public QAbstractListModel {
+ Q_OBJECT
+
+ public:
+ enum ModelRole {
+ IconRole = Qt::DisplayRole,
+ NameRole = Qt::DecorationRole,
+ IdRole = Qt::UserRole,
+ VersionRole,
+ DescriptionRole,
+ ShortNameRole,
+ AuthorRole
+ };
+ Q_ENUM(ModelRole)
+
+ explicit NativeAppModel(QObject* parent = nullptr);
+ ~NativeAppModel();
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex& index,
+ int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ Q_INVOKABLE QString id(int index) const;
+ Q_INVOKABLE QString name(int index) const;
+ Q_INVOKABLE int launch(const QString& application);
+ Q_INVOKABLE void uninstall(int index);
+ Q_INVOKABLE void refresh();
+
+ void appChanged(const QString& info);
+
+ signals:
+ void applistChanged(const QList<AppInfo>& applist);
+
+ private:
+ class Private;
+ Private* d;
+};
+
+#endif // NATIVEAPPMODE_H
diff --git a/app/src/serverappmodel.cpp b/app/src/serverappmodel.cpp
new file mode 100644
index 0000000..ac0db62
--- /dev/null
+++ b/app/src/serverappmodel.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "serverappmodel.h"
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+#include "afm_user_daemon_proxy.h"
+#include "httpclient.h"
+
+#include "hmi-debug.h"
+
+extern org::AGL::afm::user* afm_user_daemon_proxy;
+
+ServerAppModel::ServerAppModel(QObject* parent) : QAbstractListModel(parent) {
+ // this->getAppPage(0, PAGE_SIZE);
+ connect(afm_user_daemon_proxy, &org::AGL::afm::user::changed, this,
+ &ServerAppModel::appChanged);
+}
+
+ServerAppModel::~ServerAppModel() {}
+
+int ServerAppModel::rowCount(const QModelIndex& parent) const {
+ if (parent.isValid())
+ return 0;
+
+ return this->applist.count();
+}
+
+QVariant ServerAppModel::data(const QModelIndex& index, int role) const {
+ QVariant ret;
+ if (!index.isValid())
+ return ret;
+
+ switch (role) {
+ case IconRole:
+ ret = this->applist[index.row()].iconPath();
+ break;
+ case NameRole:
+ ret = this->applist[index.row()].name();
+ break;
+ case IdRole:
+ ret = this->applist[index.row()].id();
+ break;
+ case VersionRole:
+ ret = this->applist[index.row()].version();
+ break;
+ case DescriptionRole:
+ ret = this->applist[index.row()].description();
+ break;
+ case AuthorRole:
+ ret = this->applist[index.row()].author();
+ break;
+ case ServerIdRole:
+ ret = this->applist[index.row()].serverId();
+ break;
+ case CategoryNameRole:
+ ret = this->applist[index.row()].categoryName();
+ break;
+ case CreatedTimeRole:
+ ret = this->applist[index.row()].createdTime();
+ break;
+ case StateRole:
+ ret = this->applist[index.row()].state();
+ break;
+ case StateTextRole:
+ switch (this->applist[index.row()].state()) {
+ case AppInfo::Install:
+ ret = "Install";
+ break;
+ case AppInfo::Update:
+ ret = "Update";
+ break;
+ case AppInfo::Launch:
+ ret = "Launch";
+ break;
+ case AppInfo::Downloading:
+ ret = "Downloading";
+ break;
+ case AppInfo::Installing:
+ ret = "Installing";
+ break;
+ default:
+ break;
+ }
+ break;
+ case ProgressRole:
+ ret = this->applist[index.row()].progress();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+bool ServerAppModel::setData(const QModelIndex& index,
+ const QVariant& value,
+ int role) {
+ if (!index.isValid())
+ return false;
+
+ switch (role) {
+ case StateRole:
+ applist[index.row()].setState(value.toInt());
+ break;
+ case ProgressRole:
+ applist[index.row()].setProgress(value.toReal());
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ emit dataChanged(index, index);
+ return true;
+}
+
+bool ServerAppModel::removeRows(int row, int count, const QModelIndex&) {
+ QList<AppInfo>::iterator begin = applist.begin() + row;
+ QList<AppInfo>::iterator end = begin + count;
+
+ applist.erase(begin, end);
+
+ return true;
+}
+
+QHash<int, QByteArray> ServerAppModel::roleNames() const {
+ QHash<int, QByteArray> roles;
+ roles[IconRole] = "icon";
+ roles[NameRole] = "name";
+ roles[IdRole] = "id";
+ roles[VersionRole] = "version";
+ roles[DescriptionRole] = "description";
+ roles[AuthorRole] = "author";
+ roles[ServerIdRole] = "appid";
+ roles[CategoryNameRole] = "category";
+ roles[CreatedTimeRole] = "createdtime";
+ roles[StateRole] = "state";
+ roles[StateTextRole] = "statetext";
+ roles[ProgressRole] = "progress";
+ return roles;
+}
+
+QString ServerAppModel::id(int i) const {
+ return data(index(i), IdRole).toString();
+}
+
+QString ServerAppModel::name(int i) const {
+ return data(index(i), NameRole).toString();
+}
+
+QString ServerAppModel::stateText(int i) const {
+ return data(index(i), StateTextRole).toString();
+}
+
+int ServerAppModel::launch(const QString& application) {
+ int result = -1;
+ HMI_DEBUG("launch", "ApplicationLauncher launch %s.",
+ application.toStdString().c_str());
+
+ result = afm_user_daemon_proxy->start(application).value().toInt();
+ HMI_DEBUG("launch", "ApplicationLauncher pid: %d.", result);
+
+ return result;
+}
+
+void ServerAppModel::appChanged(const QString& info) {
+ QJsonDocument japps = QJsonDocument::fromJson(info.toUtf8());
+ QJsonObject const& jso = japps.object();
+ QString operation = jso["operation"].toString();
+ QString id = jso["data"].toString();
+ if (operation == "uninstall") {
+ for (int i = 0; i < applist.size(); ++i) {
+ if (applist.at(i).id() == id) {
+ setData(index(i), AppInfo::Install, StateRole);
+ break;
+ }
+ }
+ }
+}
+
+void ServerAppModel::install(int i) {
+ setData(index(i), AppInfo::Downloading, StateRole);
+
+ QString url = getWgtUrl(applist[i].wgtPath());
+ HttpClient client(url);
+
+ client.download(
+ getDownloadFilePath(applist[i].fileName()),
+ [this, i](const QString&) {
+ setData(index(i), AppInfo::Installing, StateRole);
+
+ QTimer::singleShot(3000, this, [this, i] {
+ QString installResult = afm_user_daemon_proxy->install(
+ getDownloadFilePath(applist[i].fileName()));
+
+ setData(index(i),
+ installResult.isEmpty() ? AppInfo::Install : AppInfo::Launch,
+ StateRole);
+ setData(index(i), 0.0, ProgressRole);
+ });
+ },
+ [this, i](const QString& error) {
+ HMI_ERROR("ERROR", "%s", error.toStdString().c_str());
+
+ setData(index(i), AppInfo::Install, StateRole);
+ setData(index(i), 0.0, ProgressRole);
+ },
+ [this, i](const qint64 bytesReceived, const qint64 bytesTotal) {
+ qreal progressValue = ((qreal)bytesReceived / bytesTotal) * 100;
+ setData(index(i), progressValue, ProgressRole);
+ });
+}
+
+void ServerAppModel::clearList() {
+ beginResetModel();
+ applist.clear();
+ endResetModel();
+}
+
+void ServerAppModel::getPrevPage(int PageIndex, QString name, int type) {
+ this->getAppPage(PageIndex > 0 ? PageIndex - 1 : 0, PAGE_SIZE, name, type,
+ true);
+}
+
+void ServerAppModel::getNextPage(int PageIndex, QString name, int type) {
+ this->getAppPage(applist.count() >= PAGE_SIZE ? PageIndex + 1 : PageIndex,
+ PAGE_SIZE, name, type);
+}
+
+void ServerAppModel::setNativeApplist(const QList<AppInfo>& applist) {
+ nativeApplist.clear();
+ nativeApplist = applist;
+ checkAppState();
+}
+
+void ServerAppModel::checkAppState() {
+ if (applist.isEmpty() || nativeApplist.isEmpty()) {
+ return;
+ }
+
+ QList<AppInfo>::iterator it;
+ int idx = 0;
+ for (it = applist.begin(); it != applist.end(); ++it) {
+ QList<AppInfo>::iterator nit;
+ for (nit = nativeApplist.begin(); nit != nativeApplist.end(); ++nit) {
+ if ((*it).id() == (*nit).id()) {
+ setData(index(idx),
+ (*it).version() != (*nit).version() ? AppInfo::Update
+ : AppInfo::Launch,
+ StateRole);
+ break;
+ }
+ }
+ idx++;
+ }
+}
+
+void ServerAppModel::getAppPage(int pageIndex,
+ int pageSize,
+ QString name,
+ int type,
+ bool isPrev) {
+ QString url =
+ getUrlWithPage(SERVER_API_LIST, pageIndex * pageSize, pageSize)
+ .append(QString("&appDeviceTypeId=%1").arg(QString::number(0)));
+ if (!name.isEmpty()) {
+ // get search list by name
+ url.append(QString("&keyWord=%1").arg(name));
+ }
+ if (type != -1) {
+ // get search list by type
+ url.append(QString("&appTypeId=%1").arg(QString::number(type)));
+ }
+ HMI_ERROR("Message", "%s", url.toStdString().c_str());
+
+ HttpClient client(url);
+
+ client.get(
+ [=](const QString& result) {
+ QJsonDocument jresult = QJsonDocument::fromJson(result.toUtf8());
+ QJsonObject const& jro = jresult.object();
+ QJsonArray const& jappList = jro["pagination_data"].toArray();
+
+ int offsetSize = 0;
+ bool distinct = true;
+
+ beginResetModel();
+ if (isPrev || applist.size() < PAGE_SIZE || jappList.size() == PAGE_SIZE) {
+ applist.clear();
+ distinct = false;
+ } else {
+ //offsetSize = 0;
+ if (applist.size() > PAGE_SIZE) {
+ for (int i = 0; i < (applist.size() - PAGE_SIZE); i++) {
+ applist.removeLast();
+ offsetSize--;
+ }
+ }
+ }
+
+ for (auto const& app : jappList) {
+ QJsonObject const& jso = app.toObject();
+
+ AppInfo appinfo;
+ appinfo.readFromServer(jso);
+ if (distinct) {
+ if (applist.contains(appinfo)) {
+ continue;
+ } else {
+ offsetSize++;
+ }
+ }
+ applist.append(appinfo);
+ }
+ endResetModel();
+ checkAppState();
+
+ emit requestCompleted(offsetSize, pageIndex, PAGE_SIZE, isPrev);
+ },
+ [=](const QString& msg) {
+ HMI_ERROR("response", "response error: %s", msg.toStdString().c_str());
+ });
+}
diff --git a/app/src/serverappmodel.h b/app/src/serverappmodel.h
new file mode 100644
index 0000000..b60571f
--- /dev/null
+++ b/app/src/serverappmodel.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION
+ *
+ * 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 SERVERAPPMODEL_H
+#define SERVERAPPMODEL_H
+
+#include <QtCore/QAbstractListModel>
+#include "appinfo.h"
+#include "config.h"
+
+class ServerAppModel : public QAbstractListModel {
+ Q_OBJECT
+
+ public:
+ enum ModelRole {
+ IconRole = Qt::DisplayRole,
+ NameRole = Qt::DecorationRole,
+ IdRole = Qt::UserRole,
+ VersionRole,
+ DescriptionRole,
+ AuthorRole,
+ ServerIdRole,
+ CategoryNameRole,
+ CreatedTimeRole,
+ StateRole,
+ StateTextRole,
+ ProgressRole
+ };
+ Q_ENUM(ModelRole)
+
+ explicit ServerAppModel(QObject* parent = nullptr);
+ ~ServerAppModel();
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex& index,
+ int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ bool setData(const QModelIndex& index,
+ const QVariant& value,
+ int role) override;
+ bool removeRows(int row,
+ int count,
+ const QModelIndex& parent = QModelIndex()) override;
+ Q_INVOKABLE QString id(int index) const;
+ Q_INVOKABLE QString name(int index) const;
+ Q_INVOKABLE QString stateText(int index) const;
+ Q_INVOKABLE void install(int index);
+ Q_INVOKABLE int launch(const QString& application);
+
+ Q_INVOKABLE void clearList();
+ Q_INVOKABLE void getPrevPage(int PageIndex, QString name = "", int type = -1);
+ Q_INVOKABLE void getNextPage(int PageIndex, QString name = "", int type = -1);
+
+ Q_INVOKABLE void setNativeApplist(const QList<AppInfo>& applist);
+
+ void getAppPage(int pageIndex,
+ int pageSize,
+ QString name,
+ int type,
+ bool isPrev = false);
+
+ void appChanged(const QString& info);
+
+ signals:
+ void requestCompleted(int offsetSize,
+ int pageIndex,
+ int pageSize,
+ bool isPrev);
+
+ private:
+ void checkAppState();
+
+ QList<AppInfo> applist;
+ QList<AppInfo> nativeApplist;
+};
+
+#endif // SERVERAPPMODEL_H
diff --git a/app/src/src.pri b/app/src/src.pri
new file mode 100644
index 0000000..455ded3
--- /dev/null
+++ b/app/src/src.pri
@@ -0,0 +1,17 @@
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/nativeappmodel.h \
+ $$PWD/serverappmodel.h \
+ $$PWD/appinfo.h \
+ $$PWD/hmi-debug.h \
+ $$PWD/httpclient.h \
+ $$PWD/config.h
+
+SOURCES += \
+ $$PWD/main.cpp \
+ $$PWD/nativeappmodel.cpp \
+ $$PWD/serverappmodel.cpp \
+ $$PWD/appinfo.cpp \
+ $$PWD/httpclient.cpp