summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarius Vlad <marius.vlad@collabora.com>2023-10-11 12:08:16 +0300
committerMarius Vlad <marius.vlad@collabora.com>2023-10-26 00:41:50 +0300
commit36e2c9697e431414ae0263635f3ebf1f3c200723 (patch)
tree5a4c103039ee6e0a7f68c3e34248893f3425899a
parent8db829a4a790e30b5dfd27b531aa8018918fde10 (diff)
AglShellGrpcClient: Add activation with gRPC proxy
This follow-ups in footsteps of flutter-homescreen to have activation using gRPC. Note that setting up wayland surfaces is still need to have the agl-shell protocol available. In Qt this is managed directly by Qt/QPA while on other toolkits this happens at a lower level (flutter-auto or chromium CEF). With it, create a listening thread for gRRC events in order to perform the initial start + activate sequence. Bug-AGL: SPEC-4912 Signed-off-by: Marius Vlad <marius.vlad@collabora.com> Change-Id: I019d0e7944dde02c84b2841e22d3971f226d610a
-rw-r--r--homescreen/meson.build35
-rw-r--r--homescreen/proto/agl_shell.proto110
-rw-r--r--homescreen/src/AglShellGrpcClient.cpp186
-rw-r--r--homescreen/src/AglShellGrpcClient.h110
-rw-r--r--homescreen/src/homescreenhandler.cpp48
-rw-r--r--homescreen/src/homescreenhandler.h9
-rw-r--r--homescreen/src/main.cpp30
7 files changed, 486 insertions, 42 deletions
diff --git a/homescreen/meson.build b/homescreen/meson.build
index db2409d..50c644c 100644
--- a/homescreen/meson.build
+++ b/homescreen/meson.build
@@ -9,6 +9,10 @@ dep_qtappfw = [
dependency('qtappfw-applauncher')
]
+grpcpp_reflection_dep = cpp.find_library('grpc++_reflection')
+protoc = find_program('protoc')
+grpc_cpp = find_program('grpc_cpp_plugin')
+
qt_defines = []
qpa_header_path = join_paths(qt5_dep.version(), 'QtGui')
qpa_header = join_paths(qpa_header_path, 'qpa/qplatformnativeinterface.h')
@@ -24,10 +28,35 @@ prog_scanner = find_program('wayland-scanner')
agl_compositor_dep = dependency('agl-compositor-0.0.21-protocols')
dir_agl_compositor_base = agl_compositor_dep.get_variable(pkgconfig: 'pkgdatadir')
+protoc_gen = generator(protoc, \
+ output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/proto',
+ '--cpp_out=@BUILD_DIR@',
+ '@INPUT@'])
+
+generated_protoc_sources = protoc_gen.process('proto/agl_shell.proto')
+
+grpc_gen = generator(protoc, \
+ output : ['@BASENAME@.grpc.pb.cc', '@BASENAME@.grpc.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/proto',
+ '--grpc_out=@BUILD_DIR@',
+ '--plugin=protoc-gen-grpc=' + grpc_cpp.path(),
+ '@INPUT@'])
+generated_grpc_sources = grpc_gen.process('proto/agl_shell.proto')
+
+grpc_deps = [
+ dependency('protobuf'),
+ dependency('grpc'),
+ dependency('grpc++'),
+ grpcpp_reflection_dep,
+]
+
+
homescreen_dep = [
qt5_dep,
dep_wayland_client,
dep_qtappfw,
+ grpc_deps
]
homescreen_resources = [
@@ -83,6 +112,7 @@ homescreen_src_headers = [
'src/statusbarmodel.h',
'src/statusbarserver.h',
'src/homescreenhandler.h',
+ 'src/AglShellGrpcClient.h',
'src/shell.h'
]
@@ -96,9 +126,12 @@ homescreen_src = [
'src/applicationlauncher.cpp',
'src/mastervolume.cpp',
'src/homescreenhandler.cpp',
+ 'src/AglShellGrpcClient.cpp',
'src/main.cpp',
agl_shell_client_protocol_h,
- agl_shell_protocol_c
+ agl_shell_protocol_c,
+ generated_protoc_sources,
+ generated_grpc_sources
]
executable('homescreen', homescreen_src, resource_files, moc_files,
diff --git a/homescreen/proto/agl_shell.proto b/homescreen/proto/agl_shell.proto
new file mode 100644
index 0000000..c4f3dfe
--- /dev/null
+++ b/homescreen/proto/agl_shell.proto
@@ -0,0 +1,110 @@
+syntax = "proto3";
+// using empty Response suitable better for forward compat
+//import "google/protobuf/empty.proto";
+package agl_shell_ipc;
+
+service AglShellManagerService {
+ rpc ActivateApp(ActivateRequest) returns (ActivateResponse) {}
+ rpc DeactivateApp(DeactivateRequest) returns (DeactivateResponse) {}
+ rpc SetAppSplit(SplitRequest) returns (SplitResponse) {}
+ rpc SetAppFloat(FloatRequest) returns (FloatResponse) {}
+ rpc SetAppFullscreen(FullscreenRequest) returns (FullscreenResponse) {}
+ rpc AppStatusState(AppStateRequest) returns (stream AppStateResponse) {}
+ rpc GetOutputs(OutputRequest) returns (ListOutputResponse) {}
+ rpc SetAppNormal(NormalRequest) returns (NormalResponse) {}
+ rpc SetAppOnOutput(AppOnOutputRequest) returns (AppOnOutputResponse) {}
+ rpc SetAppPosition(AppPositionRequest) returns (AppPositionResponse) {}
+ rpc SetAppScale(AppScaleRequest) returns (AppScaleResponse) {}
+}
+
+message ActivateRequest {
+ string app_id = 1;
+ string output_name = 2;
+}
+
+message ActivateResponse {
+};
+
+
+message DeactivateRequest {
+ string app_id = 1;
+}
+
+message DeactivateResponse {
+}
+
+message SplitRequest {
+ string app_id = 1;
+ int32 tile_orientation = 2;
+}
+
+message SplitResponse {
+}
+
+message FloatRequest {
+ string app_id = 1;
+ int32 x_pos = 2;
+ int32 y_pos = 3;
+}
+
+message FloatResponse {
+}
+
+message AppStateRequest {
+}
+
+message AppStateResponse {
+ int32 state = 1;
+ string app_id = 2;
+}
+
+message OutputRequest {
+};
+
+message OutputResponse {
+ string name = 1;
+};
+
+message ListOutputResponse {
+ repeated OutputResponse outputs = 1;
+};
+
+message NormalRequest {
+ string app_id = 1;
+};
+
+message NormalResponse {
+};
+
+message FullscreenRequest {
+ string app_id = 1;
+};
+
+message FullscreenResponse {
+};
+
+message AppOnOutputRequest {
+ string app_id = 1;
+ string output = 2;
+};
+
+message AppOnOutputResponse {
+};
+
+message AppPositionRequest {
+ string app_id = 1;
+ int32 x = 2;
+ int32 y = 3;
+};
+
+message AppPositionResponse {
+};
+
+message AppScaleRequest {
+ string app_id = 1;
+ int32 width = 2;
+ int32 height = 3;
+};
+
+message AppScaleResponse {
+};
diff --git a/homescreen/src/AglShellGrpcClient.cpp b/homescreen/src/AglShellGrpcClient.cpp
new file mode 100644
index 0000000..6f4ff24
--- /dev/null
+++ b/homescreen/src/AglShellGrpcClient.cpp
@@ -0,0 +1,186 @@
+//include stuff here
+#include <cstdio>
+
+#include <mutex>
+#include <condition_variable>
+#include <grpc/grpc.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/health_check_service_interface.h>
+
+#include "AglShellGrpcClient.h"
+#include "agl_shell.grpc.pb.h"
+
+namespace {
+ const char kDefaultGrpcServiceAddress[] = "127.0.0.1:14005";
+}
+
+GrpcClient::GrpcClient()
+{
+ auto channel = grpc::CreateChannel(kDefaultGrpcServiceAddress,
+ grpc::InsecureChannelCredentials());
+
+ // init the stub here
+ m_stub = agl_shell_ipc::AglShellManagerService::NewStub(channel);
+ reader = new Reader(m_stub.get());
+}
+
+
+bool
+GrpcClient::ActivateApp(const std::string& app_id, const std::string& output_name)
+{
+ agl_shell_ipc::ActivateRequest request;
+
+ request.set_app_id(app_id);
+ request.set_output_name(output_name);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::ActivateResponse reply;
+
+ grpc::Status status = m_stub->ActivateApp(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::DeactivateApp(const std::string& app_id)
+{
+ agl_shell_ipc::DeactivateRequest request;
+
+ request.set_app_id(app_id);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::DeactivateResponse reply;
+
+ grpc::Status status = m_stub->DeactivateApp(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppFloat(const std::string& app_id, int32_t x_pos, int32_t y_pos)
+{
+ agl_shell_ipc::FloatRequest request;
+
+ request.set_app_id(app_id);
+
+ request.set_x_pos(x_pos);
+ request.set_y_pos(y_pos);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::FloatResponse reply;
+
+ grpc::Status status = m_stub->SetAppFloat(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppNormal(const std::string& app_id)
+{
+ agl_shell_ipc::NormalRequest request;
+
+ request.set_app_id(app_id);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::NormalResponse reply;
+
+ grpc::Status status = m_stub->SetAppNormal(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppFullscreen(const std::string& app_id)
+{
+ agl_shell_ipc::FullscreenRequest request;
+
+ request.set_app_id(app_id);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::FullscreenResponse reply;
+
+ grpc::Status status = m_stub->SetAppFullscreen(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppOnOutput(const std::string& app_id, const std::string &output)
+{
+ agl_shell_ipc::AppOnOutputRequest request;
+
+ request.set_app_id(app_id);
+ request.set_output(output);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::AppOnOutputResponse reply;
+
+ grpc::Status status = m_stub->SetAppOnOutput(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppPosition(const std::string& app_id, int32_t x, int32_t y)
+{
+ agl_shell_ipc::AppPositionRequest request;
+
+ request.set_app_id(app_id);
+ request.set_x(x);
+ request.set_y(y);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::AppPositionResponse reply;
+
+ grpc::Status status = m_stub->SetAppPosition(&context, request, &reply);
+ return status.ok();
+}
+
+bool
+GrpcClient::SetAppScale(const std::string& app_id, int32_t width, int32_t height)
+{
+ agl_shell_ipc::AppScaleRequest request;
+
+ request.set_app_id(app_id);
+ request.set_width(width);
+ request.set_height(height);
+
+ grpc::ClientContext context;
+ ::agl_shell_ipc::AppScaleResponse reply;
+
+ grpc::Status status = m_stub->SetAppScale(&context, request, &reply);
+ return status.ok();
+}
+
+
+grpc::Status
+GrpcClient::Wait(void)
+{
+ return reader->Await();
+}
+
+void
+GrpcClient::AppStatusState(Callback callback)
+{
+ reader->AppStatusState(callback);
+}
+
+std::vector<std::string>
+GrpcClient::GetOutputs()
+{
+ grpc::ClientContext context;
+ std::vector<std::string> v;
+
+ ::agl_shell_ipc::OutputRequest request;
+ ::agl_shell_ipc::ListOutputResponse response;
+
+ grpc::Status status = m_stub->GetOutputs(&context, request, &response);
+ if (!status.ok())
+ return std::vector<std::string>();
+
+ for (int i = 0; i < response.outputs_size(); i++) {
+ ::agl_shell_ipc::OutputResponse rresponse = response.outputs(i);
+ v.push_back(rresponse.name());
+ }
+
+ return v;
+}
diff --git a/homescreen/src/AglShellGrpcClient.h b/homescreen/src/AglShellGrpcClient.h
new file mode 100644
index 0000000..ff190f7
--- /dev/null
+++ b/homescreen/src/AglShellGrpcClient.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include <cstdio>
+
+#include <mutex>
+#include <condition_variable>
+#include <grpc/grpc.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/health_check_service_interface.h>
+
+#include "agl_shell.grpc.pb.h"
+
+typedef void (*Callback)(agl_shell_ipc::AppStateResponse app_response);
+
+class Reader : public grpc::ClientReadReactor<::agl_shell_ipc::AppStateResponse> {
+public:
+ Reader(agl_shell_ipc::AglShellManagerService::Stub *stub)
+ : m_stub(stub)
+ {
+ }
+
+ void AppStatusState(Callback callback)
+ {
+ ::agl_shell_ipc::AppStateRequest request;
+
+ // set up the callback
+ m_callback = callback;
+ m_stub->async()->AppStatusState(&m_context, &request, this);
+
+ StartRead(&m_app_state);
+ StartCall();
+ }
+
+ void OnReadDone(bool ok) override
+ {
+ if (ok) {
+ m_callback(m_app_state);
+
+ // blocks in StartRead() if the server doesn't send
+ // antyhing
+ StartRead(&m_app_state);
+ }
+ }
+
+ void SetDone()
+ {
+ fprintf(stderr, "%s()\n", __func__);
+ std::unique_lock<std::mutex> l(m_mutex);
+ m_done = true;
+ }
+
+ void OnDone(const grpc::Status& s) override
+ {
+ fprintf(stderr, "%s()\n", __func__);
+ std::unique_lock<std::mutex> l(m_mutex);
+
+ m_status = s;
+
+ fprintf(stderr, "%s() done\n", __func__);
+ m_cv.notify_one();
+ }
+
+ grpc::Status Await()
+ {
+ std::unique_lock<std::mutex> l(m_mutex);
+
+ m_cv.wait(l, [this] { return m_done; });
+
+ return std::move(m_status);
+ }
+private:
+ grpc::ClientContext m_context;
+ ::agl_shell_ipc::AppStateResponse m_app_state;
+ agl_shell_ipc::AglShellManagerService::Stub *m_stub;
+
+ Callback m_callback;
+
+
+ std::mutex m_mutex;
+ std::condition_variable m_cv;
+ grpc::Status m_status;
+ bool m_done = false;
+};
+
+class GrpcClient {
+public:
+ GrpcClient();
+ bool ActivateApp(const std::string& app_id, const std::string& output_name);
+ bool DeactivateApp(const std::string& app_id);
+ bool SetAppFloat(const std::string& app_id, int32_t x_pos, int32_t y_pos);
+ bool SetAppFullscreen(const std::string& app_id);
+ bool SetAppOnOutput(const std::string& app_id, const std::string& output);
+ bool SetAppNormal(const std::string& app_id);
+ bool SetAppPosition(const std::string& app_id, int32_t x, int32_t y);
+ bool SetAppScale(const std::string& app_id, int32_t width, int32_t height);
+ std::vector<std::string> GetOutputs();
+ void GetAppState();
+ void AppStatusState(Callback callback);
+ grpc::Status Wait();
+
+private:
+ Reader *reader;
+ std::unique_ptr<agl_shell_ipc::AglShellManagerService::Stub> m_stub;
+};
+
diff --git a/homescreen/src/homescreenhandler.cpp b/homescreen/src/homescreenhandler.cpp
index 9353713..d81e22f 100644
--- a/homescreen/src/homescreenhandler.cpp
+++ b/homescreen/src/homescreenhandler.cpp
@@ -5,6 +5,7 @@
*/
#include <QGuiApplication>
+#include <QScreen>
#include <QFileInfo>
#include <functional>
@@ -20,12 +21,10 @@ QScreen *find_screen(const char *output);
// a user session by systemd
#define LAUNCHER_APP_ID "launcher"
-static struct wl_output *
-getWlOutput(QPlatformNativeInterface *native, QScreen *screen);
-HomescreenHandler::HomescreenHandler(Shell *_aglShell, ApplicationLauncher *launcher, QObject *parent) :
- QObject(parent),
- aglShell(_aglShell)
+HomescreenHandler::HomescreenHandler(ApplicationLauncher *launcher, GrpcClient *_client, QObject *parent) :
+ QObject(parent)
+ , m_grpc_client(_client)
{
mp_launcher = launcher;
mp_applauncher_client = new AppLauncherClient();
@@ -43,16 +42,10 @@ HomescreenHandler::HomescreenHandler(Shell *_aglShell, ApplicationLauncher *laun
HomescreenHandler::~HomescreenHandler()
{
+ delete m_grpc_client;
delete mp_applauncher_client;
}
-static struct wl_output *
-getWlOutput(QPlatformNativeInterface *native, QScreen *screen)
-{
- void *output = native->nativeResourceForScreen("output", screen);
- return static_cast<struct ::wl_output*>(output);
-}
-
void HomescreenHandler::tapShortcut(QString app_id)
{
HMI_DEBUG("HomeScreen","tapShortcut %s", app_id.toStdString().c_str());
@@ -92,18 +85,15 @@ void HomescreenHandler::addAppToStack(const QString& app_id)
void HomescreenHandler::activateApp(const QString& app_id)
{
- struct agl_shell *agl_shell = aglShell->shell.get();
- QScreen *tmp_screen = qApp->screens().first();
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
- struct wl_output *mm_output = nullptr;
+ QScreen *default_screen = qApp->screens().first();
+ std::string default_output_name;
- if (!tmp_screen) {
- HMI_DEBUG("HomeScreen", "No output found to activate on!\n");
+ if (!default_screen) {
+ HMI_DEBUG("HomeScreen", "No default output found to activate on!\n");
} else {
- mm_output = getWlOutput(native, tmp_screen);
-
- HMI_DEBUG("HomeScreen", "Activating app_id %s by default on output %p\n",
- app_id.toStdString().c_str(), mm_output);
+ default_output_name = default_screen->name().toStdString();
+ HMI_DEBUG("HomeScreen", "Activating app_id %s by default on output %s\n",
+ app_id.toStdString().c_str(), default_output_name.c_str());
}
if (mp_launcher) {
@@ -155,27 +145,25 @@ void HomescreenHandler::activateApp(const QString& app_id)
HMI_DEBUG("HomeScreen", "Found a stream remoting output %s to activate application %s on",
new_remote_output.c_str(),
app_id.toStdString().c_str());
+ default_output_name = new_remote_output;
}
- mm_output = getWlOutput(native, screen);
pending_app_list.erase(iter);
-
HMI_DEBUG("HomeScreen", "For application %s found another "
"output to activate %s\n",
app_id.toStdString().c_str(),
- output_name.toStdString().c_str());
+ default_output_name.c_str());
}
- if (!mm_output) {
+ if (default_output_name.empty()) {
HMI_DEBUG("HomeScreen", "No suitable output found for activating %s",
app_id.toStdString().c_str());
return;
}
- HMI_DEBUG("HomeScreen", "Activating application %s",
- app_id.toStdString().c_str());
-
- agl_shell_activate_app(agl_shell, app_id.toStdString().c_str(), mm_output);
+ HMI_DEBUG("HomeScreen", "Activating application %s on output %s",
+ app_id.toStdString().c_str(), default_output_name.c_str());
+ m_grpc_client->ActivateApp(app_id.toStdString(), default_output_name);
}
void HomescreenHandler::deactivateApp(const QString& app_id)
diff --git a/homescreen/src/homescreenhandler.h b/homescreen/src/homescreenhandler.h
index 9a659a6..d95963b 100644
--- a/homescreen/src/homescreenhandler.h
+++ b/homescreen/src/homescreenhandler.h
@@ -12,8 +12,7 @@
#include "applicationlauncher.h"
#include "AppLauncherClient.h"
-
-#include "shell.h"
+#include "AglShellGrpcClient.h"
using namespace std;
@@ -21,7 +20,7 @@ class HomescreenHandler : public QObject
{
Q_OBJECT
public:
- explicit HomescreenHandler(Shell *aglShell, ApplicationLauncher *launcher = 0, QObject *parent = 0);
+ explicit HomescreenHandler(ApplicationLauncher *launcher = 0, GrpcClient *_client = nullptr, QObject *parent = 0);
~HomescreenHandler();
Q_INVOKABLE void tapShortcut(QString application_id);
@@ -42,9 +41,7 @@ public slots:
private:
ApplicationLauncher *mp_launcher;
AppLauncherClient *mp_applauncher_client;
-
- Shell *aglShell;
-
+ GrpcClient *m_grpc_client;
};
#endif // HOMESCREENHANDLER_H
diff --git a/homescreen/src/main.cpp b/homescreen/src/main.cpp
index d0bd2c3..b004fd5 100644
--- a/homescreen/src/main.cpp
+++ b/homescreen/src/main.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2016, 2017 Mentor Graphics Development (Deutschland) GmbH
* Copyright (c) 2017, 2018 TOYOTA MOTOR CORPORATION
* Copyright (c) 2022 Konsulko Group
+ * Copyright (c) 2023 Collabora, Ltd.
*/
#include <QGuiApplication>
@@ -32,6 +33,9 @@
#include "agl-shell-client-protocol.h"
#include "shell.h"
+#include <thread>
+#include "AglShellGrpcClient.h"
+
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
@@ -361,6 +365,20 @@ load_agl_shell_app(QPlatformNativeInterface *native, QQmlApplicationEngine *engi
});
}
+static void
+run_in_thread(GrpcClient *client)
+{
+ grpc::Status status = client->Wait();
+}
+
+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;
+}
+
int main(int argc, char *argv[])
{
setenv("QT_QPA_PLATFORM", "wayland", 1);
@@ -416,7 +434,6 @@ int main(int argc, char *argv[])
std::shared_ptr<struct agl_shell> agl_shell{shell_data.shell, agl_shell_destroy};
- Shell *aglShell = new Shell(agl_shell, &app);
// Import C++ class to QML
qmlRegisterType<StatusBarModel>("HomeScreen", 1, 0, "StatusBarModel");
@@ -425,7 +442,13 @@ int main(int argc, char *argv[])
ApplicationLauncher *launcher = new ApplicationLauncher();
launcher->setCurrent(QStringLiteral("launcher"));
- HomescreenHandler* homescreenHandler = new HomescreenHandler(aglShell, 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);
shell_data.homescreenHandler = homescreenHandler;
QQmlApplicationEngine engine;
@@ -436,9 +459,6 @@ int main(int argc, char *argv[])
context->setContextProperty("weather", new Weather());
context->setContextProperty("bluetooth", new Bluetooth(false, context));
- // We add it here even if we don't use it
- context->setContextProperty("shell", aglShell);
-
load_agl_shell_app(native, &engine, shell_data.shell,
screen_name, is_demo_val);