Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for incoming application control #154

Merged
merged 18 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions shell/platform/tizen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ template("embedder") {

if (embedder_for_target) {
sources += [
"channels/app_control.cc",
pkosko marked this conversation as resolved.
Show resolved Hide resolved
"channels/app_control_channel.cc",
"channels/platform_channel.cc",
"channels/settings_channel.cc",
"channels/settings_channel_tizen.cc",
Expand All @@ -162,6 +164,7 @@ template("embedder") {
"base-utils-i18n",
"capi-appfw-application",
"capi-appfw-app-common",
"capi-appfw-app-control",
"capi-base-common",
"capi-system-info",
"capi-system-system-settings",
Expand Down
325 changes: 325 additions & 0 deletions shell/platform/tizen/channels/app_control.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app_control.h"
#include "flutter/shell/platform/tizen/channels/app_control_channel.h"

#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h"
pkosko marked this conversation as resolved.
Show resolved Hide resolved

namespace flutter {

int AppControl::next_id_ = 0;

AppControl::AppControl(app_control_h app_control) : id_(next_id_++) {
handle_ = app_control;
}

AppControl::~AppControl() {
app_control_destroy(handle_);
}

AppControlResult AppControl::GetString(std::string& str,
int func(app_control_h, char**)) {
char* op;
AppControlResult ret = func(handle_, &op);
if (!ret) {
return ret;
}
if (op != nullptr) {
str = std::string{op};
free(op);
} else {
str = "";
}
return AppControlResult(APP_CONTROL_ERROR_NONE);
}

AppControlResult AppControl::SetString(const std::string& str,
int func(app_control_h, const char*)) {
int ret = func(handle_, str.c_str());
return AppControlResult(ret);
}

bool OnAppControlExtraDataCallback(app_control_h app,
const char* key,
void* user_data) {
auto extra_data = static_cast<EncodableMap*>(user_data);
bool is_array = false;
int ret = app_control_is_extra_data_array(app, key, &is_array);
if (ret != APP_CONTROL_ERROR_NONE) {
FT_LOG(Error) << "app_control_is_extra_data_array() failed at key " << key;
return false;
}

if (is_array) {
char** strings = NULL;
pkosko marked this conversation as resolved.
Show resolved Hide resolved
int length = 0;
ret = app_control_get_extra_data_array(app, key, &strings, &length);
if (ret != APP_CONTROL_ERROR_NONE) {
FT_LOG(Error) << "app_control_get_extra_data_array() failed at key "
<< key;
return false;
}
EncodableList list;
for (int i = 0; i < length; i++) {
list.push_back(EncodableValue(std::string(strings[i])));
free(strings[i]);
}
free(strings);
extra_data->insert(
{EncodableValue(std::string(key)), EncodableValue(list)});
} else {
char* value;
pkosko marked this conversation as resolved.
Show resolved Hide resolved
ret = app_control_get_extra_data(app, key, &value);
if (ret != APP_CONTROL_ERROR_NONE) {
FT_LOG(Error) << "app_control_get_extra_data() failed at key " << key;
return false;
}
extra_data->insert(
{EncodableValue(std::string(key)), EncodableValue(std::string(value))});
free(value);
}

return true;
}

AppControlResult AppControl::GetExtraData(EncodableMap& value) {
EncodableMap extra_data;
int ret = app_control_foreach_extra_data(
bbrto21 marked this conversation as resolved.
Show resolved Hide resolved
handle_, OnAppControlExtraDataCallback, &extra_data);
if (ret == APP_CONTROL_ERROR_NONE) {
value = std::move(extra_data);
}
return AppControlResult(ret);
}

AppControlResult AppControl::SetExtraData(const EncodableMap& map) {
for (const auto& v : map) {
if (!std::holds_alternative<std::string>(v.first)) {
FT_LOG(Error) << "Key for extra data has to be string, omitting";
continue;
}
std::string key = std::get<std::string>(v.first);
AppControlResult ret = AddExtraData(key, v.second);
if (!ret) {
FT_LOG(Error) << "Invalid data at " << key << ", omitting";
continue;
}
}
return AppControlResult();
}

void AppControl::SetManager(AppControlChannel* m) {
manager_ = m;
}

AppControlChannel* AppControl::GetManager() {
return manager_;
}

AppControlResult AppControl::GetOperation(std::string& operation) {
return GetString(operation, app_control_get_operation);
}

AppControlResult AppControl::SetOperation(const std::string& operation) {
return SetString(operation, app_control_set_operation);
}

AppControlResult AppControl::GetUri(std::string& uri) {
return GetString(uri, app_control_get_uri);
}

AppControlResult AppControl::SetUri(const std::string& uri) {
return SetString(uri, app_control_set_uri);
}

AppControlResult AppControl::GetMime(std::string& mime) {
return GetString(mime, app_control_get_mime);
}

AppControlResult AppControl::SetMime(const std::string& mime) {
return SetString(mime, app_control_set_mime);
}

AppControlResult AppControl::GetCategory(std::string& category) {
return GetString(category, app_control_get_category);
}

AppControlResult AppControl::SetCategory(const std::string& category) {
return SetString(category, app_control_set_category);
}

AppControlResult AppControl::GetAppId(std::string& app_id) {
return GetString(app_id, app_control_get_app_id);
}

AppControlResult AppControl::SetAppId(const std::string& app_id) {
return SetString(app_id, app_control_set_app_id);
}

AppControlResult AppControl::GetCaller(std::string& caller) {
return GetString(caller, app_control_get_caller);
}

AppControlResult AppControl::GetLaunchMode(std::string& launch_mode) {
app_control_launch_mode_e launch_mode_e;
int ret = app_control_get_launch_mode(handle_, &launch_mode_e);
if (ret != APP_CONTROL_ERROR_NONE) {
return AppControlResult(ret);
}
launch_mode =
(launch_mode_e == APP_CONTROL_LAUNCH_MODE_SINGLE ? "single" : "group");
return AppControlResult(APP_CONTROL_ERROR_NONE);
}

AppControlResult AppControl::SetLaunchMode(const std::string& launch_mode) {
app_control_launch_mode_e launch_mode_e;
if (launch_mode.compare("single")) {
launch_mode_e = APP_CONTROL_LAUNCH_MODE_SINGLE;
} else {
launch_mode_e = APP_CONTROL_LAUNCH_MODE_GROUP;
}
int ret = app_control_set_launch_mode(handle_, launch_mode_e);
return AppControlResult(ret);
}

EncodableValue AppControl::SerializeAppControlToMap() {
std::string app_id, operation, mime, category, uri, caller_id, launch_mode;
AppControlResult results[7];
results[0] = GetAppId(app_id);
results[1] = GetOperation(operation);
results[2] = GetMime(mime);
results[3] = GetCategory(category);
results[4] = GetUri(uri);
results[5] = GetLaunchMode(launch_mode);
// Caller Id is optional.
GetCaller(caller_id);
EncodableMap extra_data;
results[6] = GetExtraData(extra_data);
for (int i = 0; i < 7; i++) {
if (!results[i]) {
return EncodableValue();
}
}
EncodableMap map;
map[EncodableValue("id")] = EncodableValue(GetId());
map[EncodableValue("appId")] = EncodableValue(app_id);
map[EncodableValue("operation")] = EncodableValue(operation);
map[EncodableValue("mime")] = EncodableValue(mime);
map[EncodableValue("category")] = EncodableValue(category);
map[EncodableValue("uri")] = EncodableValue(uri);
map[EncodableValue("callerId")] = EncodableValue(caller_id);
map[EncodableValue("launchMode")] = EncodableValue(launch_mode);
map[EncodableValue("extraData")] = EncodableValue(extra_data);

return EncodableValue(map);
}

AppControlResult AppControl::SendLaunchRequest() {
AppControlResult ret =
app_control_send_launch_request(handle_, nullptr, nullptr);
return ret;
}

AppControlResult AppControl::SendLaunchRequestWithReply(
std::shared_ptr<EventSink<EncodableValue>> reply_sink,
AppControlChannel* manager) {
SetManager(manager);
auto on_reply = [](app_control_h request, app_control_h reply,
app_control_result_e result, void* user_data) {
AppControl* app_control = static_cast<AppControl*>(user_data);
app_control_h clone = nullptr;
AppControlResult ret = app_control_clone(&clone, reply);
if (!ret) {
FT_LOG(Error) << "Could not clone app_control: " << ret.message();
return;
}

std::shared_ptr<AppControl> app_control_reply =
std::make_shared<AppControl>(clone);
EncodableMap map;
map[EncodableValue("id")] = EncodableValue(app_control->GetId());
map[EncodableValue("reply")] =
app_control_reply->SerializeAppControlToMap();
if (result == APP_CONTROL_RESULT_APP_STARTED) {
map[EncodableValue("result")] = EncodableValue("appStarted");
} else if (result == APP_CONTROL_RESULT_SUCCEEDED) {
map[EncodableValue("result")] = EncodableValue("succeeded");
} else if (result == APP_CONTROL_RESULT_FAILED) {
map[EncodableValue("result")] = EncodableValue("failed");
} else if (result == APP_CONTROL_RESULT_CANCELED) {
map[EncodableValue("result")] = EncodableValue("cancelled");
}

app_control->reply_sink_->Success(EncodableValue(map));
app_control->GetManager()->AddExistingAppControl(
std::move(app_control_reply));
};
reply_sink_ = std::move(reply_sink);
AppControlResult ret =
app_control_send_launch_request(handle_, on_reply, this);
return ret;
}

AppControlResult AppControl::SendTerminateRequest() {
AppControlResult ret = app_control_send_terminate_request(handle_);
return ret;
}

AppControlResult AppControl::Reply(std::shared_ptr<AppControl> reply,
const std::string& result) {
app_control_result_e result_e;
if (result == "appStarted") {
result_e = APP_CONTROL_RESULT_APP_STARTED;
} else if (result == "succeeded") {
result_e = APP_CONTROL_RESULT_SUCCEEDED;
} else if (result == "failed") {
result_e = APP_CONTROL_RESULT_FAILED;
} else if (result == "cancelled") {
result_e = APP_CONTROL_RESULT_CANCELED;
} else {
return AppControlResult(APP_CONTROL_ERROR_INVALID_PARAMETER);
}
AppControlResult ret = app_control_reply_to_launch_request(
reply->Handle(), this->handle_, result_e);
return ret;
}

AppControlResult AppControl::AddExtraData(std::string key,
EncodableValue value) {
bool is_array = std::holds_alternative<EncodableList>(value);
if (is_array) {
EncodableList& list = std::get<EncodableList>(value);
return AddExtraDataList(key, list);
} else {
bool is_string = std::holds_alternative<std::string>(value);
if (is_string) {
int ret = app_control_add_extra_data(
handle_, key.c_str(), std::get<std::string>(value).c_str());
return AppControlResult(ret);
} else {
return AppControlResult(APP_ERROR_INVALID_PARAMETER);
}
}
return AppControlResult(APP_CONTROL_ERROR_NONE);
}

AppControlResult AppControl::AddExtraDataList(std::string& key,
EncodableList& list) {
size_t length = list.size();
auto strings = std::vector<const char*>(length);
for (size_t i = 0; i < length; i++) {
bool is_string = std::holds_alternative<std::string>(list[i]);
if (is_string) {
strings[i] = std::get<std::string>(list[i]).c_str();
} else {
return AppControlResult(APP_ERROR_INVALID_PARAMETER);
}
}
int ret = app_control_add_extra_data_array(handle_, key.c_str(),
strings.data(), length);
return AppControlResult(ret);
}

} // namespace flutter
Loading