From e3767af1a9d44abe2ea88ba85ff004cbdaefc21c Mon Sep 17 00:00:00 2001 From: zheng_wenlong Date: Thu, 6 Jun 2019 15:55:19 +0900 Subject: add vui button --- homescreen/homescreen.pro | 9 +- homescreen/qml/images/images.qrc | 1 + homescreen/qml/images/voice.png | Bin 0 -> 6581 bytes homescreen/qml/main.qml | 40 +++++- homescreen/src/homescreenhandler.cpp | 2 +- homescreen/src/homescreenvoice.cpp | 229 +++++++++++++++++++++++++++++++++++ homescreen/src/homescreenvoice.h | 64 ++++++++++ homescreen/src/main.cpp | 18 ++- homescreen/src/shortcutappmodel.cpp | 1 - package/config.xml | 1 + 10 files changed, 355 insertions(+), 10 deletions(-) create mode 100644 homescreen/qml/images/voice.png create mode 100644 homescreen/src/homescreenvoice.cpp create mode 100644 homescreen/src/homescreenvoice.h diff --git a/homescreen/homescreen.pro b/homescreen/homescreen.pro index 0de8e03..923c961 100644 --- a/homescreen/homescreen.pro +++ b/homescreen/homescreen.pro @@ -20,6 +20,9 @@ CONFIG += c++11 link_pkgconfig DESTDIR = $${OUT_PWD}/../package/root/bin PKGCONFIG += qlibwindowmanager qlibhomescreen qtappfw afb-helpers-qt +LIBS += -lafbwsc +LIBS += -lsystemd + include(../interfaces/interfaces.pri) SOURCES += \ @@ -30,7 +33,8 @@ SOURCES += \ src/mastervolume.cpp \ src/homescreenhandler.cpp \ src/toucharea.cpp \ - src/shortcutappmodel.cpp + src/shortcutappmodel.cpp \ + src/homescreenvoice.cpp HEADERS += \ src/statusbarmodel.h \ @@ -39,7 +43,8 @@ HEADERS += \ src/mastervolume.h \ src/homescreenhandler.h \ src/toucharea.h \ - src/shortcutappmodel.h + src/shortcutappmodel.h \ + src/homescreenvoice.h OTHER_FILES += \ README.md diff --git a/homescreen/qml/images/images.qrc b/homescreen/qml/images/images.qrc index 39f7eb6..2e09cc9 100644 --- a/homescreen/qml/images/images.qrc +++ b/homescreen/qml/images/images.qrc @@ -11,5 +11,6 @@ fullscreen.png normal.png normal_disable.png + voice.png diff --git a/homescreen/qml/images/voice.png b/homescreen/qml/images/voice.png new file mode 100644 index 0000000..80f2a5a Binary files /dev/null and b/homescreen/qml/images/voice.png differ diff --git a/homescreen/qml/main.qml b/homescreen/qml/main.qml index a8d095b..de833a9 100644 --- a/homescreen/qml/main.qml +++ b/homescreen/qml/main.qml @@ -142,13 +142,15 @@ Window { container.state = 'fullscreen' touchArea.switchArea(1) homescreenHandler.tapShortcut(appName, true) - container.opacity = 0.0 + container.visible = false + voiceBtn.visible = false } else { image.source = './images/normal.png' container.state = 'normal' touchArea.switchArea(0) homescreenHandler.tapShortcut(appName, false) - container.opacity = 1.0 + container.visible = true + voiceBtn.visible = true } } } @@ -189,6 +191,7 @@ Window { image.visible = true touchArea.switchArea(0) container.opacity = 1.0 + voiceBtn.visible = true } } @@ -199,6 +202,7 @@ Window { image.visible = false touchArea.switchArea(1) container.opacity = 0.0 + voiceBtn.visible = false } } @@ -293,4 +297,36 @@ Window { notificationTimer.restart() } } + + Connections { + target: homescreenVoice + onStatusChanged: { + voiceBtn.visible = status + } + } + + Item { + id: voiceBtn + width: 110 + height: 110 + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: 50 + anchors.rightMargin: 0 + visible: true + Image { + id: voiceimage + anchors.left: parent.left + anchors.top: parent.top + width: 110 + height: 110 + source: './images/voice.png' + } + MouseArea { + anchors.fill: parent + onClicked: { + homescreenVoice.startListening(); + } + } + } } diff --git a/homescreen/src/homescreenhandler.cpp b/homescreen/src/homescreenhandler.cpp index cbf816a..2e5c9cf 100644 --- a/homescreen/src/homescreenhandler.cpp +++ b/homescreen/src/homescreenhandler.cpp @@ -133,7 +133,7 @@ void HomescreenHandler::tapShortcut(QString application_id, bool is_full) void HomescreenHandler::updateShortcut(QString id, struct json_object* object) { - mp_qhs->updateShortcut(id.toStdString().c_str(), object); + mp_qhs->updateShortcut(id, object); } diff --git a/homescreen/src/homescreenvoice.cpp b/homescreen/src/homescreenvoice.cpp new file mode 100644 index 0000000..4a376e1 --- /dev/null +++ b/homescreen/src/homescreenvoice.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2017, 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 +#include "homescreenvoice.h" +#include +#include +#include +#include +#include +#include "hmi-debug.h" + + + +static const char API[] = "vshl-core"; +const string vshl_core_event = "{\"va_id\": \"VA-001\", \"events\": [\"voice_dialogstate_event\"]}"; + +static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj) +{ + static_cast(closure)->on_hangup(NULL,wsj); +} + +static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg) +{ + /* HomescreenVoice is not called from other process */ +} + +static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg) +{ + static_cast(closure)->on_event(NULL,event,msg); +} + +static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg) +{ + static_cast(closure)->on_reply(NULL,msg); +} + +const std::vector HomescreenVoice::state_lists { + std::string("IDLE"), + std::string("LISTENING"), + std::string("THINKING"), + std::string("UNKNOWN"), + std::string("SPEAKING") +}; + + +static void event_loop_run(struct sd_event* loop){ + sd_event_loop(loop); + sd_event_unref(loop); +} + +HomescreenVoice::HomescreenVoice(QObject *parent) : + QObject(parent) +{ + +} + +HomescreenVoice::~HomescreenVoice() +{ + if(sp_websock != NULL) + { + afb_wsj1_unref(sp_websock); + } + if(mploop) + { + sd_event_exit(mploop, 0); + } +} + +int HomescreenVoice::init(int port, const string& token) +{ + int ret = 0; + if(port > 0 && token.size() > 0) + { + mport = port; + mtoken = token; + } + else + { + HMI_ERROR("HomescreenVoice","port and token should be > 0, Initial port and token uses."); + } + + ret = initialize_websocket(); + if(ret != 0 ) + { + HMI_ERROR("HomescreenVoice","Failed to initialize websocket"); + } + else{ + HMI_DEBUG("HomescreenVoice","Initialized"); + subscribe(vshl_core_event); + } + + return ret; +} + +int HomescreenVoice::initialize_websocket(void) +{ + HMI_DEBUG("HomescreenVoice"," initialize_websocket called"); + mploop = NULL; + int ret = sd_event_new(&mploop); + if(ret < 0) + { + HMI_ERROR("HomescreenVoice","Failed to create event loop"); + return -1; + } + + { + // enforce context to avoid initialization/goto error + std::thread th(event_loop_run, mploop); + th.detach(); + } + + /* Initialize interface from websocket */ + minterface.on_hangup = _on_hangup_static; + minterface.on_call = _on_call_static; + minterface.on_event = _on_event_static; + muri += "ws://localhost:" + to_string(mport) + "/api?token=" + mtoken; /*To be modified*/ + sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this); + + if(sp_websock == NULL) + { + HMI_ERROR("HomescreenVoice","Failed to create websocket connection"); + return -1; + } + + return 0; +} + +int HomescreenVoice::subscribe(const string event_name) +{ + HMI_DEBUG("HomescreenVoice"," subscribe called"); + if(!sp_websock) + { + return -1; + } + + json_object* j_obj = json_tokener_parse(event_name.c_str()); + + int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this); + if (ret < 0) { + HMI_ERROR("HomescreenVoice","Failed to call verb"); + } + return ret; +} + +int HomescreenVoice::startListening(void) +{ + HMI_DEBUG("HomescreenVoice"," startListening called"); + struct json_object* j_obj = json_object_new_object(); + int ret = afb_wsj1_call_j(sp_websock, API, "startListening", j_obj, _on_reply_static, this); + if (ret < 0) { + HMI_ERROR("HomescreenVoice"," startListening Failed to call verb"); + } + return ret; +} + +/************* Callback Function *************/ + +void HomescreenVoice::on_hangup(void *closure, struct afb_wsj1 *wsj) +{ + HMI_DEBUG("HomescreenVoice"," on_hangup called"); +} + +void HomescreenVoice::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg) +{ + HMI_DEBUG("HomescreenVoice"," on_call called"); +} + +/* +* event is like "homescreen/hvac" +* msg is like {"event":"homescreen\/hvac","data":{"type":"tap_shortcut"},"jtype":"afb-event"} +* so you can get + event name : struct json_object obj = json_object_object_get(msg,"event") +*/ +void HomescreenVoice::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg) +{ + HMI_DEBUG("HomescreenVoice","event: (%s) msg: (%s).", event, afb_wsj1_msg_object_s(msg)); + + if (strstr(event, API) == NULL) { + return; + } + struct json_object* ev_contents = afb_wsj1_msg_object_j(msg); + struct json_object *json_data_str; + if(!json_object_object_get_ex(ev_contents, "data", &json_data_str)) { + HMI_ERROR("HomescreenVoice", "got ev_contents error."); + return; + } + + struct json_object *json_state; + struct json_object *json_data = json_tokener_parse(json_object_get_string(json_data_str)); + if(!json_object_object_get_ex(json_data, "state", &json_state)) { + HMI_ERROR("HomescreenVoice", "got json_data1 error."); + return; + } + + const char* corestatus = json_object_get_string(json_state); + + if (strcasecmp(corestatus, HomescreenVoice::state_lists[0].c_str()) == 0) { + emit statusChanged(true); + } + else if ((strcasecmp(corestatus, HomescreenVoice::state_lists[1].c_str()) == 0)|| + (strcasecmp(corestatus, HomescreenVoice::state_lists[2].c_str()) == 0)|| + (strcasecmp(corestatus, HomescreenVoice::state_lists[3].c_str()) == 0)|| + (strcasecmp(corestatus, HomescreenVoice::state_lists[4].c_str()) == 0)){ + emit statusChanged(false); + } +} + +/** + * msg is like ({"response":{"verb":"subscribe","error":0},"jtype":"afb-reply","request":{"status":"success","info":"homescreen binder subscribe event name [on_screen_message]"}}) + * msg is like ({"response":{"verb":"tap_shortcut","error":0},"jtype":"afb-reply","request":{"status":"success","info":"afb_event_push event [tap_shortcut]"}}) + */ +void HomescreenVoice::on_reply(void *closure, struct afb_wsj1_msg *msg) +{ + HMI_DEBUG("HomescreenVoice"," on_reply called"); +} diff --git a/homescreen/src/homescreenvoice.h b/homescreen/src/homescreenvoice.h new file mode 100644 index 0000000..6a4f7e5 --- /dev/null +++ b/homescreen/src/homescreenvoice.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 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 HOMESCREENVOICE_H +#define HOMESCREENVOICE_H + +#include +#include +#include +#include +#include +#include +extern "C" +{ +#include +#include +} + +using namespace std; + +class HomescreenVoice : public QObject +{ + Q_OBJECT +public: + explicit HomescreenVoice(QObject *parent = 0); + ~HomescreenVoice(); + static const std::vector state_lists; + + int init(int port, const string& token); + void on_hangup(void *closure, struct afb_wsj1 *wsj); + void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg); + void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg); + void on_reply(void *closure, struct afb_wsj1_msg *msg); + Q_INVOKABLE int startListening(void); +signals: + void statusChanged(bool status); + +private: + int initialize_websocket(void); + int subscribe(const string event_name); + + struct afb_wsj1* sp_websock; + struct afb_wsj1_itf minterface; + sd_event* mploop; + std::string muri; + int mport = 2000; + std::string mtoken = "hs"; + +}; + +#endif // HOMESCREENVOICE_H diff --git a/homescreen/src/main.cpp b/homescreen/src/main.cpp index 0c477fd..c7c343e 100644 --- a/homescreen/src/main.cpp +++ b/homescreen/src/main.cpp @@ -32,6 +32,7 @@ #include "afm_user_daemon_proxy.h" #include "mastervolume.h" #include "homescreenhandler.h" +#include "homescreenvoice.h" #include "toucharea.h" #include "shortcutappmodel.h" #include "hmi-debug.h" @@ -100,6 +101,8 @@ int main(int argc, char *argv[]) QLibWindowmanager* layoutHandler = new QLibWindowmanager(); HomescreenHandler* homescreenHandler = new HomescreenHandler(); ShortcutAppModel* shortcutAppModel = new ShortcutAppModel(); + HomescreenVoice* homescreenVoice = new HomescreenVoice(); + if(layoutHandler->init(port,token) != 0){ exit(EXIT_FAILURE); } @@ -122,12 +125,14 @@ int main(int argc, char *argv[]) TouchArea* touchArea = new TouchArea(); homescreenHandler->init(port, token.toStdString().c_str(), layoutHandler, graphic_role); + homescreenVoice->init(port, token.toStdString().c_str()); // mail.qml loading QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("bindingAddress", bindingAddress); engine.rootContext()->setContextProperty("layoutHandler", layoutHandler); engine.rootContext()->setContextProperty("homescreenHandler", homescreenHandler); + engine.rootContext()->setContextProperty("homescreenVoice", homescreenVoice); engine.rootContext()->setContextProperty("touchArea", touchArea); engine.rootContext()->setContextProperty("shortcutAppModel", shortcutAppModel); engine.rootContext()->setContextProperty("launcher", launcher); @@ -144,15 +149,16 @@ int main(int argc, char *argv[]) layoutHandler->endDraw(graphic_role); }); - layoutHandler->set_event_handler(QLibWindowmanager::Event_ScreenUpdated, [layoutHandler, launcher, homescreenHandler, root](json_object *object) { + layoutHandler->set_event_handler(QLibWindowmanager::Event_ScreenUpdated, [layoutHandler, launcher, homescreenHandler, shortcutAppModel, root](json_object *object) { json_object *jarray = json_object_object_get(object, "ids"); HMI_DEBUG("HomeScreen","ids=%s", json_object_to_json_string(object)); int arrLen = json_object_array_length(jarray); QString label = QString(""); + static bool first_start = true; for( int idx = 0; idx < arrLen; idx++) { label = QString(json_object_get_string( json_object_array_get_idx(jarray, idx) )); - HMI_DEBUG("HomeScreen","Event_ScreenUpdated application11: %s.", label.toStdString().c_str()); + HMI_DEBUG("HomeScreen","Event_ScreenUpdated application: %s.", label.toStdString().c_str()); homescreenHandler->setCurrentApplication(label); QMetaObject::invokeMethod(launcher, "setCurrent", Qt::QueuedConnection, Q_ARG(QString, label)); } @@ -161,6 +167,12 @@ int main(int argc, char *argv[]) }else{ QMetaObject::invokeMethod(root, "changeSwitchState", Q_ARG(QVariant, false)); } + if(first_start) { + if((arrLen == 1) && (QString("launcher") == label)) { + first_start = false; + shortcutAppModel->screenUpdated(); + } + } }); touchArea->setWindow(window); @@ -177,7 +189,5 @@ int main(int argc, char *argv[]) QObject::connect(homescreenHandler, SIGNAL(shortcutChanged(QString, QString, QString)), shortcutAppModel, SLOT(changeShortcut(QString, QString, QString))); QObject::connect(shortcutAppModel, SIGNAL(shortcutUpdated(QString, struct json_object*)), homescreenHandler, SLOT(updateShortcut(QString, struct json_object*))); - shortcutAppModel->screenUpdated(); - return a.exec(); } diff --git a/homescreen/src/shortcutappmodel.cpp b/homescreen/src/shortcutappmodel.cpp index 76078da..7776bd1 100644 --- a/homescreen/src/shortcutappmodel.cpp +++ b/homescreen/src/shortcutappmodel.cpp @@ -122,7 +122,6 @@ struct json_object* ShortcutAppModel::makeAppListJson() json_object_array_add(obj_array, obj_shortcut); } json_object_object_add(obj, "shortcut", obj_array); - HMI_DEBUG("Homescreen", "makeAppListJson id1=%s",json_object_new_string(d->data.at(1).name.toStdString().c_str())); return obj; } diff --git a/package/config.xml b/package/config.xml index d1e83eb..540fbdf 100644 --- a/package/config.xml +++ b/package/config.xml @@ -13,6 +13,7 @@ + -- cgit 1.2.3-korg