homescreenhandler: Add support for split
[apps/homescreen.git] / homescreen / src / homescreenhandler.cpp
1 /*
2  * Copyright (c) 2017, 2018, 2019 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <QGuiApplication>
18 #include <QFileInfo>
19 #include "homescreenhandler.h"
20 #include <functional>
21 #include "hmi-debug.h"
22
23 #include <qpa/qplatformnativeinterface.h>
24
25 #define APPLAUNCH_DBUS_IFACE     "org.automotivelinux.AppLaunch"
26 #define APPLAUNCH_DBUS_OBJECT    "/org/automotivelinux/AppLaunch"
27 /* LAUNCHER_APP_ID shouldn't be started by applaunchd as it is started as a
28  * user session by systemd */
29 #define LAUNCHER_APP_ID          "launcher"
30
31 void* HomescreenHandler::myThis = 0;
32
33 HomescreenHandler::HomescreenHandler(Shell *_aglShell, ApplicationLauncher *launcher, QObject *parent) :
34     QObject(parent),
35     aglShell(_aglShell)
36 {
37     mp_launcher = launcher;
38     applaunch_iface = new org::automotivelinux::AppLaunch(APPLAUNCH_DBUS_IFACE, APPLAUNCH_DBUS_OBJECT,
39                                                           QDBusConnection::sessionBus(), this);
40 }
41
42 HomescreenHandler::~HomescreenHandler()
43 {
44 }
45
46 void HomescreenHandler::init(void)
47 {
48     myThis = this;
49
50     /*
51      * The "started" signal is received any time a start request is made to applaunchd,
52      * and the application either starts successfully or is already running. This
53      * effectively acts as a "switch to app X" action.
54      */
55     connect(applaunch_iface, SIGNAL(started(QString)), this, SLOT(appStarted(QString)));
56     connect(applaunch_iface, SIGNAL(terminated(QString)), this, SLOT(appTerminated(QString)));
57     connect(applaunch_iface, SIGNAL(splited(QString, uint32_t)), this, SLOT(appSplit(QString, uint32_t)));
58
59 }
60
61 static struct wl_output *
62 getWlOutput(QPlatformNativeInterface *native, QScreen *screen)
63 {
64         void *output = native->nativeResourceForScreen("output", screen);
65         return static_cast<struct ::wl_output*>(output);
66 }
67
68 void HomescreenHandler::tapShortcut(QString application_id)
69 {
70     QDBusPendingReply<> reply;
71     HMI_DEBUG("HomeScreen","tapShortcut %s", application_id.toStdString().c_str());
72
73     if (application_id == LAUNCHER_APP_ID)
74         goto activate_app;
75
76     reply = applaunch_iface->start(application_id);
77     reply.waitForFinished();
78
79     if (reply.isError()) {
80         HMI_ERROR("HomeScreen","Unable to start application '%s': %s",
81             application_id.toStdString().c_str(),
82             reply.error().message().toStdString().c_str());
83         return;
84     }
85
86 activate_app:
87     if (mp_launcher) {
88         mp_launcher->setCurrent(application_id);
89     }
90     appStarted(application_id);
91 }
92
93 /*
94  * Keep track of currently running apps and the order in which
95  * they were activated. That way, when an app is closed, we can
96  * switch back to the previously active one.
97  */
98 void HomescreenHandler::addAppToStack(const QString& application_id)
99 {
100     if (application_id == "homescreen")
101         return;
102
103     if (!apps_stack.contains(application_id)) {
104         apps_stack << application_id;
105     } else {
106         int current_pos = apps_stack.indexOf(application_id);
107         int last_pos = apps_stack.size() - 1;
108
109         if (current_pos != last_pos)
110             apps_stack.move(current_pos, last_pos);
111     }
112 }
113
114 void HomescreenHandler::appSplit(const QString& application_id, uint32_t orientation)
115 {
116     struct agl_shell *agl_shell = aglShell->shell.get();
117     QPlatformNativeInterface *native = qApp->platformNativeInterface();
118     struct wl_output *output = getWlOutput(native, qApp->screens().first());
119
120     HMI_DEBUG("HomeScreen", "Split application %s", application_id.toStdString().c_str());
121
122     fprintf(stderr, "homescreen: doing a split for app %s with orientation passed %d\n",
123                     application_id.toStdString().c_str(), orientation);
124     agl_shell_set_app_split(agl_shell, application_id.toStdString().c_str(),
125                             orientation, output);
126 }
127
128 void HomescreenHandler::appStarted(const QString& application_id)
129 {
130     struct agl_shell *agl_shell = aglShell->shell.get();
131     QPlatformNativeInterface *native = qApp->platformNativeInterface();
132     struct wl_output *output = getWlOutput(native, qApp->screens().first());
133
134     HMI_DEBUG("HomeScreen", "Activating application %s", application_id.toStdString().c_str());
135     agl_shell_activate_app(agl_shell, application_id.toStdString().c_str(), output);
136     addAppToStack(application_id);
137 }
138
139 void HomescreenHandler::appTerminated(const QString& application_id)
140 {
141     HMI_DEBUG("HomeScreen", "Application %s terminated, activating last app", application_id.toStdString().c_str());
142     if (apps_stack.contains(application_id)) {
143         apps_stack.removeOne(application_id);
144         if (!apps_stack.isEmpty())
145             appStarted(apps_stack.last());
146     }
147 }