Change unittest package name and improves code coverage
[platform/core/appfw/appcore-widget.git] / src / efl_base / widget_app.cc
1 /*
2 * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <Elementary.h>
18 #include <app_event_internal.hh>
19 #include <aul.h>
20 #include <aul_app_com.h>
21 #include <aul_widget.h>
22 #include <dlog.h>
23 #include <glib.h>
24 #include <stdlib.h>
25 #include <system_info.h>
26 #include <widget_errno.h>
27 #include <widget_instance.h>
28
29 #include <stdexcept>
30
31 #include "common/export_private.hh"
32 #include "common/log_private.hh"
33 #include "include/widget_app.h"
34 #include "include/widget_app_internal.h"
35 #include "include/widget_base.hh"
36
37 using namespace tizen_cpp;
38 namespace {
39
40 constexpr const int kIconifyTimeout = 500;
41 constexpr const char kFeatureShellAppWidget[] =
42     "http://tizen.org/feature/shell.appwidget";
43 constexpr int APP_EVENT_MAX = static_cast<int>(IAppCore::IEvent::Type::END);
44 constexpr IAppCore::IEvent::Type __app_event_converter[APP_EVENT_MAX] = {
45   [APP_EVENT_LOW_MEMORY] = IAppCore::IEvent::Type::LOW_MEMORY,
46   [APP_EVENT_LOW_BATTERY] = IAppCore::IEvent::Type::LOW_BATTERY,
47   [APP_EVENT_LANGUAGE_CHANGED] = IAppCore::IEvent::Type::LANG_CHANGE,
48   [APP_EVENT_DEVICE_ORIENTATION_CHANGED]
49       = IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED,
50   [APP_EVENT_REGION_FORMAT_CHANGED] = IAppCore::IEvent::Type::REGION_CHANGE,
51   [APP_EVENT_SUSPENDED_STATE_CHANGED]
52       = IAppCore::IEvent::Type::SUSPENDED_STATE_CHANGE,
53   [APP_EVENT_UPDATE_REQUESTED] = IAppCore::IEvent::Type::UPDATE_REQUESTED,
54   [APP_EVENT_TIME_ZONE_CHANGED] = IAppCore::IEvent::Type::TIME_ZONE_CHANGED,
55 };
56
57 class AppWidget : public WidgetBase {
58  public:
59   AppWidget(widget_app_lifecycle_callback_s* callback, void* user_data)
60       : callback_(callback), user_data_(user_data) {}
61
62   int OnCreate() override {
63     WidgetBase::OnCreate();
64     if (callback_ && callback_->create) {
65       if (callback_->create(user_data_) == nullptr) {
66         _E("Failed to create widget");
67         return -1;
68       }
69
70       _D("Widget app is created");
71       aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
72       return 0;
73     }
74
75     return -1;
76   }
77
78   int OnTerminate() override {
79     if (callback_ && callback_->terminate) {
80       callback_->terminate(user_data_);
81       WidgetBase::OnTerminate();
82       _D("Widget app is terminated");
83       aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
84       return 0;
85     }
86
87     WidgetBase::OnTerminate();
88     return -1;
89   }
90 /* LCOV_EXCL_START */
91   void OnLoopInit(int argc, char** argv) override {
92     elm_init(argc, argv);
93   }
94
95   void OnLoopFinish() override {
96     elm_shutdown();
97   }
98
99   void OnLoopRun() override {
100     elm_run();
101   }
102 /* LCOV_EXCL_STOP */
103   void OnLoopExit() override {
104     elm_exit();
105   }
106 /* LCOV_EXCL_START */
107   int OnTrimMemory() override {
108     _D("Trim memory");
109     elm_cache_all_flush();
110     return WidgetBase::OnTrimMemory();
111   }
112 /* LCOV_EXCL_STOP */
113  private:
114   widget_app_lifecycle_callback_s* callback_;
115   void* user_data_;
116 };
117
118 class AppWidgetContext : public WidgetContext {
119  public:
120   class Factory : public AppCoreMultiWindowBase::Context::IFactory {
121    public:
122     Factory(std::string widget_id,
123         widget_instance_lifecycle_callback_s callback, void* user_data)
124         : widget_id_(std::move(widget_id)),
125           callback_(callback),
126           user_data_(user_data) {
127     }
128
129     std::unique_ptr<Context> Create(std::string inst_id,
130         AppCoreMultiWindowBase* app) override {
131       return std::unique_ptr<Context>(
132           new AppWidgetContext(widget_id_, std::move(inst_id), app,
133               callback_, user_data_));
134     }
135
136    private:
137     std::string widget_id_;
138     widget_instance_lifecycle_callback_s callback_;
139     void* user_data_;
140   };
141
142   AppWidgetContext(std::string context_id, std::string inst_id,
143       AppCoreMultiWindowBase* app,
144       widget_instance_lifecycle_callback_s callback, void* user_data)
145       : WidgetContext(std::move(context_id), std::move(inst_id), app),
146           callback_(callback), user_data_(user_data) {}
147
148   bool OnCreate(const tizen_base::Bundle& contents, int w, int h) override {
149     int ret = -1;
150     if (callback_.create) {
151       ret = callback_.create(reinterpret_cast<widget_context_h>(this),
152           contents.GetHandle(), w, h, user_data_);
153       aul_widget_write_log(LOG_TAG, "[%s:%d]  ret : %d",
154           __FUNCTION__, __LINE__, ret);
155     }
156
157     return ret == 0;
158   }
159
160   void OnDestroy(DestroyType reason,
161       const tizen_base::Bundle& contents) override {
162     if (callback_.destroy) {
163       callback_.destroy(reinterpret_cast<widget_context_h>(this),
164           reason == DestroyType::PERMANENT ? WIDGET_APP_DESTROY_TYPE_PERMANENT :
165           WIDGET_APP_DESTROY_TYPE_TEMPORARY, contents.GetHandle(), user_data_);
166       aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
167     }
168
169     UnsetIconifyTimer();
170   }
171
172   void OnPause() override {
173     UnsetIconifyTimer();
174     SetIconifyTimer();
175
176     WidgetContext::OnPause();
177     if (callback_.pause) {
178       callback_.pause(reinterpret_cast<widget_context_h>(this), user_data_);
179     }
180   }
181
182   void OnResume() override {
183     UnsetIconifyTimer();
184
185     if (is_iconified_) {
186       Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
187           ecore_evas_ecore_evas_get(evas_object_evas_get(win_)));
188       if (win) {
189         ecore_wl2_window_iconified_set(win, EINA_FALSE);
190         is_iconified_ = false;
191         _D("Set iconify false");
192       }
193     }
194
195     WidgetContext::OnResume();
196     if (callback_.resume) {
197       callback_.resume(reinterpret_cast<widget_context_h>(this), user_data_);
198     }
199   }
200
201   void OnResize(int w, int h) override {
202     WidgetContext::OnResize(w, h);
203
204     if (win_)
205       evas_object_resize(win_, w, h);
206     else
207       _E("Failed to find window");
208
209     if (callback_.resize) {
210       callback_.resize(reinterpret_cast<widget_context_h>(this),
211           w, h, user_data_);
212     }
213   }
214
215   void OnUpdate(const tizen_base::Bundle& contents, bool force) override {
216     WidgetContext::OnUpdate(contents, force);
217     if (callback_.update) {
218       callback_.update(reinterpret_cast<widget_context_h>(this),
219           contents.GetHandle(), force, user_data_);
220     }
221   }
222
223   void SetTag(void* tag) {
224     tag_ = tag;
225   }
226
227   void* GetTag() const {
228     return tag_;
229   }
230
231   Evas_Object* GetWindow() const {
232     return win_;
233   }
234
235   void SetWindow(Evas_Object* win) {
236     win_ = win;
237   }
238
239  private:
240 /* LCOV_EXCL_START */
241   void SetIconifyTimer() {
242     if (iconify_timer_)
243       return;
244
245     iconify_timer_ = g_timeout_add(kIconifyTimeout,
246         [](gpointer user_data) -> gboolean{
247           AppWidgetContext* cxt = static_cast<AppWidgetContext*>(user_data);
248           Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
249               ecore_evas_ecore_evas_get(evas_object_evas_get(cxt->win_)));
250           if (win) {
251             ecore_wl2_window_iconified_set(win, EINA_TRUE);
252             cxt->is_iconified_ = true;
253             _D("Set iconify true");
254           }
255
256           cxt->iconify_timer_ = 0;
257           return G_SOURCE_REMOVE;
258         }, this);
259   }
260 /* LCOV_EXCL_STOP */
261   void UnsetIconifyTimer() {
262     if (iconify_timer_) {
263       g_source_remove(iconify_timer_);
264       iconify_timer_ = 0;
265     }
266   }
267
268  private:
269   widget_instance_lifecycle_callback_s callback_;
270   void* user_data_;
271   Evas_Object* win_ = nullptr;
272   guint iconify_timer_ = 0;
273   bool is_iconified_ = false;
274   void* tag_ = nullptr;
275 };
276
277 std::unique_ptr<AppWidget> __app_widget;
278 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
279
280 }  // namespace
281
282 API int widget_app_main(int argc, char** argv,
283     widget_app_lifecycle_callback_s* callback, void* user_data) {
284   bool feature;
285   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
286   if (ret < 0)
287     return WIDGET_ERROR_FAULT;
288
289   if (!feature)
290     return WIDGET_ERROR_NOT_SUPPORTED;
291
292   if (argc <= 0 || argv == nullptr || callback == nullptr) {
293     _E("Invalid parameter");
294     return WIDGET_ERROR_INVALID_PARAMETER;
295   }
296
297   if (callback->create == nullptr) {
298     _E("widget_app_create_cb() callback must be registered");/* LCOV_EXCL_LINE */
299     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
300   }
301
302   try {
303     __app_widget = std::make_unique<AppWidget>(callback, user_data);
304     for (auto& i : __pending_app_events)
305       __app_widget->AddEvent(i);
306
307     __app_widget->Run(argc, argv);
308   } catch (std::runtime_error& e) {/* LCOV_EXCL_LINE */
309     return WIDGET_ERROR_FAULT;/* LCOV_EXCL_LINE */
310   }
311
312   return WIDGET_ERROR_NONE;
313 }
314
315 API int widget_app_exit(void) {
316   bool feature;
317   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
318   if (ret < 0)
319     return WIDGET_ERROR_FAULT;
320
321   if (!feature)
322     return WIDGET_ERROR_NOT_SUPPORTED;
323
324   if (__app_widget.get() == nullptr)
325     return WIDGET_ERROR_FAULT;
326
327   __app_widget->Exit();
328   return WIDGET_ERROR_NONE;
329 }
330
331 API int widget_app_terminate_context(widget_context_h context) {
332   bool feature;
333   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
334   if (ret < 0)
335     return WIDGET_ERROR_FAULT;
336
337   if (!feature)
338     return WIDGET_ERROR_NOT_SUPPORTED;
339
340   if (context == nullptr) {
341     _E("Invalid parameter");/* LCOV_EXCL_LINE */
342     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
343   }
344
345   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
346   cxt->ExitAsync();
347   return WIDGET_ERROR_NONE;
348 }
349
350 API int widget_app_foreach_context(widget_context_cb cb, void* data) {
351   bool feature;
352   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
353   if (ret < 0)
354     return WIDGET_ERROR_FAULT;
355
356   if (!feature)
357     return WIDGET_ERROR_NOT_SUPPORTED;
358
359   if (cb == nullptr) {
360     _E("Invalid parameter");/* LCOV_EXCL_LINE */
361     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
362   }
363
364   if (__app_widget.get() == nullptr)
365     return WIDGET_ERROR_FAULT;
366
367   auto l = __app_widget->GetContexts();
368   for (auto& i : l) {
369     if (!cb(reinterpret_cast<widget_context_h>(i.get()), data))
370       break;
371   }
372
373   return WIDGET_ERROR_NONE;
374 }
375
376 API int widget_app_add_event_handler(app_event_handler_h* event_handler,
377     app_event_type_e event_type, app_event_cb callback, void* user_data) {
378   bool feature;
379   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
380   if (ret < 0)
381     return WIDGET_ERROR_FAULT;
382
383   if (!feature)
384     return WIDGET_ERROR_NOT_SUPPORTED;
385
386   if (event_handler == nullptr || callback == nullptr)
387     return WIDGET_ERROR_INVALID_PARAMETER;
388
389   if (event_type < APP_EVENT_LOW_MEMORY ||
390       event_type > APP_EVENT_TIME_ZONE_CHANGED)
391     return WIDGET_ERROR_INVALID_PARAMETER;
392
393   if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
394     return WIDGET_ERROR_NOT_SUPPORTED;
395
396   auto* app_event = new (std::nothrow) AppEvent(
397       ::__app_event_converter[event_type], callback, user_data);
398   if (app_event == nullptr) {
399     _E("Out of memory");/* LCOV_EXCL_LINE */
400     return WIDGET_ERROR_OUT_OF_MEMORY;/* LCOV_EXCL_LINE */
401   }
402
403   auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(app_event);
404   if (h == nullptr) {
405     _E("Out of memory");/* LCOV_EXCL_LINE */
406     delete app_event;/* LCOV_EXCL_LINE */
407     return WIDGET_ERROR_OUT_OF_MEMORY;/* LCOV_EXCL_LINE */
408   }
409
410   if (__app_widget.get() != nullptr)
411     __app_widget->AddEvent(*h);
412   else
413     __pending_app_events.push_back(*h);
414
415   *event_handler = reinterpret_cast<app_event_handler_h>(h);
416   return WIDGET_ERROR_NONE;
417 }
418
419 API int widget_app_remove_event_handler(app_event_handler_h event_handler) {
420   bool feature;
421   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
422   if (ret < 0)
423     return WIDGET_ERROR_FAULT;
424
425   if (!feature)
426     return WIDGET_ERROR_NOT_SUPPORTED;
427
428   if (event_handler == nullptr)
429     return WIDGET_ERROR_INVALID_PARAMETER;
430
431   auto* h = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
432
433   if (__app_widget.get() != nullptr) {
434     if (!__app_widget->RemoveEvent(*h))
435       return WIDGET_ERROR_INVALID_PARAMETER;
436   } else {
437     __pending_app_events.remove(*h);
438   }
439
440   delete h;
441   return WIDGET_ERROR_NONE;
442 }
443
444 API const char* widget_app_get_id(widget_context_h context) {
445   bool feature;
446   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
447   if (ret < 0) {
448     set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
449     return nullptr;/* LCOV_EXCL_LINE */
450   }
451
452   if (!feature) {
453     set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
454     return nullptr;/* LCOV_EXCL_LINE */
455   }
456
457   if (context == nullptr) {
458     set_last_result(WIDGET_ERROR_INVALID_PARAMETER);/* LCOV_EXCL_LINE */
459     return nullptr;/* LCOV_EXCL_LINE */
460   }
461
462   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
463   const std::string& id = cxt->GetInstId();
464   set_last_result(WIDGET_ERROR_NONE);
465   return id.c_str();
466 }
467
468 API int widget_app_get_elm_win(widget_context_h context, Evas_Object** win) {
469   bool feature;
470   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
471   if (ret < 0)
472     return WIDGET_ERROR_FAULT;
473
474   if (!feature)
475     return WIDGET_ERROR_NOT_SUPPORTED;
476
477   if (context == nullptr || win == nullptr) {
478     _E("Invalid parameter");/* LCOV_EXCL_LINE */
479     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
480   }
481
482   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
483   const std::string& id = cxt->GetInstId();
484
485   Evas_Object* ret_win = elm_win_add(nullptr, id.c_str(), ELM_WIN_BASIC);
486   if (ret_win == nullptr) {
487     _E("Failed to create window");
488     return WIDGET_ERROR_FAULT;
489   }
490
491   elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
492   int rots[3] = { 0, };
493   elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
494
495   Ecore_Wl2_Window* wl_win = ecore_evas_wayland2_window_get(
496       ecore_evas_ecore_evas_get(evas_object_evas_get(ret_win)));
497   if (wl_win == nullptr) {
498     _E("Failed to get wayland window");/* LCOV_EXCL_LINE */
499     evas_object_del(ret_win);/* LCOV_EXCL_LINE */
500     return WIDGET_ERROR_FAULT;/* LCOV_EXCL_LINE */
501   }
502
503   ecore_wl2_window_class_set(wl_win, id.c_str());
504   elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
505   cxt->WindowBind(id, wl_win);
506
507   /* Set data to use in accessibility */
508   std::string plug_id = id + ":" + std::to_string(getpid());
509   evas_object_data_set(ret_win, "___PLUGID", strdup(plug_id.c_str()));
510   evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL,
511       [](void *data, Evas *e, Evas_Object *obj, void *event_info) {
512         char* plug_id = static_cast<char*>(
513             evas_object_data_del(obj, "___PLUGID"));
514         free(plug_id);
515       }, nullptr);
516
517   int win_id = ecore_wl2_window_id_get(wl_win);
518   _D("Window created: %d", win_id);
519
520   cxt->SetWindow(ret_win);
521   *win = ret_win;
522   return WIDGET_ERROR_NONE;
523 }
524
525 API widget_class_h widget_app_class_add(widget_class_h widget_class,
526     const char* class_id, widget_instance_lifecycle_callback_s callback,
527     void* user_data) {
528   bool feature;
529   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
530   if (ret < 0) {
531     set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
532     return nullptr;/* LCOV_EXCL_LINE */
533   }
534
535   if (!feature) {
536     set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
537     return nullptr;/* LCOV_EXCL_LINE */
538   }
539
540   if (class_id == nullptr || callback.create == nullptr) {
541     _E("Invalid parameter");/* LCOV_EXCL_LINE */
542     set_last_result(WIDGET_ERROR_INVALID_PARAMETER);/* LCOV_EXCL_LINE */
543     return nullptr;/* LCOV_EXCL_LINE */
544   }
545
546   if (__app_widget.get() == nullptr) {
547     set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
548     return nullptr;/* LCOV_EXCL_LINE */
549   }
550
551   auto factory = std::shared_ptr<AppCoreMultiWindowBase::Context::IFactory>(
552       new (std::nothrow) AppWidgetContext::Factory(
553           class_id, callback, user_data));
554   if (factory.get() == nullptr) {
555     set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);/* LCOV_EXCL_LINE */
556     return nullptr;/* LCOV_EXCL_LINE */
557   }
558
559   __app_widget->AddContextFactory(std::move(factory), class_id);
560   set_last_result(WIDGET_ERROR_NONE);
561   static int dummy = 1;
562   widget_class_h cls = reinterpret_cast<widget_class_h>(&dummy);
563   return cls;
564 }
565
566 API widget_class_h widget_app_class_create(
567     widget_instance_lifecycle_callback_s callback, void* user_data) {
568   bool feature;
569   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
570   if (ret < 0) {
571     set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
572     return nullptr;/* LCOV_EXCL_LINE */
573   }
574
575   if (!feature) {
576     set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
577     return nullptr;/* LCOV_EXCL_LINE */
578   }
579
580   if (callback.create == nullptr) {
581     _E("Invalid parameter");/* LCOV_EXCL_LINE */
582     set_last_result(WIDGET_ERROR_INVALID_PARAMETER);/* LCOV_EXCL_LINE */
583     return nullptr;/* LCOV_EXCL_LINE */
584   }
585
586   char* appid = nullptr;
587   app_get_id(&appid);
588   if (appid == nullptr) {
589     LOGE("app_get_id() is failed");/* LCOV_EXCL_LINE */
590     return nullptr;/* LCOV_EXCL_LINE */
591   }
592   std::unique_ptr<char, decltype(std::free)*> ptr(appid, std::free);
593
594   return static_cast<widget_class_h>(
595       widget_app_class_add(nullptr, appid, callback, user_data));
596 }
597
598 API int widget_app_context_set_tag(widget_context_h context, void* tag) {
599   bool feature;
600   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
601   if (ret < 0)
602     return WIDGET_ERROR_FAULT;
603
604   if (!feature)
605     return WIDGET_ERROR_NOT_SUPPORTED;
606
607   if (context == nullptr) {
608     _E("Invalid parameter");/* LCOV_EXCL_LINE */
609     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
610   }
611
612   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
613   cxt->SetTag(tag);
614   return WIDGET_ERROR_NONE;
615 }
616
617 API int widget_app_context_get_tag(widget_context_h context, void** tag) {
618   bool feature;
619   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
620   if (ret < 0)
621     return WIDGET_ERROR_FAULT;
622
623   if (!feature)
624     return WIDGET_ERROR_NOT_SUPPORTED;
625
626   if (context == nullptr || tag == nullptr) {
627     _E("Invalid parameter");/* LCOV_EXCL_LINE */
628     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
629   }
630
631   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
632   *tag = cxt->GetTag();
633   return WIDGET_ERROR_NONE;
634 }
635
636 API int widget_app_context_set_content_info(widget_context_h context,
637     bundle* content_info) {
638   bool feature;
639   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
640   if (ret < 0)
641     return WIDGET_ERROR_FAULT;
642
643   if (!feature)
644     return WIDGET_ERROR_NOT_SUPPORTED;
645
646   if (context == nullptr || content_info == nullptr) {
647     _E("Invalid parameter");/* LCOV_EXCL_LINE */
648     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
649   }
650
651   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
652   ret = cxt->SetContents(tizen_base::Bundle(content_info));
653   if (ret != WIDGET_ERROR_NONE) {
654     _E("Failed to set content");/* LCOV_EXCL_LINE */
655     return static_cast<widget_error_e>(ret);/* LCOV_EXCL_LINE */
656   }
657
658   return WIDGET_ERROR_NONE;
659 }
660
661 API int widget_app_context_set_title(widget_context_h context,
662     const char* title) {
663   bool feature;
664   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
665   if (ret < 0)
666     return WIDGET_ERROR_FAULT;
667
668   if (!feature)
669     return WIDGET_ERROR_NOT_SUPPORTED;
670
671   if (context == nullptr || title == nullptr) {
672     _E("Invalid parameter");/* LCOV_EXCL_LINE */
673     return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
674   }
675
676   auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
677   if (cxt->GetWindow())
678     elm_win_title_set(cxt->GetWindow(), title);/* LCOV_EXCL_LINE */
679
680   return WIDGET_ERROR_NONE;
681 }
682
683 API int widget_app_restart(void) {
684   bool feature;
685   int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
686   if (ret < 0)
687     return WIDGET_ERROR_FAULT;
688
689   if (!feature)
690     return WIDGET_ERROR_NOT_SUPPORTED;
691
692   if (__app_widget.get() == nullptr)
693     return WIDGET_ERROR_IO_ERROR;
694
695   std::string class_id;
696   auto l = __app_widget->GetContexts();
697   for (auto& i : l) {
698     class_id = i->GetContextId();
699     break;
700   }
701
702   if (class_id.empty())
703     return WIDGET_ERROR_IO_ERROR;
704
705   tizen_base::Bundle b;
706   int status = AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST;
707   std::vector<unsigned char> v;
708   auto* p = reinterpret_cast<const uint8_t*>(&status);
709   std::copy(p, p + sizeof(int), std::back_inserter(v));
710
711   b.Add(AUL_K_WIDGET_ID, class_id);
712   b.Add(AUL_K_WIDGET_STATUS, v);
713
714   std::string endpoint = __app_widget->GetViewerEndpoint();
715   ret = aul_app_com_send(endpoint.empty() ? nullptr : endpoint.c_str(),
716       b.GetHandle());
717   if (ret != AUL_R_OK) {
718     _E("Failed to send restart request");
719     return WIDGET_ERROR_IO_ERROR;
720   }
721
722   return WIDGET_ERROR_NONE;
723 }