Skip to content

Commit 57f7452

Browse files
rwalczynapkosko
authored andcommitted
Add support for incoming application control (#154)
* [AppControl] Add support for reading operation from app_control Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add EventChannel and queue for app controls Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add basic operations for AppControl Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Refactor extra data to use EncodableValue Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Refactor HandleMethodCall Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Refactor Event, Send and Terminate logic Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add support for extra data and dispose Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add support for reply Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add support for launch mode and organize logs Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Fix bugs with not saving app control on reply and with double launch Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Update logs and comments Signed-off-by: Rafal Walczyna <[email protected]> * Run code formatter Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Fixes after code review Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Add missing files Signed-off-by: Rafal Walczyna <[email protected]> * [AppControl] Changel enums to lowerCase Signed-off-by: Rafal Walczyna <[email protected]> * [appcontrol] Fixes after review * renamings * missing empty lines or dots * changed way of returning extra data * masking of app_control in flutter_tizen_engine.* and flutter_tizen.* files * [appcontrol] Few more fixes for review * [appcontrol] Removed unnecessary code and initialized poiters with nullptr Co-authored-by: Piotr Kosko/Tizen API (PLT) /SRPOL/Engineer/Samsung Electronics <[email protected]>
1 parent 2c6fb27 commit 57f7452

9 files changed

+831
-0
lines changed

shell/platform/tizen/BUILD.gn

+3
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ template("embedder") {
150150

151151
if (embedder_for_target) {
152152
sources += [
153+
"channels/app_control.cc",
154+
"channels/app_control_channel.cc",
153155
"channels/platform_channel.cc",
154156
"channels/settings_channel.cc",
155157
"channels/settings_channel_tizen.cc",
@@ -162,6 +164,7 @@ template("embedder") {
162164
"base-utils-i18n",
163165
"capi-appfw-application",
164166
"capi-appfw-app-common",
167+
"capi-appfw-app-control",
165168
"capi-base-common",
166169
"capi-system-info",
167170
"capi-system-system-settings",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
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

Comments
 (0)