2 * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <Elementary.h>
18 #include <app_event_internal.hh>
20 #include <aul_app_com.h>
21 #include <aul_widget.h>
25 #include <system_info.h>
26 #include <widget_errno.h>
27 #include <widget_instance.h>
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"
37 using namespace tizen_cpp;
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,
57 class AppWidget : public WidgetBase {
59 AppWidget(widget_app_lifecycle_callback_s* callback, void* user_data)
60 : callback_(callback), user_data_(user_data) {}
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");
70 _D("Widget app is created");
71 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
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__);
87 WidgetBase::OnTerminate();
91 void OnLoopInit(int argc, char** argv) override {
95 void OnLoopFinish() override {
99 void OnLoopRun() override {
103 void OnLoopExit() override {
106 /* LCOV_EXCL_START */
107 int OnTrimMemory() override {
109 elm_cache_all_flush();
110 return WidgetBase::OnTrimMemory();
114 widget_app_lifecycle_callback_s* callback_;
118 class AppWidgetContext : public WidgetContext {
120 class Factory : public AppCoreMultiWindowBase::Context::IFactory {
122 Factory(std::string widget_id,
123 widget_instance_lifecycle_callback_s callback, void* user_data)
124 : widget_id_(std::move(widget_id)),
126 user_data_(user_data) {
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_));
137 std::string widget_id_;
138 widget_instance_lifecycle_callback_s callback_;
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) {}
148 bool OnCreate(const tizen_base::Bundle& contents, int w, int h) override {
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);
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__);
172 void OnPause() override {
176 WidgetContext::OnPause();
177 if (callback_.pause) {
178 callback_.pause(reinterpret_cast<widget_context_h>(this), user_data_);
182 void OnResume() override {
186 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
187 ecore_evas_ecore_evas_get(evas_object_evas_get(win_)));
189 ecore_wl2_window_iconified_set(win, EINA_FALSE);
190 is_iconified_ = false;
191 _D("Set iconify false");
195 WidgetContext::OnResume();
196 if (callback_.resume) {
197 callback_.resume(reinterpret_cast<widget_context_h>(this), user_data_);
201 void OnResize(int w, int h) override {
202 WidgetContext::OnResize(w, h);
205 evas_object_resize(win_, w, h);
207 _E("Failed to find window");
209 if (callback_.resize) {
210 callback_.resize(reinterpret_cast<widget_context_h>(this),
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_);
223 void SetTag(void* tag) {
227 void* GetTag() const {
231 Evas_Object* GetWindow() const {
235 void SetWindow(Evas_Object* win) {
240 /* LCOV_EXCL_START */
241 void SetIconifyTimer() {
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_)));
251 ecore_wl2_window_iconified_set(win, EINA_TRUE);
252 cxt->is_iconified_ = true;
253 _D("Set iconify true");
256 cxt->iconify_timer_ = 0;
257 return G_SOURCE_REMOVE;
261 void UnsetIconifyTimer() {
262 if (iconify_timer_) {
263 g_source_remove(iconify_timer_);
269 widget_instance_lifecycle_callback_s callback_;
271 Evas_Object* win_ = nullptr;
272 guint iconify_timer_ = 0;
273 bool is_iconified_ = false;
274 void* tag_ = nullptr;
277 std::unique_ptr<AppWidget> __app_widget;
278 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
282 API int widget_app_main(int argc, char** argv,
283 widget_app_lifecycle_callback_s* callback, void* user_data) {
285 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
287 return WIDGET_ERROR_FAULT;
290 return WIDGET_ERROR_NOT_SUPPORTED;
292 if (argc <= 0 || argv == nullptr || callback == nullptr) {
293 _E("Invalid parameter");
294 return WIDGET_ERROR_INVALID_PARAMETER;
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 */
303 __app_widget = std::make_unique<AppWidget>(callback, user_data);
304 for (auto& i : __pending_app_events)
305 __app_widget->AddEvent(i);
307 __app_widget->Run(argc, argv);
308 } catch (std::runtime_error& e) {/* LCOV_EXCL_LINE */
309 return WIDGET_ERROR_FAULT;/* LCOV_EXCL_LINE */
312 return WIDGET_ERROR_NONE;
315 API int widget_app_exit(void) {
317 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
319 return WIDGET_ERROR_FAULT;
322 return WIDGET_ERROR_NOT_SUPPORTED;
324 if (__app_widget.get() == nullptr)
325 return WIDGET_ERROR_FAULT;
327 __app_widget->Exit();
328 return WIDGET_ERROR_NONE;
331 API int widget_app_terminate_context(widget_context_h context) {
333 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
335 return WIDGET_ERROR_FAULT;
338 return WIDGET_ERROR_NOT_SUPPORTED;
340 if (context == nullptr) {
341 _E("Invalid parameter");/* LCOV_EXCL_LINE */
342 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
345 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
347 return WIDGET_ERROR_NONE;
350 API int widget_app_foreach_context(widget_context_cb cb, void* data) {
352 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
354 return WIDGET_ERROR_FAULT;
357 return WIDGET_ERROR_NOT_SUPPORTED;
360 _E("Invalid parameter");/* LCOV_EXCL_LINE */
361 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
364 if (__app_widget.get() == nullptr)
365 return WIDGET_ERROR_FAULT;
367 auto l = __app_widget->GetContexts();
369 if (!cb(reinterpret_cast<widget_context_h>(i.get()), data))
373 return WIDGET_ERROR_NONE;
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) {
379 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
381 return WIDGET_ERROR_FAULT;
384 return WIDGET_ERROR_NOT_SUPPORTED;
386 if (event_handler == nullptr || callback == nullptr)
387 return WIDGET_ERROR_INVALID_PARAMETER;
389 if (event_type < APP_EVENT_LOW_MEMORY ||
390 event_type > APP_EVENT_TIME_ZONE_CHANGED)
391 return WIDGET_ERROR_INVALID_PARAMETER;
393 if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
394 return WIDGET_ERROR_NOT_SUPPORTED;
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 */
403 auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(app_event);
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 */
410 if (__app_widget.get() != nullptr)
411 __app_widget->AddEvent(*h);
413 __pending_app_events.push_back(*h);
415 *event_handler = reinterpret_cast<app_event_handler_h>(h);
416 return WIDGET_ERROR_NONE;
419 API int widget_app_remove_event_handler(app_event_handler_h event_handler) {
421 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
423 return WIDGET_ERROR_FAULT;
426 return WIDGET_ERROR_NOT_SUPPORTED;
428 if (event_handler == nullptr)
429 return WIDGET_ERROR_INVALID_PARAMETER;
431 auto* h = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
433 if (__app_widget.get() != nullptr) {
434 if (!__app_widget->RemoveEvent(*h))
435 return WIDGET_ERROR_INVALID_PARAMETER;
437 __pending_app_events.remove(*h);
441 return WIDGET_ERROR_NONE;
444 API const char* widget_app_get_id(widget_context_h context) {
446 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
448 set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
449 return nullptr;/* LCOV_EXCL_LINE */
453 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
454 return nullptr;/* LCOV_EXCL_LINE */
457 if (context == nullptr) {
458 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);/* LCOV_EXCL_LINE */
459 return nullptr;/* LCOV_EXCL_LINE */
462 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
463 const std::string& id = cxt->GetInstId();
464 set_last_result(WIDGET_ERROR_NONE);
468 API int widget_app_get_elm_win(widget_context_h context, Evas_Object** win) {
470 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
472 return WIDGET_ERROR_FAULT;
475 return WIDGET_ERROR_NOT_SUPPORTED;
477 if (context == nullptr || win == nullptr) {
478 _E("Invalid parameter");/* LCOV_EXCL_LINE */
479 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
482 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
483 const std::string& id = cxt->GetInstId();
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;
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);
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 */
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);
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"));
517 int win_id = ecore_wl2_window_id_get(wl_win);
518 _D("Window created: %d", win_id);
520 cxt->SetWindow(ret_win);
522 return WIDGET_ERROR_NONE;
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,
529 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
531 set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
532 return nullptr;/* LCOV_EXCL_LINE */
536 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
537 return nullptr;/* LCOV_EXCL_LINE */
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 */
546 if (__app_widget.get() == nullptr) {
547 set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
548 return nullptr;/* LCOV_EXCL_LINE */
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 */
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);
566 API widget_class_h widget_app_class_create(
567 widget_instance_lifecycle_callback_s callback, void* user_data) {
569 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
571 set_last_result(WIDGET_ERROR_FAULT);/* LCOV_EXCL_LINE */
572 return nullptr;/* LCOV_EXCL_LINE */
576 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);/* LCOV_EXCL_LINE */
577 return nullptr;/* LCOV_EXCL_LINE */
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 */
586 char* appid = nullptr;
588 if (appid == nullptr) {
589 LOGE("app_get_id() is failed");/* LCOV_EXCL_LINE */
590 return nullptr;/* LCOV_EXCL_LINE */
592 std::unique_ptr<char, decltype(std::free)*> ptr(appid, std::free);
594 return static_cast<widget_class_h>(
595 widget_app_class_add(nullptr, appid, callback, user_data));
598 API int widget_app_context_set_tag(widget_context_h context, void* tag) {
600 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
602 return WIDGET_ERROR_FAULT;
605 return WIDGET_ERROR_NOT_SUPPORTED;
607 if (context == nullptr) {
608 _E("Invalid parameter");/* LCOV_EXCL_LINE */
609 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
612 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
614 return WIDGET_ERROR_NONE;
617 API int widget_app_context_get_tag(widget_context_h context, void** tag) {
619 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
621 return WIDGET_ERROR_FAULT;
624 return WIDGET_ERROR_NOT_SUPPORTED;
626 if (context == nullptr || tag == nullptr) {
627 _E("Invalid parameter");/* LCOV_EXCL_LINE */
628 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
631 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
632 *tag = cxt->GetTag();
633 return WIDGET_ERROR_NONE;
636 API int widget_app_context_set_content_info(widget_context_h context,
637 bundle* content_info) {
639 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
641 return WIDGET_ERROR_FAULT;
644 return WIDGET_ERROR_NOT_SUPPORTED;
646 if (context == nullptr || content_info == nullptr) {
647 _E("Invalid parameter");/* LCOV_EXCL_LINE */
648 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
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 */
658 return WIDGET_ERROR_NONE;
661 API int widget_app_context_set_title(widget_context_h context,
664 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
666 return WIDGET_ERROR_FAULT;
669 return WIDGET_ERROR_NOT_SUPPORTED;
671 if (context == nullptr || title == nullptr) {
672 _E("Invalid parameter");/* LCOV_EXCL_LINE */
673 return WIDGET_ERROR_INVALID_PARAMETER;/* LCOV_EXCL_LINE */
676 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
677 if (cxt->GetWindow())
678 elm_win_title_set(cxt->GetWindow(), title);/* LCOV_EXCL_LINE */
680 return WIDGET_ERROR_NONE;
683 API int widget_app_restart(void) {
685 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
687 return WIDGET_ERROR_FAULT;
690 return WIDGET_ERROR_NOT_SUPPORTED;
692 if (__app_widget.get() == nullptr)
693 return WIDGET_ERROR_IO_ERROR;
695 std::string class_id;
696 auto l = __app_widget->GetContexts();
698 class_id = i->GetContextId();
702 if (class_id.empty())
703 return WIDGET_ERROR_IO_ERROR;
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));
711 b.Add(AUL_K_WIDGET_ID, class_id);
712 b.Add(AUL_K_WIDGET_STATUS, v);
714 std::string endpoint = __app_widget->GetViewerEndpoint();
715 ret = aul_app_com_send(endpoint.empty() ? nullptr : endpoint.c_str(),
717 if (ret != AUL_R_OK) {
718 _E("Failed to send restart request");
719 return WIDGET_ERROR_IO_ERROR;
722 return WIDGET_ERROR_NONE;