|
| 1 | +// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +#include "app_control.h" |
| 6 | +#include "flutter/shell/platform/common/client_wrapper/include/flutter/event_stream_handler_functions.h" |
| 7 | +#include "flutter/shell/platform/tizen/channels/app_control_channel.h" |
| 8 | + |
| 9 | +namespace flutter { |
| 10 | + |
| 11 | +int AppControl::next_id_ = 0; |
| 12 | + |
| 13 | +AppControl::AppControl(app_control_h app_control) : id_(next_id_++) { |
| 14 | + handle_ = app_control; |
| 15 | +} |
| 16 | + |
| 17 | +AppControl::~AppControl() { |
| 18 | + app_control_destroy(handle_); |
| 19 | +} |
| 20 | + |
| 21 | +AppControlResult AppControl::GetString(std::string& str, |
| 22 | + int func(app_control_h, char**)) { |
| 23 | + char* op; |
| 24 | + AppControlResult ret = func(handle_, &op); |
| 25 | + if (!ret) { |
| 26 | + return ret; |
| 27 | + } |
| 28 | + if (op != nullptr) { |
| 29 | + str = std::string{op}; |
| 30 | + free(op); |
| 31 | + } else { |
| 32 | + str = ""; |
| 33 | + } |
| 34 | + return AppControlResult(APP_CONTROL_ERROR_NONE); |
| 35 | +} |
| 36 | + |
| 37 | +AppControlResult AppControl::SetString(const std::string& str, |
| 38 | + int func(app_control_h, const char*)) { |
| 39 | + int ret = func(handle_, str.c_str()); |
| 40 | + return AppControlResult(ret); |
| 41 | +} |
| 42 | + |
| 43 | +bool OnAppControlExtraDataCallback(app_control_h app, |
| 44 | + const char* key, |
| 45 | + void* user_data) { |
| 46 | + auto extra_data = static_cast<EncodableMap*>(user_data); |
| 47 | + bool is_array = false; |
| 48 | + int ret = app_control_is_extra_data_array(app, key, &is_array); |
| 49 | + if (ret != APP_CONTROL_ERROR_NONE) { |
| 50 | + FT_LOG(Error) << "app_control_is_extra_data_array() failed at key " << key; |
| 51 | + return false; |
| 52 | + } |
| 53 | + |
| 54 | + if (is_array) { |
| 55 | + char** strings = nullptr; |
| 56 | + int length = 0; |
| 57 | + ret = app_control_get_extra_data_array(app, key, &strings, &length); |
| 58 | + if (ret != APP_CONTROL_ERROR_NONE) { |
| 59 | + FT_LOG(Error) << "app_control_get_extra_data_array() failed at key " |
| 60 | + << key; |
| 61 | + return false; |
| 62 | + } |
| 63 | + EncodableList list; |
| 64 | + for (int i = 0; i < length; i++) { |
| 65 | + list.push_back(EncodableValue(std::string(strings[i]))); |
| 66 | + free(strings[i]); |
| 67 | + } |
| 68 | + free(strings); |
| 69 | + extra_data->insert( |
| 70 | + {EncodableValue(std::string(key)), EncodableValue(list)}); |
| 71 | + } else { |
| 72 | + char* value = nullptr; |
| 73 | + ret = app_control_get_extra_data(app, key, &value); |
| 74 | + if (ret != APP_CONTROL_ERROR_NONE) { |
| 75 | + FT_LOG(Error) << "app_control_get_extra_data() failed at key " << key; |
| 76 | + return false; |
| 77 | + } |
| 78 | + extra_data->insert( |
| 79 | + {EncodableValue(std::string(key)), EncodableValue(std::string(value))}); |
| 80 | + free(value); |
| 81 | + } |
| 82 | + |
| 83 | + return true; |
| 84 | +} |
| 85 | + |
| 86 | +AppControlResult AppControl::GetExtraData(EncodableMap& value) { |
| 87 | + EncodableMap extra_data; |
| 88 | + int ret = app_control_foreach_extra_data( |
| 89 | + handle_, OnAppControlExtraDataCallback, &extra_data); |
| 90 | + if (ret == APP_CONTROL_ERROR_NONE) { |
| 91 | + value = std::move(extra_data); |
| 92 | + } |
| 93 | + return AppControlResult(ret); |
| 94 | +} |
| 95 | + |
| 96 | +AppControlResult AppControl::SetExtraData(const EncodableMap& map) { |
| 97 | + for (const auto& v : map) { |
| 98 | + if (!std::holds_alternative<std::string>(v.first)) { |
| 99 | + FT_LOG(Error) << "Key for extra data has to be string, omitting"; |
| 100 | + continue; |
| 101 | + } |
| 102 | + std::string key = std::get<std::string>(v.first); |
| 103 | + AppControlResult ret = AddExtraData(key, v.second); |
| 104 | + if (!ret) { |
| 105 | + FT_LOG(Error) << "Invalid data at " << key << ", omitting"; |
| 106 | + continue; |
| 107 | + } |
| 108 | + } |
| 109 | + return AppControlResult(); |
| 110 | +} |
| 111 | + |
| 112 | +void AppControl::SetManager(AppControlChannel* m) { |
| 113 | + manager_ = m; |
| 114 | +} |
| 115 | + |
| 116 | +AppControlChannel* AppControl::GetManager() { |
| 117 | + return manager_; |
| 118 | +} |
| 119 | + |
| 120 | +AppControlResult AppControl::GetOperation(std::string& operation) { |
| 121 | + return GetString(operation, app_control_get_operation); |
| 122 | +} |
| 123 | + |
| 124 | +AppControlResult AppControl::SetOperation(const std::string& operation) { |
| 125 | + return SetString(operation, app_control_set_operation); |
| 126 | +} |
| 127 | + |
| 128 | +AppControlResult AppControl::GetUri(std::string& uri) { |
| 129 | + return GetString(uri, app_control_get_uri); |
| 130 | +} |
| 131 | + |
| 132 | +AppControlResult AppControl::SetUri(const std::string& uri) { |
| 133 | + return SetString(uri, app_control_set_uri); |
| 134 | +} |
| 135 | + |
| 136 | +AppControlResult AppControl::GetMime(std::string& mime) { |
| 137 | + return GetString(mime, app_control_get_mime); |
| 138 | +} |
| 139 | + |
| 140 | +AppControlResult AppControl::SetMime(const std::string& mime) { |
| 141 | + return SetString(mime, app_control_set_mime); |
| 142 | +} |
| 143 | + |
| 144 | +AppControlResult AppControl::GetCategory(std::string& category) { |
| 145 | + return GetString(category, app_control_get_category); |
| 146 | +} |
| 147 | + |
| 148 | +AppControlResult AppControl::SetCategory(const std::string& category) { |
| 149 | + return SetString(category, app_control_set_category); |
| 150 | +} |
| 151 | + |
| 152 | +AppControlResult AppControl::GetAppId(std::string& app_id) { |
| 153 | + return GetString(app_id, app_control_get_app_id); |
| 154 | +} |
| 155 | + |
| 156 | +AppControlResult AppControl::SetAppId(const std::string& app_id) { |
| 157 | + return SetString(app_id, app_control_set_app_id); |
| 158 | +} |
| 159 | + |
| 160 | +AppControlResult AppControl::GetCaller(std::string& caller) { |
| 161 | + return GetString(caller, app_control_get_caller); |
| 162 | +} |
| 163 | + |
| 164 | +AppControlResult AppControl::GetLaunchMode(std::string& launch_mode) { |
| 165 | + app_control_launch_mode_e launch_mode_e; |
| 166 | + int ret = app_control_get_launch_mode(handle_, &launch_mode_e); |
| 167 | + if (ret != APP_CONTROL_ERROR_NONE) { |
| 168 | + return AppControlResult(ret); |
| 169 | + } |
| 170 | + launch_mode = |
| 171 | + (launch_mode_e == APP_CONTROL_LAUNCH_MODE_SINGLE ? "single" : "group"); |
| 172 | + return AppControlResult(APP_CONTROL_ERROR_NONE); |
| 173 | +} |
| 174 | + |
| 175 | +AppControlResult AppControl::SetLaunchMode(const std::string& launch_mode) { |
| 176 | + app_control_launch_mode_e launch_mode_e; |
| 177 | + if (launch_mode.compare("single")) { |
| 178 | + launch_mode_e = APP_CONTROL_LAUNCH_MODE_SINGLE; |
| 179 | + } else { |
| 180 | + launch_mode_e = APP_CONTROL_LAUNCH_MODE_GROUP; |
| 181 | + } |
| 182 | + int ret = app_control_set_launch_mode(handle_, launch_mode_e); |
| 183 | + return AppControlResult(ret); |
| 184 | +} |
| 185 | + |
| 186 | +EncodableValue AppControl::SerializeAppControlToMap() { |
| 187 | + std::string app_id, operation, mime, category, uri, caller_id, launch_mode; |
| 188 | + AppControlResult results[7]; |
| 189 | + results[0] = GetAppId(app_id); |
| 190 | + results[1] = GetOperation(operation); |
| 191 | + results[2] = GetMime(mime); |
| 192 | + results[3] = GetCategory(category); |
| 193 | + results[4] = GetUri(uri); |
| 194 | + results[5] = GetLaunchMode(launch_mode); |
| 195 | + // Caller Id is optional. |
| 196 | + GetCaller(caller_id); |
| 197 | + EncodableMap extra_data; |
| 198 | + results[6] = GetExtraData(extra_data); |
| 199 | + for (int i = 0; i < 7; i++) { |
| 200 | + if (!results[i]) { |
| 201 | + return EncodableValue(); |
| 202 | + } |
| 203 | + } |
| 204 | + EncodableMap map; |
| 205 | + map[EncodableValue("id")] = EncodableValue(GetId()); |
| 206 | + map[EncodableValue("appId")] = EncodableValue(app_id); |
| 207 | + map[EncodableValue("operation")] = EncodableValue(operation); |
| 208 | + map[EncodableValue("mime")] = EncodableValue(mime); |
| 209 | + map[EncodableValue("category")] = EncodableValue(category); |
| 210 | + map[EncodableValue("uri")] = EncodableValue(uri); |
| 211 | + map[EncodableValue("callerId")] = EncodableValue(caller_id); |
| 212 | + map[EncodableValue("launchMode")] = EncodableValue(launch_mode); |
| 213 | + map[EncodableValue("extraData")] = EncodableValue(extra_data); |
| 214 | + |
| 215 | + return EncodableValue(map); |
| 216 | +} |
| 217 | + |
| 218 | +AppControlResult AppControl::SendLaunchRequest() { |
| 219 | + AppControlResult ret = |
| 220 | + app_control_send_launch_request(handle_, nullptr, nullptr); |
| 221 | + return ret; |
| 222 | +} |
| 223 | + |
| 224 | +AppControlResult AppControl::SendLaunchRequestWithReply( |
| 225 | + std::shared_ptr<EventSink<EncodableValue>> reply_sink, |
| 226 | + AppControlChannel* manager) { |
| 227 | + SetManager(manager); |
| 228 | + auto on_reply = [](app_control_h request, app_control_h reply, |
| 229 | + app_control_result_e result, void* user_data) { |
| 230 | + AppControl* app_control = static_cast<AppControl*>(user_data); |
| 231 | + app_control_h clone = nullptr; |
| 232 | + AppControlResult ret = app_control_clone(&clone, reply); |
| 233 | + if (!ret) { |
| 234 | + FT_LOG(Error) << "Could not clone app_control: " << ret.message(); |
| 235 | + return; |
| 236 | + } |
| 237 | + |
| 238 | + std::shared_ptr<AppControl> app_control_reply = |
| 239 | + std::make_shared<AppControl>(clone); |
| 240 | + EncodableMap map; |
| 241 | + map[EncodableValue("id")] = EncodableValue(app_control->GetId()); |
| 242 | + map[EncodableValue("reply")] = |
| 243 | + app_control_reply->SerializeAppControlToMap(); |
| 244 | + if (result == APP_CONTROL_RESULT_APP_STARTED) { |
| 245 | + map[EncodableValue("result")] = EncodableValue("appStarted"); |
| 246 | + } else if (result == APP_CONTROL_RESULT_SUCCEEDED) { |
| 247 | + map[EncodableValue("result")] = EncodableValue("succeeded"); |
| 248 | + } else if (result == APP_CONTROL_RESULT_FAILED) { |
| 249 | + map[EncodableValue("result")] = EncodableValue("failed"); |
| 250 | + } else if (result == APP_CONTROL_RESULT_CANCELED) { |
| 251 | + map[EncodableValue("result")] = EncodableValue("cancelled"); |
| 252 | + } |
| 253 | + |
| 254 | + app_control->reply_sink_->Success(EncodableValue(map)); |
| 255 | + app_control->GetManager()->AddExistingAppControl( |
| 256 | + std::move(app_control_reply)); |
| 257 | + }; |
| 258 | + reply_sink_ = std::move(reply_sink); |
| 259 | + AppControlResult ret = |
| 260 | + app_control_send_launch_request(handle_, on_reply, this); |
| 261 | + return ret; |
| 262 | +} |
| 263 | + |
| 264 | +AppControlResult AppControl::SendTerminateRequest() { |
| 265 | + AppControlResult ret = app_control_send_terminate_request(handle_); |
| 266 | + return ret; |
| 267 | +} |
| 268 | + |
| 269 | +AppControlResult AppControl::Reply(std::shared_ptr<AppControl> reply, |
| 270 | + const std::string& result) { |
| 271 | + app_control_result_e result_e; |
| 272 | + if (result == "appStarted") { |
| 273 | + result_e = APP_CONTROL_RESULT_APP_STARTED; |
| 274 | + } else if (result == "succeeded") { |
| 275 | + result_e = APP_CONTROL_RESULT_SUCCEEDED; |
| 276 | + } else if (result == "failed") { |
| 277 | + result_e = APP_CONTROL_RESULT_FAILED; |
| 278 | + } else if (result == "cancelled") { |
| 279 | + result_e = APP_CONTROL_RESULT_CANCELED; |
| 280 | + } else { |
| 281 | + return AppControlResult(APP_CONTROL_ERROR_INVALID_PARAMETER); |
| 282 | + } |
| 283 | + AppControlResult ret = app_control_reply_to_launch_request( |
| 284 | + reply->Handle(), this->handle_, result_e); |
| 285 | + return ret; |
| 286 | +} |
| 287 | + |
| 288 | +AppControlResult AppControl::AddExtraData(std::string key, |
| 289 | + EncodableValue value) { |
| 290 | + bool is_array = std::holds_alternative<EncodableList>(value); |
| 291 | + if (is_array) { |
| 292 | + EncodableList& list = std::get<EncodableList>(value); |
| 293 | + return AddExtraDataList(key, list); |
| 294 | + } else { |
| 295 | + bool is_string = std::holds_alternative<std::string>(value); |
| 296 | + if (is_string) { |
| 297 | + int ret = app_control_add_extra_data( |
| 298 | + handle_, key.c_str(), std::get<std::string>(value).c_str()); |
| 299 | + return AppControlResult(ret); |
| 300 | + } else { |
| 301 | + return AppControlResult(APP_ERROR_INVALID_PARAMETER); |
| 302 | + } |
| 303 | + } |
| 304 | + return AppControlResult(APP_CONTROL_ERROR_NONE); |
| 305 | +} |
| 306 | + |
| 307 | +AppControlResult AppControl::AddExtraDataList(std::string& key, |
| 308 | + EncodableList& list) { |
| 309 | + size_t length = list.size(); |
| 310 | + auto strings = std::vector<const char*>(length); |
| 311 | + for (size_t i = 0; i < length; i++) { |
| 312 | + bool is_string = std::holds_alternative<std::string>(list[i]); |
| 313 | + if (is_string) { |
| 314 | + strings[i] = std::get<std::string>(list[i]).c_str(); |
| 315 | + } else { |
| 316 | + return AppControlResult(APP_ERROR_INVALID_PARAMETER); |
| 317 | + } |
| 318 | + } |
| 319 | + int ret = app_control_add_extra_data_array(handle_, key.c_str(), |
| 320 | + strings.data(), length); |
| 321 | + return AppControlResult(ret); |
| 322 | +} |
| 323 | + |
| 324 | +} // namespace flutter |
0 commit comments