Fix static analysis issue
[platform/core/appfw/appcore-widget.git] / src / base / widget_base.cc
1 /*
2  * Copyright (c) 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 <aul.h>
18 #include <aul_app_com.h>
19 #include <aul_widget.h>
20 #include <bundle_internal.h>
21 #include <dlog.h>
22 #include <glib.h>
23 #include <screen_connector_provider.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include <widget_errno.h>
27 #include <widget_instance.h>
28
29 #include <app_core_multi_window_base.hh>
30
31 #include "common/log_private.hh"
32 #include "include/widget_base.hh"
33
34 namespace tizen_cpp {
35 namespace {
36
37 constexpr const char kStatusForeground[] = "fg";
38 constexpr const char kStatusBackground[] = "bg";
39
40 class AppContext {
41  public:
42   void SetAppId(const std::string& app_id) {
43     app_id_ = app_id;
44   }
45
46   const std::string& GetAppId() const {
47     return app_id_;
48   }
49
50   void SetPackageId(const std::string& package_id) {
51     package_id_ = package_id;
52   }
53
54   const std::string& GetPackageId() const {
55     return package_id_;
56   }
57
58   void SetViewerEndpoint(const std::string& viewer_endpoint) {
59     viewer_endpoint_ = viewer_endpoint;
60   }
61
62   const std::string& GetViewerEndpoint() const {
63     return viewer_endpoint_;
64   }
65
66   void SetPermanent(bool permanent) {
67     permanent_ = permanent;
68   }
69
70   bool IsPermanent() const {
71     return permanent_;
72   }
73
74   void SetFgSignal(bool fg_signal) {
75     fg_signal_ = fg_signal;
76   }
77
78   bool IsFgSignal() const {
79     return fg_signal_;
80   }
81
82   int SendUpdateStatus(const std::string& class_id,
83       const std::string& instance_id, int status, int err,
84       bundle* extra) {
85     int ret = aul_widget_send_status_to_viewer(class_id.c_str(),
86         instance_id.c_str(), viewer_endpoint_.c_str(), status, err, extra);
87     if (ret != AUL_R_OK)
88       return ret;
89
90     int lifecycle = widget_instance_convert_event_to_lifecycle_status(status);
91     if (lifecycle > -1) {
92       ret = aul_widget_send_status_to_service(class_id.c_str(),
93           instance_id.c_str(), package_id_.c_str(), lifecycle);
94     }
95
96     return ret;
97   }
98
99  private:
100   std::string app_id_;
101   std::string package_id_;
102   std::string viewer_endpoint_;
103   bool permanent_ = false;
104   bool fg_signal_ = false;
105 };
106
107 AppContext __context;
108
109 }  // namespace
110
111 class WidgetBase::Impl {
112  public:
113   explicit Impl(WidgetBase* parent) : parent_(parent) {}
114
115  private:
116   friend class WidgetBase;
117   WidgetBase* parent_;
118
119   void ControlCreate(const std::string& class_id, const std::string& id,
120       const tizen_base::Bundle& b);
121   void ControlDestroy(const std::string& class_id, const std::string& id,
122       const tizen_base::Bundle& b);
123   void ControlResume(const std::string& class_id, const std::string& id,
124       const tizen_base::Bundle& b);
125   void ControlPause(const std::string& class_id, const std::string& id,
126       const tizen_base::Bundle& b);
127   void ControlChangePeriod(const std::string& class_id, const std::string& id,
128       const tizen_base::Bundle& b);
129   void ControlUpdate(const std::string& class_id, const std::string& id,
130       const tizen_base::Bundle& b);
131   void ControlResize(const std::string& class_id, const std::string& id,
132       const tizen_base::Bundle& b);
133   void GetContent(tizen_base::Bundle& b);
134 };
135
136 WidgetBase* __widget;
137
138 class WidgetContext::Impl {
139  public:
140   explicit Impl(WidgetContext* parent) : parent_(parent) {}
141
142   ~Impl() {
143     UnsetPeriodicTimer();
144   }
145
146  private:
147   void UpdateProcess(const tizen_base::Bundle& b);
148   void OnUpdate(bool force);
149   void SetPeriod(double period);
150   void SetPeriodicTimer();
151   void UnsetPeriodicTimer();
152   static gboolean TimedOutCb(gpointer user_data);
153
154  private:
155   friend class WidgetContext;
156   friend class WidgetBase;
157   friend class WidgetBase::Impl;
158
159   WidgetContext* parent_;
160
161   std::unique_ptr<tizen_base::Bundle> args_;
162   std::string content_;
163   double period_ = 0.0f;
164   guint periodic_timer_ = 0;
165   bool pending_update_ = false;
166   std::string pending_content_;
167 };
168
169 void WidgetBase::Impl::ControlCreate(const std::string& class_id,
170     const std::string& id, const tizen_base::Bundle& b) {
171   if (parent_->FindById(id).get() != nullptr) {
172     _E("Already exists. ID(%s)", id.c_str());
173     return;
174   }
175
176   std::shared_ptr<Context> context;
177   try {
178     context = parent_->CreateContext(class_id, id);
179   } catch (std::runtime_error& e) {
180     _E("runtime_error exception occurs");
181     return;
182   }
183
184   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
185   if (wc == nullptr)
186     return;
187
188   wc->impl_->args_.reset(new tizen_base::Bundle(b));
189   auto ctx = parent_->RunContext(context);
190   if (ctx.get() == nullptr)
191     return;
192
193   wc->impl_->args_.reset();
194   wc->impl_->content_ = b.GetString(WIDGET_K_CONTENT_INFO);
195 }
196
197 void WidgetBase::Impl::ControlDestroy(const std::string& class_id,
198     const std::string& id, const tizen_base::Bundle& b) {
199   auto context = parent_->FindById(id);
200   if (context.get() == nullptr) {
201     _E("Failed to find widget context. ID(%s)", id.c_str());
202     aul_widget_instance_del(class_id.c_str(), id.c_str());
203     return;
204   }
205
206   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
207   if (wc == nullptr)
208     return;
209
210   wc->impl_->args_.reset(new tizen_base::Bundle(b));
211   parent_->ExitContext(context);
212 }
213
214 void WidgetBase::Impl::ControlResume(const std::string& class_id,
215     const std::string& id, const tizen_base::Bundle& b) {
216   auto context = parent_->FindById(id);
217   if (context.get() == nullptr) {
218     _E("Failed to find widget context. ID(%s)", id.c_str());
219     return;
220   }
221
222   context->Resume();
223 }
224
225 void WidgetBase::Impl::ControlPause(const std::string& class_id,
226     const std::string& id, const tizen_base::Bundle& b) {
227   auto context = parent_->FindById(id);
228   if (context.get() == nullptr) {
229     _E("Failed to find widget context. ID(%s)", id.c_str());
230     return;
231   }
232
233   context->Pause();
234 }
235
236 void WidgetBase::Impl::ControlUpdate(const std::string& class_id,
237     const std::string& id, const tizen_base::Bundle& b) {
238   if (id.empty()) {
239     for (auto& i : parent_->GetContexts()) {
240       if (i->GetContextId() == class_id) {
241         WidgetContext* cxt = dynamic_cast<WidgetContext*>(i.get());
242         if (cxt == nullptr)
243           continue;
244
245         cxt->impl_->UpdateProcess(b);
246       }
247     }
248     return;
249   }
250
251   auto context = parent_->FindById(id);
252   if (context.get() == nullptr) {
253     _E("Failed to find widget context. ID(%s)", id.c_str());
254     return;
255   }
256
257   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
258   if (wc == nullptr)
259     return;
260
261   wc->impl_->UpdateProcess(b);
262 }
263
264 void WidgetBase::Impl::ControlResize(const std::string& class_id,
265     const std::string& id, const tizen_base::Bundle& b) {
266   auto context = parent_->FindById(id);
267   if (context.get() == nullptr) {
268     _E("Failed to find widget context. ID(%s)", id.c_str());
269     return;
270   }
271
272   int w = 0;
273   std::string w_str = b.GetString(WIDGET_K_WIDTH);
274   if (!w_str.empty()) {
275     char* remain = nullptr;
276     w = static_cast<int>(g_ascii_strtoll(w_str.c_str(), &remain, 10));
277   }
278
279   int h = 0;
280   std::string h_str = b.GetString(WIDGET_K_HEIGHT);
281   if (!h_str.empty()) {
282     char* remain = nullptr;
283     h = static_cast<int>(g_ascii_strtoll(h_str.c_str(), &remain, 10));
284   }
285
286   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
287   if (wc == nullptr)
288     return;
289
290   wc->OnResize(w, h);
291
292   _D("WidgetContext(%s) is resized to %dx%d", id.c_str(), w, h);
293   __context.SendUpdateStatus(class_id, id,
294       WIDGET_INSTANCE_EVENT_SIZE_CHANGED, 0, nullptr);
295 }
296
297 void WidgetBase::Impl::ControlChangePeriod(const std::string& class_id,
298     const std::string& id, const tizen_base::Bundle& b) {
299   auto context = parent_->FindById(id);
300   if (context.get() == nullptr) {
301     _E("Failed to find widget context. ID(%s)", id.c_str());
302     return;
303   }
304
305   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
306   if (wc == nullptr)
307     return;
308
309   wc->impl_->UnsetPeriodicTimer();
310
311   auto v = b.GetByte(WIDGET_K_PERIOD);
312   if (v.empty())
313     return;
314
315   const double* period = reinterpret_cast<double*>(v.data());
316   wc->impl_->SetPeriod(*period);
317   wc->impl_->SetPeriodicTimer();
318 }
319
320 void WidgetBase::Impl::GetContent(tizen_base::Bundle& b) {
321   std::string instance_id = b.GetString(AUL_K_WIDGET_INSTANCE_ID);
322   if (instance_id.empty()) {
323     _E("Instance ID is nullptr");
324     return;
325   }
326
327   auto context = parent_->FindById(instance_id);
328   if (context.get() == nullptr) {
329     _E("Failed to find widget context. ID(%s)", instance_id.c_str());
330     return;
331   }
332
333   WidgetContext* wc = dynamic_cast<WidgetContext*>(context.get());
334   if (wc == nullptr)
335     return;
336
337   if (!wc->impl_->content_.empty()) {
338     b.Add(AUL_K_WIDGET_CONTENT_INFO, wc->impl_->content_);
339     _D("Content info of %s found", instance_id.c_str());
340   } else {
341     b.Add(AUL_K_WIDGET_CONTENT_INFO, "");
342     _D("Empty content info added");
343   }
344 }
345
346 WidgetBase::WidgetBase() : impl_(std::make_unique<WidgetBase::Impl>(this)) {
347 }
348
349 WidgetBase::~WidgetBase() = default;
350
351 std::string WidgetBase::GetViewerEndpoint() {
352   return __context.GetViewerEndpoint();
353 }
354
355 void WidgetBase::Run(int argc, char** argv) {
356   bundle* kb = bundle_import_from_argv(argc, argv);
357   if (kb) {
358     tizen_base::Bundle b(kb, false, true);
359     __context.SetViewerEndpoint(b.GetString(AUL_K_WIDGET_VIEWER));
360     if (!__context.GetViewerEndpoint().empty())
361       _D("Viewer endpoint :%s", __context.GetViewerEndpoint().c_str());
362     else
363       _E("Endpoint is missing");
364   } else {
365     _E("Failed to get launch argv");
366     throw std::runtime_error("Failed to get launch argv");
367   }
368
369   AppCoreMultiWindowBase::Run(argc, argv);
370 }
371
372 void WidgetBase::Dispose() {
373   AppCoreMultiWindowBase::Dispose();
374   if (getenv("AUL_LOADER_INIT")) {
375       unsetenv("AUL_LOADER_INIT");
376       OnLoopFinish();
377   }
378 }
379
380 void WidgetBase::ExitContext(
381     std::shared_ptr<AppCoreMultiWindowBase::Context> context) {
382   AppCoreMultiWindowBase::ExitContext(context);
383   int cnt = GetContextCnt();
384   if (cnt == 0)
385     Exit();
386
387   aul_widget_write_log(LOG_TAG,
388       "[%s:%d] instance_id(%s)", __FUNCTION__, __LINE__,
389       context->GetInstId().c_str());
390 }
391
392 void WidgetBase::Exit() {
393   AppCoreMultiWindowBase::Exit();
394   int cnt = GetContextCnt();
395   int ret = 0;
396   if (cnt == 0 && __context.IsPermanent())
397     ret = aul_notify_exit();
398
399   aul_widget_write_log(LOG_TAG,
400       "[%s:%d] exit : ret(%d), cnt(%d), permanent(%d)",
401       __FUNCTION__, __LINE__, ret, cnt, __context.IsPermanent());
402 }
403
404 int WidgetBase::OnCreate() {
405   AppCoreMultiWindowBase::OnCreate();
406
407   char appid[256] = { 0, };
408   int ret = aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
409   if (ret != AUL_R_OK) {
410     _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
411     return -1;
412   }
413
414   __context.SetAppId(appid);
415
416   char pkgid[256] = { 0, };
417   ret = aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid));
418   if (ret != AUL_R_OK) {
419     _E("aul_app_get_pkgid_bypid() is failed. error(%d)", ret);
420     return -1;
421   }
422
423   __context.SetPackageId(pkgid);
424
425   screen_connector_provider_init();
426   _D("Widget base is created");
427   __widget = this;
428   return 0;
429 }
430
431 int WidgetBase::OnTerminate() {
432   screen_connector_provider_fini();
433   __widget = nullptr;
434
435   AppCoreMultiWindowBase::OnTerminate();
436   _D("Widget base is terminated");
437   return 0;
438 }
439
440 int WidgetBase::OnReceive(aul_type type, tizen_base::Bundle b) {
441   AppCoreMultiWindowBase::OnReceive(type,
442       tizen_base::Bundle(b.GetHandle(), false, false));
443
444   switch (type) {
445     case AUL_RESUME: {
446         for (auto& i : GetContexts())
447           i->Resume();
448       }
449       break;
450     case AUL_TERMINATE:
451       Exit();
452       break;
453     case AUL_WIDGET_CONTENT:
454       impl_->GetContent(b);
455       break;
456     default:
457       break;
458   }
459
460   return 0;
461 }
462
463 int WidgetBase::OnControl(tizen_base::Bundle b) {
464   AppCoreMultiWindowBase::OnControl(
465       tizen_base::Bundle(b.GetHandle(), false, false));
466
467   std::string class_id = b.GetString(WIDGET_K_CLASS);
468   /* for previous version compatibility, use appid for default class id */
469   if (class_id.empty())
470     class_id = __context.GetAppId();
471
472   std::string id = b.GetString(AUL_K_WIDGET_INSTANCE_ID);
473   std::string operation = b.GetString(WIDGET_K_OPERATION);
474   if (operation.empty()) {
475     _E("Operation is empty");
476     return 0;
477   }
478
479   _I("Operation(%s)", operation.c_str());
480   if (operation == "create")
481     impl_->ControlCreate(class_id, id, b);
482   else if (operation == "resize")
483     impl_->ControlResize(class_id, id, b);
484   else if (operation == "update")
485     impl_->ControlUpdate(class_id, id, b);
486   else if (operation == "destroy")
487     impl_->ControlDestroy(class_id, id, b);
488   else if (operation == "resume")
489     impl_->ControlResume(class_id, id, b);
490   else if (operation == "pause")
491     impl_->ControlPause(class_id, id, b);
492   else if (operation == "terminate")
493     impl_->ControlDestroy(class_id, id, b);
494   else if (operation == "period")
495     impl_->ControlChangePeriod(class_id, id, b);
496
497   return 0;
498 }
499
500 void WidgetContext::Impl::OnUpdate(bool force) {
501   parent_->OnUpdate(pending_content_.empty() ? tizen_base::Bundle() :
502       tizen_base::Bundle(pending_content_), force);
503
504   std::string class_id = parent_->GetContextId();
505   std::string id = parent_->GetInstId();
506   __context.SendUpdateStatus(class_id, id,
507       WIDGET_INSTANCE_EVENT_UPDATE, 0, nullptr);
508   _D("Updated: %s", id.c_str());
509 }
510
511 void WidgetContext::Impl::UpdateProcess(const tizen_base::Bundle& b) {
512   bool force;
513   std::string force_str = b.GetString(WIDGET_K_FORCE);
514   if (force_str == "true")
515     force = true;
516   else
517     force = false;
518
519   std::string content_raw = b.GetString(WIDGET_K_CONTENT_INFO);
520   if (!parent_->IsResumed() && !force) {
521     pending_content_ = content_raw;
522     pending_update_ = true;
523   } else {
524     parent_->OnUpdate(content_raw.empty() ? tizen_base::Bundle() :
525         tizen_base::Bundle(content_raw), force);
526
527     std::string class_id = parent_->GetContextId();
528     std::string id = parent_->GetInstId();
529     __context.SendUpdateStatus(class_id, id,
530         WIDGET_INSTANCE_EVENT_UPDATE, 0, nullptr);
531     _D("Updated: %s", id.c_str());
532   }
533 }
534
535 void WidgetContext::Impl::SetPeriod(double period) {
536   period_ = period;
537 }
538
539 void WidgetContext::Impl::SetPeriodicTimer() {
540   if (periodic_timer_)
541     return;
542
543   if (period_ > 0) {
544     _D("Restart timer!");
545     periodic_timer_ = g_timeout_add_seconds(period_,
546         TimedOutCb, parent_);
547   }
548 }
549
550 void WidgetContext::Impl::UnsetPeriodicTimer() {
551   if (periodic_timer_) {
552     _D("Remove timer!");
553     g_source_remove(periodic_timer_);
554     periodic_timer_ = 0;
555   }
556 }
557
558 gboolean WidgetContext::Impl::TimedOutCb(gpointer user_data) {
559   WidgetContext* wc = reinterpret_cast<WidgetContext*>(user_data);
560   if (wc->IsResumed()) {
561     _D("Periodic update!");
562     wc->OnUpdate(tizen_base::Bundle(), false);
563
564     __context.SendUpdateStatus(wc->GetContextId(), wc->GetInstId(),
565         WIDGET_INSTANCE_EVENT_UPDATE, 0, nullptr);
566     _D("Updated: %s", wc->GetInstId().c_str());
567   } else {
568     wc->impl_->pending_update_ = true;
569     wc->impl_->UnsetPeriodicTimer();
570   }
571
572   return G_SOURCE_CONTINUE;
573 }
574
575 WidgetContext::WidgetContext(std::string context_id, std::string inst_id,
576     AppCoreMultiWindowBase* app)
577     : AppCoreMultiWindowBase::Context(
578           std::move(context_id), std::move(inst_id), app),
579       impl_(std::make_unique<WidgetContext::Impl>(this)) {
580 }
581
582 WidgetContext::~WidgetContext() = default;
583
584 void WidgetContext::OnPause() {
585   std::string id = GetInstId();
586   _D("WidgetContext(%s) is paused", id.c_str());
587   std::string class_id = GetContextId();
588   __context.SendUpdateStatus(class_id.c_str(), id.c_str(),
589       WIDGET_INSTANCE_EVENT_PAUSE, 0, nullptr);
590
591   if (__context.IsFgSignal()) {
592     _D("Send bg signal to resourceD");
593     aul_widget_instance_change_status(class_id.c_str(), kStatusBackground);
594     __context.SetFgSignal(false);
595   }
596 }
597
598 void WidgetContext::OnResume() {
599   if (impl_->pending_update_) {
600     _D("Pending update!");
601     impl_->pending_update_ = false;
602     impl_->OnUpdate(false);
603     impl_->SetPeriodicTimer();
604   }
605
606   std::string id = GetInstId();
607   _D("WidgetContext(%s) is resumed", id.c_str());
608   std::string class_id = GetContextId();
609   __context.SendUpdateStatus(class_id.c_str(), id.c_str(),
610       WIDGET_INSTANCE_EVENT_RESUME, 0, nullptr);
611
612   if (!__context.IsFgSignal()) {
613     _D("Send fg signal to resourceD");
614     aul_widget_instance_change_status(class_id.c_str(), kStatusForeground);
615     __context.SetFgSignal(true);
616   }
617 }
618
619 void WidgetContext::OnResize(int w, int h) {
620 }
621
622 void WidgetContext::OnUpdate(const tizen_base::Bundle& contents, bool force) {
623 }
624
625 void WidgetContext::ExitAsync() {
626   tizen_base::Bundle b;
627   b.Add(WIDGET_K_OPERATION, "terminate");
628
629   impl_->args_.reset(new tizen_base::Bundle(std::move(b)));
630   g_idle_add([](gpointer user_data) -> gboolean {
631     if (__widget == nullptr)
632       return G_SOURCE_REMOVE;
633
634     WidgetContext* wc = static_cast<WidgetContext*>(user_data);
635
636     std::string id = wc->GetInstId();
637     auto context = __widget->FindById(id);
638     if (context.get() == nullptr) {
639       _E("Failed to find context. ID(%s)", id.c_str());
640       return G_SOURCE_REMOVE;
641     }
642
643     __widget->ExitContext(context);
644     return G_SOURCE_REMOVE;
645   }, this);
646 }
647
648 int WidgetContext::SetContents(const tizen_base::Bundle& contents) {
649   std::string id = GetInstId();
650   if (id.empty())
651     return WIDGET_ERROR_FAULT;
652
653   std::string class_id = GetContextId();
654   if (class_id.empty())
655     return WIDGET_ERROR_FAULT;
656
657   int ret = __context.SendUpdateStatus(class_id, id,
658       WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, contents.GetHandle());
659   if (ret < 0) {
660     _E("Failed to send content info: %s of %s (%d)",
661         id.c_str(), class_id.c_str(), ret);
662     return WIDGET_ERROR_FAULT;
663   }
664
665   return WIDGET_ERROR_NONE;
666 }
667
668 int WidgetContext::WindowBind(std::string id, Ecore_Wl2_Window* wl_win) {
669   wl_surface* surface = ecore_wl2_window_surface_get(wl_win);
670   if (surface == nullptr) {
671     _E("Failed to get surface, wl_win(%p)", wl_win);
672     return -1;
673   }
674
675   screen_connector_provider_remote_enable(id.c_str(), surface);
676   WindowBind(wl_win);
677   return 0;
678 }
679
680 void WidgetContext::OnCreate() {
681   auto& b = impl_->args_;
682   std::string class_id = b->GetString(WIDGET_K_CLASS);
683   /* For previous version compatibility, use appid for default class id */
684   if (class_id.empty())
685     class_id = __context.GetAppId();
686
687   std::string id = b->GetString(AUL_K_WIDGET_INSTANCE_ID);
688   std::string operation = b->GetString(WIDGET_K_OPERATION);
689   if (operation.empty()) {
690     _E("Operation is empty");
691     return;
692   }
693
694   std::string w_str = b->GetString(WIDGET_K_WIDTH);
695   int w = 0;
696   if (!w_str.empty()) {
697     char* remain = nullptr;
698     w = static_cast<int>(g_ascii_strtoll(w_str.c_str(), &remain, 10));
699   }
700
701   std::string h_str = b->GetString(WIDGET_K_HEIGHT);
702   int h = 0;
703   if (!h_str.empty()) {
704     char* remain = nullptr;
705     h = static_cast<int>(g_ascii_strtoll(h_str.c_str(), &remain, 10));
706   }
707
708   tizen_base::Bundle content_info;
709   std::string content = b->GetString(WIDGET_K_CONTENT_INFO);
710   try {
711     if (!content.empty())
712       content_info = tizen_base::Bundle(content);
713   } catch (std::bad_alloc& e) {
714     _W("Failed to decode content info(%s)", content.c_str());
715   }
716
717   bool r = OnCreate(content_info, w, h);
718   if (!r) {
719     _W("Create callback returns error");
720     int ret = __context.SendUpdateStatus(class_id, id,
721         WIDGET_INSTANCE_EVENT_CREATE_ABORTED, WIDGET_ERROR_CANCELED, nullptr);
722     if (ret != 0)
723       _E("Failed to send abrot status. error(%d)", ret);
724
725     throw std::runtime_error("Create callback returns error");
726   } else {
727     _D("WidgetContext(%s) is created", id.c_str());
728     aul_widget_instance_add(class_id.c_str(), id.c_str());
729     int ret = __context.SendUpdateStatus(class_id, id,
730         WIDGET_INSTANCE_EVENT_CREATE, 0, nullptr);
731     if (ret != 0)
732       _E("Failed to send create status. error(%d)", ret);
733
734     auto v = b->GetByte(WIDGET_K_PERIOD);
735     if (v.empty())
736       return;
737
738     const double* period = reinterpret_cast<double*>(v.data());
739     if (*period > 0) {
740       _I("Set periodic update timer. period(%lf)", *period);
741       impl_->SetPeriod(*period);
742       impl_->SetPeriodicTimer();
743     }
744   }
745 }
746
747 void WidgetContext::OnTerminate() {
748   DestroyType reason = DestroyType::TEMPORARY;
749   int event = WIDGET_INSTANCE_EVENT_TERMINATE;
750   std::string id = GetInstId();
751   std::string class_id = GetContextId();
752   auto& b = impl_->args_;
753   if (b.get()) {
754     std::string operation = b->GetString(WIDGET_K_OPERATION);
755     if (operation == "destroy")
756       reason = DestroyType::PERMANENT;
757   }
758
759   tizen_base::Bundle content_info = impl_->content_.empty() ?
760       tizen_base::Bundle() : tizen_base::Bundle(impl_->content_);
761
762   OnDestroy(reason, content_info);
763
764   _W("WidgetContext(%s) is destroyed. reason(%s)", id.c_str(),
765       reason == DestroyType::TEMPORARY ? "TEMPORARY" : "PERMANENT");
766   if (reason == DestroyType::PERMANENT) {
767     __context.SetPermanent(true);
768     event = WIDGET_INSTANCE_EVENT_DESTROY;
769     aul_widget_instance_del(class_id.c_str(), id.c_str());
770   } else {
771     __context.SetPermanent(false);
772     __context.SendUpdateStatus(class_id.c_str(), id.c_str(),
773         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info.GetHandle());
774   }
775
776   impl_->UnsetPeriodicTimer();
777
778   __context.SendUpdateStatus(class_id.c_str(), id.c_str(), event, 0, nullptr);
779 }
780
781 }  // namespace tizen_cpp