AglShellGrpcClient: Activate windows with gRPC 08/29308/2
authorMarius Vlad <marius.vlad@collabora.com>
Sun, 15 Oct 2023 12:43:51 +0000 (15:43 +0300)
committerMarius Vlad <marius.vlad@collabora.com>
Wed, 25 Oct 2023 21:41:55 +0000 (00:41 +0300)
In order to use HomescreenHandler we need to have a way to pass it, so
extend the callback mechanism to be able to pass other objects as well.

HomescreenHandler is the one that handles, indirectly, the activation
and that keeps track of the application status. We used in the direct
wayland event handler to we're going to re-use it as well.

Bug-AGL: SPEC-4912
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: I6eae6a5c4e144f3024dfcad6e5e0a54a8fec78a6

homescreen/src/AglShellGrpcClient.cpp
homescreen/src/AglShellGrpcClient.h
homescreen/src/homescreenhandler.h
homescreen/src/main.cpp

index 6f4ff24..ee7510f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <mutex>
 #include <condition_variable>
+#include <chrono>
 #include <grpc/grpc.h>
 #include <grpcpp/grpcpp.h>
 #include <grpcpp/server.h>
@@ -14,6 +15,9 @@
 
 #include "AglShellGrpcClient.h"
 #include "agl_shell.grpc.pb.h"
