1 // SPDX-License-Identifier: Apache-2.0
3 * Copyright (c) 2017, 2018, 2019 TOYOTA MOTOR CORPORATION
4 * Copyright (c) 2022 Konsulko Group
7 #include <QGuiApplication>
12 #include "homescreenhandler.h"
13 #include "hmi-debug.h"
15 QScreen *find_screen(const char *output);
17 // defined by meson build file
18 #include QT_QPA_HEADER
20 // LAUNCHER_APP_ID shouldn't be started by applaunchd as it is started as
21 // a user session by systemd
22 #define LAUNCHER_APP_ID "launcher"
25 HomescreenHandler::HomescreenHandler(ApplicationLauncher *launcher, GrpcClient *_client, QObject *parent) :
27 , m_grpc_client(_client)
29 mp_launcher = launcher;
30 mp_applauncher_client = new AppLauncherClient();
33 // The "started" event is received any time a start request is made to applaunchd,
34 // and the application either starts successfully or is already running. This
35 // effectively acts as a "switch to app X" action.
37 connect(mp_applauncher_client,
38 &AppLauncherClient::appStatusEvent,
40 &HomescreenHandler::processAppStatusEvent);
43 HomescreenHandler::~HomescreenHandler()
46 delete mp_applauncher_client;
49 void HomescreenHandler::tapShortcut(QString app_id)
51 HMI_DEBUG("HomeScreen","tapShortcut %s", app_id.toStdString().c_str());
53 if (app_id == LAUNCHER_APP_ID) {
58 if (!mp_applauncher_client->startApplication(app_id)) {
59 HMI_ERROR("HomeScreen","Unable to start application '%s'",
60 app_id.toStdString().c_str());
66 * Keep track of currently running apps and the order in which
67 * they were activated. That way, when an app is closed, we can
68 * switch back to the previously active one.
70 void HomescreenHandler::addAppToStack(const QString& app_id)
72 if (app_id == "homescreen")
75 if (!apps_stack.contains(app_id)) {
78 int current_pos = apps_stack.indexOf(app_id);
79 int last_pos = apps_stack.size() - 1;
81 if (current_pos != last_pos)
82 apps_stack.move(current_pos, last_pos);
86 void HomescreenHandler::activateApp(const QString& app_id)
88 QScreen *default_screen = qApp->screens().first();
89 std::string default_output_name;
91 if (!default_screen) {
92 HMI_DEBUG("HomeScreen", "No default output found to activate on!\n");
94 default_output_name = default_screen->name().toStdString();
95 HMI_DEBUG("HomeScreen", "Activating app_id %s by default on output %s\n",
96 app_id.toStdString().c_str(), default_output_name.c_str());
100 mp_launcher->setCurrent(app_id);
103 // search for a pending application which might have a different output
104 auto iter = pending_app_list.begin();
105 bool found_pending_app = false;
106 while (iter != pending_app_list.end()) {
107 const QString &app_to_search = iter->first;
109 if (app_to_search == app_id) {
110 found_pending_app = true;
111 HMI_DEBUG("HomeScreen", "Found app_id %s in pending list of applications",
112 app_id.toStdString().c_str());
119 if (found_pending_app) {
120 const QString &output_name = iter->second;
122 ::find_screen(output_name.toStdString().c_str());
125 HMI_DEBUG("HomeScreen", "Can't activate application %s on another "
126 "output, because output %s could not be found. "
127 "Trying with remoting ones.",
128 app_id.toStdString().c_str(),
129 output_name.toStdString().c_str());
131 // try with remoting-remote-X which is the streaming
133 std::string new_remote_output =
134 "remoting-" + output_name.toStdString();
136 screen = ::find_screen(new_remote_output.c_str());
138 HMI_DEBUG("HomeScreen", "Can't activate application %s on another "
139 "output, because output remoting-%s could not be found",
140 app_id.toStdString().c_str(),
141 output_name.toStdString().c_str());
145 HMI_DEBUG("HomeScreen", "Found a stream remoting output %s to activate application %s on",
146 new_remote_output.c_str(),
147 app_id.toStdString().c_str());
148 default_output_name = new_remote_output;
151 pending_app_list.erase(iter);
152 HMI_DEBUG("HomeScreen", "For application %s found another "
153 "output to activate %s\n",
154 app_id.toStdString().c_str(),
155 default_output_name.c_str());
158 if (default_output_name.empty()) {
159 HMI_DEBUG("HomeScreen", "No suitable output found for activating %s",
160 app_id.toStdString().c_str());
164 HMI_DEBUG("HomeScreen", "Activating application %s on output %s",
165 app_id.toStdString().c_str(), default_output_name.c_str());
166 m_grpc_client->ActivateApp(app_id.toStdString(), default_output_name);
169 void HomescreenHandler::deactivateApp(const QString& app_id)
171 if (apps_stack.contains(app_id)) {
172 apps_stack.removeOne(app_id);
173 if (!apps_stack.isEmpty())
174 activateApp(apps_stack.last());
178 void HomescreenHandler::processAppStatusEvent(const QString &app_id, const QString &status)
180 HMI_DEBUG("HomeScreen", "Processing application %s, status %s",
181 app_id.toStdString().c_str(), status.toStdString().c_str());
183 if (status == "started") {
185 } else if (status == "terminated") {
186 HMI_DEBUG("HomeScreen", "Application %s terminated, activating last app", app_id.toStdString().c_str());
187 deactivateApp(app_id);
188 } else if (status == "deactivated") {
189 HMI_DEBUG("HomeScreen", "Application %s deactivated, activating last app", app_id.toStdString().c_str());