+#include "hmi-debug.h"
+
+using namespace std::chrono;
 
 namespace {
        const char kDefaultGrpcServiceAddress[] = "127.0.0.1:14005";
@@ -21,9 +25,25 @@ namespace {
 
 GrpcClient::GrpcClient()
 {
+       struct timespec ts;
        auto channel = grpc::CreateChannel(kDefaultGrpcServiceAddress,
                        grpc::InsecureChannelCredentials());
 
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+       ts.tv_sec = 0;
+       ts.tv_nsec = 500 * 1000 * 1000; // 500ms
+
+       bool try_to_connect = true;
+       grpc_connectivity_state state = channel->GetState(try_to_connect);
+
+       while (state != GRPC_CHANNEL_READY) {
+               state = channel->GetState(try_to_connect);
+
+               HMI_DEBUG("HomesScreen", "waiting for channel state to be ready, current state %d", state);
+               nanosleep(&ts, NULL);
+       }
+
+
        // init the stub here
        m_stub = agl_shell_ipc::AglShellManagerService::NewStub(channel);
        reader = new Reader(m_stub.get());
@@ -159,9 +179,9 @@ GrpcClient::Wait(void)
 }
 
 void
-GrpcClient::AppStatusState(Callback callback)
+GrpcClient::AppStatusState(Callback callback, void *data)
 {
-       reader->AppStatusState(callback);
+       reader->AppStatusState(callback, data);
 }
 
 std::vector<std::string>
index ff190f7..bb74377 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "agl_shell.grpc.pb.h"
 
-typedef void (*Callback)(agl_shell_ipc::AppStateResponse app_response);
+typedef void (*Callback)(agl_shell_ipc::AppStateResponse app_response, void *data);
 
 class Reader : public grpc::ClientReadReactor<::agl_shell_ipc::AppStateResponse> {
 public:
@@ -24,12 +24,13 @@ public:
        {
        }
 
-       void AppStatusState(Callback callback)
+       void AppStatusState(Callback callback, void *_data)
        {
                ::agl_shell_ipc::AppStateRequest request;
 
                // set up the callback
                m_callback = callback;
+               m_data = _data;
                m_stub->async()->AppStatusState(&m_context, &request, this);
 
                StartRead(&m_app_state);
@@ -39,7 +40,7 @@ public:
        void OnReadDone(bool ok) override
        {
                if (ok) {
-                       m_callback(m_app_state);
+                       m_callback(m_app_state, m_data);
 
                        // blocks in StartRead() if the server doesn't send
                        // antyhing
@@ -76,6 +77,7 @@ public:
 private:
        grpc::ClientContext m_context;
        ::agl_shell_ipc::AppStateResponse m_app_state;
+       void *m_data;
        agl_shell_ipc::AglShellManagerService::Stub *m_stub;
 
        Callback m_callback;
@@ -100,7 +102,7 @@ public:
        bool SetAppScale(const std::string& app_id, int32_t width, int32_t height);
        std::vector<std::string> GetOutputs();
        void GetAppState();
-       void AppStatusState(Callback callback);
+       void AppStatusState(Callback callback, void *data);
        grpc::Status Wait();
 
 private:
index d95963b..478d9fc 100644 (file)
@@ -28,6 +28,8 @@ public:
        void addAppToStack(const QString& application_id);
        void activateApp(const QString& app_id);
        void deactivateApp(const QString& app_id);
+       void setGrpcClient(GrpcClient *_client) { m_grpc_client = _client; }
+       GrpcClient *getGrpcClient(void) { return m_grpc_client; }
 
        QStringList apps_stack;
        std::list<std::pair<const QString, const QString>> pending_app_list;
index b004fd5..8598a33 100644 (file)
@@ -87,6 +87,7 @@ static void
 agl_shell_app_state(void *data, struct agl_shell *agl_shell,
                const char *app_id, uint32_t state)
 {
+#if 0
        struct shell_data *shell_data = static_cast<struct shell_data *>(data);
        HomescreenHandler *homescreenHandler = shell_data->homescreenHandler;
 
@@ -113,6 +114,7 @@ agl_shell_app_state(void *data, struct agl_shell *agl_shell,
        default:
                break;
        }
+#endif
 }
 
 static void
@@ -335,11 +337,22 @@ load_agl_shell_for_ci(QPlatformNativeInterface *native,
        qDebug() << "CI mode - with multiple surfaces";
 }
 
+static void
+app_status_callback(::agl_shell_ipc::AppStateResponse app_response, void *data);
+
+static void
+run_in_thread(GrpcClient *client)
+{
+       grpc::Status status = client->Wait();
+}
+
 static void
 load_agl_shell_app(QPlatformNativeInterface *native, QQmlApplicationEngine *engine,
-                  struct agl_shell *agl_shell, const char *screen_name, bool is_demo)
+                  struct shell_data shell_data, const char *screen_name,
+                  bool is_demo, GrpcClient *client)
 {
        QScreen *screen = nullptr;
+       HomescreenHandler *homescreenHandler = shell_data.homescreenHandler;
 
        if (!screen_name)
                screen = qApp->primaryScreen();
@@ -352,31 +365,53 @@ load_agl_shell_app(QPlatformNativeInterface *native, QQmlApplicationEngine *engi
        }
 
        if (is_demo) {
-               load_agl_shell_for_ci(native, engine, agl_shell, screen);
+               load_agl_shell_for_ci(native, engine, shell_data.shell, screen);
        } else {
-               load_agl_shell(native, engine, agl_shell, screen);
+               load_agl_shell(native, engine, shell_data.shell, screen);
        }
 
        /* Delay the ready signal until after Qt has done all of its own setup
         * in a.exec() */
-       QTimer::singleShot(500, [agl_shell](){
+       QTimer::singleShot(500, [shell_data](){
                qDebug() << "sending ready to compositor";
-               agl_shell_ready(agl_shell);
+               agl_shell_ready(shell_data.shell);
        });
 }
 
 static void
-run_in_thread(GrpcClient *client)
+app_status_callback(::agl_shell_ipc::AppStateResponse app_response, void *data)
 {
-        grpc::Status status = client->Wait();
-}
+       HomescreenHandler *homescreenHandler = static_cast<HomescreenHandler *>(data);
 
-static void
-app_status_callback(::agl_shell_ipc::AppStateResponse app_response)
-{
-       std::cout << " >> AppStateResponse app_id " <<
-               app_response.app_id() << ", with state " <<
-               app_response.state() << std::endl;
+       if (!homescreenHandler) {
+               return;
+       }
+
+       auto app_id = QString(app_response.app_id().c_str());
+       auto state = app_response.state();
+
+       qDebug() << "appstateresponse: app_id " << app_id << "state " << state;
+
+       switch (state) {
+       case AGL_SHELL_APP_STATE_STARTED:
+               qDebug() << "Got AGL_SHELL_APP_STATE_STARTED for app_id " << app_id;
+               homescreenHandler->processAppStatusEvent(app_id, "started");
+               break;
+       case AGL_SHELL_APP_STATE_TERMINATED:
+               qDebug() << "Got AGL_SHELL_APP_STATE_TERMINATED for app_id " << app_id;
+               // handled by HomescreenHandler::processAppStatusEvent
+               break;
+       case AGL_SHELL_APP_STATE_ACTIVATED:
+               qDebug() << "Got AGL_SHELL_APP_STATE_ACTIVATED for app_id " << app_id;
+               homescreenHandler->addAppToStack(app_id);
+               break;
+       case AGL_SHELL_APP_STATE_DEACTIVATED:
+               qDebug() << "Got AGL_SHELL_APP_STATE_DEACTIVATED for app_id " << app_id;
+               homescreenHandler->processAppStatusEvent(app_id, "deactivated");
+               break;
+       default:
+               break;
+       }
 }
 
 int main(int argc, char *argv[])
@@ -410,6 +445,7 @@ int main(int argc, char *argv[])
        // we need to have an app_id
        app.setDesktopFileName("homescreen");
 
+
        register_agl_shell(native, &shell_data);
        if (!shell_data.shell) {
                fprintf(stderr, "agl_shell extension is not advertised. "
@@ -435,6 +471,10 @@ int main(int argc, char *argv[])
 
        std::shared_ptr<struct agl_shell> agl_shell{shell_data.shell, agl_shell_destroy};
 
+       GrpcClient *client = new GrpcClient();
+       // create a new thread to listner for gRPC events
+       std::thread th = std::thread(run_in_thread, client);
+
        // Import C++ class to QML
        qmlRegisterType<StatusBarModel>("HomeScreen", 1, 0, "StatusBarModel");
        qmlRegisterType<MasterVolume>("MasterVolume", 1, 0, "MasterVolume");
@@ -442,14 +482,11 @@ int main(int argc, char *argv[])
        ApplicationLauncher *launcher = new ApplicationLauncher();
        launcher->setCurrent(QStringLiteral("launcher"));
 
-       GrpcClient *client = new GrpcClient();
-
-       // create a new thread to listner for gRPC events
-       std::thread th = std::thread(run_in_thread, client);
-       client->AppStatusState(app_status_callback);
-
-       HomescreenHandler* homescreenHandler = new HomescreenHandler(launcher, client);
+       HomescreenHandler* homescreenHandler = new HomescreenHandler(launcher);
        shell_data.homescreenHandler = homescreenHandler;
+       shell_data.homescreenHandler->setGrpcClient(client);
+
+       client->AppStatusState(app_status_callback, homescreenHandler);
 
        QQmlApplicationEngine engine;
        QQmlContext *context = engine.rootContext();
@@ -459,8 +496,8 @@ int main(int argc, char *argv[])
        context->setContextProperty("weather", new Weather());
        context->setContextProperty("bluetooth", new Bluetooth(false, context));
 
-       load_agl_shell_app(native, &engine, shell_data.shell,
-                          screen_name, is_demo_val);
+       load_agl_shell_app(native, &engine, shell_data,
+                          screen_name, is_demo_val, client);
 
        return app.exec();
 }