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>
29 #include "common/export_private.hh"
30 #include "common/log_private.hh"
31 #include "include/widget_app.h"
32 #include "include/widget_app_internal.h"
33 #include "include/widget_base.hh"
35 using namespace tizen_cpp;
38 constexpr const int kIconifyTimeout = 500;
39 constexpr const char kFeatureShellAppWidget[] =
40 "http://tizen.org/feature/shell.appwidget";
41 constexpr int APP_EVENT_MAX = 7;
42 constexpr IAppCore::IEvent::Type __app_event_converter[APP_EVENT_MAX] = {
43 [APP_EVENT_LOW_MEMORY] = IAppCore::IEvent::Type::LOW_MEMORY,
44 [APP_EVENT_LOW_BATTERY] = IAppCore::IEvent::Type::LOW_BATTERY,
45 [APP_EVENT_LANGUAGE_CHANGED] = IAppCore::IEvent::Type::LANG_CHANGE,
46 [APP_EVENT_DEVICE_ORIENTATION_CHANGED]
47 = IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED,
48 [APP_EVENT_REGION_FORMAT_CHANGED] = IAppCore::IEvent::Type::REGION_CHANGE,
49 [APP_EVENT_SUSPENDED_STATE_CHANGED]
50 = IAppCore::IEvent::Type::SUSPENDED_STATE_CHANGE,
53 class AppWidget : public WidgetBase {
55 AppWidget(widget_app_lifecycle_callback_s* callback, void* user_data)
56 : callback_(callback), user_data_(user_data) {}
58 int OnCreate() override {
59 WidgetBase::OnCreate();
60 if (callback_ && callback_->create) {
61 if (callback_->create(user_data_) == nullptr) {
62 _E("Failed to create widget");
66 _D("Widget app is created");
67 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
74 int OnTerminate() override {
75 if (callback_ && callback_->terminate) {
76 callback_->terminate(user_data_);
77 WidgetBase::OnTerminate();
78 _D("Widget app is terminated");
79 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
83 WidgetBase::OnTerminate();
87 void OnLoopInit(int argc, char** argv) override {
91 void OnLoopFinish() override {
95 void OnLoopRun() override {
99 void OnLoopExit() override {
103 int OnTrimMemory() override {
105 elm_cache_all_flush();
106 return WidgetBase::OnTrimMemory();
110 widget_app_lifecycle_callback_s* callback_;
114 class AppWidgetContext : public WidgetContext {
116 class Factory : public AppCoreMultiWindowBase::Context::IFactory {
118 Factory(std::string widget_id,
119 widget_instance_lifecycle_callback_s callback, void* user_data)
120 : widget_id_(std::move(widget_id)),
122 user_data_(user_data) {
125 std::unique_ptr<Context> Create(std::string inst_id,
126 AppCoreMultiWindowBase* app) override {
127 return std::unique_ptr<Context>(
128 new AppWidgetContext(widget_id_, std::move(inst_id), app,
129 callback_, user_data_));
133 std::string widget_id_;
134 widget_instance_lifecycle_callback_s callback_;
138 AppWidgetContext(std::string context_id, std::string inst_id,
139 AppCoreMultiWindowBase* app,
140 widget_instance_lifecycle_callback_s callback, void* user_data)
141 : WidgetContext(std::move(context_id), std::move(inst_id), app),
142 callback_(callback), user_data_(user_data) {}
144 bool OnCreate(const tizen_base::Bundle& contents, int w, int h) override {
146 if (callback_.create) {
147 ret = callback_.create(reinterpret_cast<widget_context_h>(this),
148 contents.GetHandle(), w, h, user_data_);
149 aul_widget_write_log(LOG_TAG, "[%s:%d] ret : %d",
150 __FUNCTION__, __LINE__, ret);
156 void OnDestroy(DestroyType reason,
157 const tizen_base::Bundle& contents) override {
158 if (callback_.destroy) {
159 callback_.destroy(reinterpret_cast<widget_context_h>(this),
160 reason == DestroyType::PERMANENT ? WIDGET_APP_DESTROY_TYPE_PERMANENT :
161 WIDGET_APP_DESTROY_TYPE_TEMPORARY, contents.GetHandle(), user_data_);
162 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
168 void OnPause() override {
172 WidgetContext::OnPause();
173 if (callback_.pause) {
174 callback_.pause(reinterpret_cast<widget_context_h>(this), user_data_);
178 void OnResume() override {
182 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
183 ecore_evas_ecore_evas_get(evas_object_evas_get(win_)));
185 ecore_wl2_window_iconified_set(win, EINA_FALSE);
186 is_iconified_ = false;
187 _D("Set iconify false");
191 WidgetContext::OnResume();
192 if (callback_.resume) {
193 callback_.resume(reinterpret_cast<widget_context_h>(this), user_data_);
197 void OnResize(int w, int h) override {
198 WidgetContext::OnResize(w, h);
201 evas_object_resize(win_, w, h);
203 _E("Failed to find window");
205 if (callback_.resize) {
206 callback_.resize(reinterpret_cast<widget_context_h>(this),
211 void OnUpdate(const tizen_base::Bundle& contents, bool force) override {
212 WidgetContext::OnUpdate(contents, force);
213 if (callback_.update) {
214 callback_.update(reinterpret_cast<widget_context_h>(this),
215 contents.GetHandle(), force, user_data_);
219 void SetTag(void* tag) {
223 void* GetTag() const {
227 Evas_Object* GetWindow() const {
231 void SetWindow(Evas_Object* win) {
236 void SetIconifyTimer() {
240 iconify_timer_ = g_timeout_add(kIconifyTimeout,
241 [](gpointer user_data) -> gboolean{
242 AppWidgetContext* cxt = static_cast<AppWidgetContext*>(user_data);
243 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
244 ecore_evas_ecore_evas_get(evas_object_evas_get(cxt->win_)));
246 ecore_wl2_window_iconified_set(win, EINA_TRUE);
247 cxt->is_iconified_ = true;
248 _D("Set iconify true");
251 cxt->iconify_timer_ = 0;
252 return G_SOURCE_REMOVE;
256 void UnsetIconifyTimer() {
257 if (iconify_timer_) {
258 g_source_remove(iconify_timer_);
264 widget_instance_lifecycle_callback_s callback_;
266 Evas_Object* win_ = nullptr;
267 guint iconify_timer_ = 0;
268 bool is_iconified_ = false;
269 void* tag_ = nullptr;
272 std::unique_ptr<AppWidget> __app_widget;
273 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
277 API int widget_app_main(int argc, char** argv,
278 widget_app_lifecycle_callback_s* callback, void* user_data) {
280 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
282 return WIDGET_ERROR_FAULT;
285 return WIDGET_ERROR_NOT_SUPPORTED;
287 if (argc <= 0 || argv == nullptr || callback == nullptr) {
288 _E("Invalid parameter");
289 return WIDGET_ERROR_INVALID_PARAMETER;
292 if (callback->create == nullptr) {
293 _E("widget_app_create_cb() callback must be registered");
294 return WIDGET_ERROR_INVALID_PARAMETER;
298 __app_widget = std::make_unique<AppWidget>(callback, user_data);
299 for (auto& i : __pending_app_events)
300 __app_widget->AddEvent(i);
302 __app_widget->Run(argc, argv);
303 } catch (std::runtime_error& e) {
304 return WIDGET_ERROR_FAULT;
307 return WIDGET_ERROR_NONE;
310 API int widget_app_exit(void) {
312 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
314 return WIDGET_ERROR_FAULT;
317 return WIDGET_ERROR_NOT_SUPPORTED;
319 if (__app_widget.get() == nullptr)
320 return WIDGET_ERROR_FAULT;
322 __app_widget->Exit();
323 return WIDGET_ERROR_NONE;
326 API int widget_app_terminate_context(widget_context_h context) {
328 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
330 return WIDGET_ERROR_FAULT;
333 return WIDGET_ERROR_NOT_SUPPORTED;
335 if (context == nullptr) {
336 _E("Invalid parameter");
337 return WIDGET_ERROR_INVALID_PARAMETER;
340 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
342 return WIDGET_ERROR_NONE;
345 API int widget_app_foreach_context(widget_context_cb cb, void* data) {
347 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
349 return WIDGET_ERROR_FAULT;
352 return WIDGET_ERROR_NOT_SUPPORTED;
355 _E("Invalid parameter");
356 return WIDGET_ERROR_INVALID_PARAMETER;
359 if (__app_widget.get() == nullptr)
360 return WIDGET_ERROR_FAULT;
362 auto l = __app_widget->GetContexts();
364 if (!cb(reinterpret_cast<widget_context_h>(i.get()), data))
368 return WIDGET_ERROR_NONE;
371 API int widget_app_add_event_handler(app_event_handler_h* event_handler,
372 app_event_type_e event_type, app_event_cb callback, void* user_data) {
374 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
376 return WIDGET_ERROR_FAULT;
379 return WIDGET_ERROR_NOT_SUPPORTED;
381 if (event_handler == nullptr || callback == nullptr)
382 return WIDGET_ERROR_INVALID_PARAMETER;
384 if (event_type < APP_EVENT_LOW_MEMORY ||
385 event_type > APP_EVENT_REGION_FORMAT_CHANGED)
386 return WIDGET_ERROR_INVALID_PARAMETER;
388 if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
389 return WIDGET_ERROR_NOT_SUPPORTED;
391 auto* app_event = new (std::nothrow) AppEvent(
392 ::__app_event_converter[event_type], callback, user_data);
393 if (app_event == nullptr) {
395 return WIDGET_ERROR_OUT_OF_MEMORY;
398 auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(app_event);
402 return WIDGET_ERROR_OUT_OF_MEMORY;
405 if (__app_widget.get() != nullptr)
406 __app_widget->AddEvent(*h);
408 __pending_app_events.push_back(*h);
410 *event_handler = reinterpret_cast<app_event_handler_h>(h);
411 return WIDGET_ERROR_NONE;
414 API int widget_app_remove_event_handler(app_event_handler_h event_handler) {
416 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
418 return WIDGET_ERROR_FAULT;
421 return WIDGET_ERROR_NOT_SUPPORTED;
423 if (event_handler == nullptr)
424 return WIDGET_ERROR_INVALID_PARAMETER;
426 auto* h = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
428 if (__app_widget.get() != nullptr) {
429 if (!__app_widget->RemoveEvent(*h))
430 return WIDGET_ERROR_INVALID_PARAMETER;
432 __pending_app_events.remove(*h);
436 return WIDGET_ERROR_NONE;
439 API const char* widget_app_get_id(widget_context_h context) {
441 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
443 set_last_result(WIDGET_ERROR_FAULT);
448 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
452 if (context == nullptr) {
453 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
457 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
458 const std::string& id = cxt->GetInstId();
459 set_last_result(WIDGET_ERROR_NONE);
463 API int widget_app_get_elm_win(widget_context_h context, Evas_Object** win) {
465 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
467 return WIDGET_ERROR_FAULT;
470 return WIDGET_ERROR_NOT_SUPPORTED;
472 if (context == nullptr || win == nullptr) {
473 _E("Invalid parameter");
474 return WIDGET_ERROR_INVALID_PARAMETER;
477 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
478 const std::string& id = cxt->GetInstId();
480 Evas_Object* ret_win = elm_win_add(nullptr, id.c_str(), ELM_WIN_BASIC);
481 if (ret_win == nullptr) {
482 _E("Failed to create window");
483 return WIDGET_ERROR_FAULT;
486 elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
487 int rots[3] = { 0, };
488 elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
490 Ecore_Wl2_Window* wl_win = ecore_evas_wayland2_window_get(
491 ecore_evas_ecore_evas_get(evas_object_evas_get(ret_win)));
492 if (wl_win == nullptr) {
493 _E("Failed to get wayland window");
494 evas_object_del(ret_win);
495 return WIDGET_ERROR_FAULT;
498 ecore_wl2_window_class_set(wl_win, id.c_str());
499 elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
500 cxt->WindowBind(id, wl_win);
502 /* Set data to use in accessibility */
503 std::string plug_id = id + ":" + std::to_string(getpid());
504 evas_object_data_set(ret_win, "___PLUGID", strdup(plug_id.c_str()));
505 evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL,
506 [](void *data, Evas *e, Evas_Object *obj, void *event_info) {
507 char* plug_id = static_cast<char*>(
508 evas_object_data_del(obj, "___PLUGID"));
512 int win_id = ecore_wl2_window_id_get(wl_win);
513 _D("Window created: %d", win_id);
515 cxt->SetWindow(ret_win);
517 return WIDGET_ERROR_NONE;
520 API widget_class_h widget_app_class_add(widget_class_h widget_class,
521 const char* class_id, widget_instance_lifecycle_callback_s callback,
524 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
526 set_last_result(WIDGET_ERROR_FAULT);
531 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
535 if (class_id == nullptr || callback.create == nullptr) {
536 _E("Invalid parameter");
537 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
541 if (__app_widget.get() == nullptr) {
542 set_last_result(WIDGET_ERROR_FAULT);
546 auto factory = std::shared_ptr<AppCoreMultiWindowBase::Context::IFactory>(
547 new (std::nothrow) AppWidgetContext::Factory(
548 class_id, callback, user_data));
549 if (factory.get() == nullptr) {
550 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
554 __app_widget->AddContextFactory(std::move(factory), class_id);
555 set_last_result(WIDGET_ERROR_NONE);
557 widget_class_h cls = reinterpret_cast<widget_class_h>(&dummy);
561 API widget_class_h widget_app_class_create(
562 widget_instance_lifecycle_callback_s callback, void* user_data) {
564 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
566 set_last_result(WIDGET_ERROR_FAULT);
571 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
575 if (callback.create == nullptr) {
576 _E("Invalid parameter");
577 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
581 char* appid = nullptr;
583 if (appid == nullptr) {
584 LOGE("app_get_id() is failed");
587 std::unique_ptr<char, decltype(std::free)*> ptr(appid, std::free);
589 return static_cast<widget_class_h>(
590 widget_app_class_add(nullptr, appid, callback, user_data));
593 API int widget_app_context_set_tag(widget_context_h context, void* tag) {
595 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
597 return WIDGET_ERROR_FAULT;
600 return WIDGET_ERROR_NOT_SUPPORTED;
602 if (context == nullptr) {
603 _E("Invalid parameter");
604 return WIDGET_ERROR_INVALID_PARAMETER;
607 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
609 return WIDGET_ERROR_NONE;
612 API int widget_app_context_get_tag(widget_context_h context, void** tag) {
614 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
616 return WIDGET_ERROR_FAULT;
619 return WIDGET_ERROR_NOT_SUPPORTED;
621 if (context == nullptr || tag == nullptr) {
622 _E("Invalid parameter");
623 return WIDGET_ERROR_INVALID_PARAMETER;
626 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
627 *tag = cxt->GetTag();
628 return WIDGET_ERROR_NONE;
631 API int widget_app_context_set_content_info(widget_context_h context,
632 bundle* content_info) {
634 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
636 return WIDGET_ERROR_FAULT;
639 return WIDGET_ERROR_NOT_SUPPORTED;
641 if (context == nullptr || content_info == nullptr) {
642 _E("Invalid parameter");
643 return WIDGET_ERROR_INVALID_PARAMETER;
646 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
647 ret = cxt->SetContents(tizen_base::Bundle(content_info));
648 if (ret != WIDGET_ERROR_NONE) {
649 _E("Failed to set content");
650 return static_cast<widget_error_e>(ret);
653 return WIDGET_ERROR_NONE;
656 API int widget_app_context_set_title(widget_context_h context,
659 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
661 return WIDGET_ERROR_FAULT;
664 return WIDGET_ERROR_NOT_SUPPORTED;
666 if (context == nullptr || title == nullptr) {
667 _E("Invalid parameter");
668 return WIDGET_ERROR_INVALID_PARAMETER;
671 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
672 if (cxt->GetWindow())
673 elm_win_title_set(cxt->GetWindow(), title);
675 return WIDGET_ERROR_NONE;
678 API int widget_app_restart(void) {
680 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
682 return WIDGET_ERROR_FAULT;
685 return WIDGET_ERROR_NOT_SUPPORTED;
687 if (__app_widget.get() == nullptr)
688 return WIDGET_ERROR_IO_ERROR;
690 std::string class_id;
691 auto l = __app_widget->GetContexts();
693 class_id = i->GetContextId();
697 if (class_id.empty())
698 return WIDGET_ERROR_IO_ERROR;
700 tizen_base::Bundle b;
701 int status = AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST;
702 std::vector<unsigned char> v;
703 auto* p = reinterpret_cast<const uint8_t*>(&status);
704 std::copy(p, p + sizeof(int), std::back_inserter(v));
706 b.Add(AUL_K_WIDGET_ID, class_id);
707 b.Add(AUL_K_WIDGET_STATUS, v);
709 std::string endpoint = __app_widget->GetViewerEndpoint();
710 ret = aul_app_com_send(endpoint.empty() ? nullptr : endpoint.c_str(),
712 if (ret != AUL_R_OK) {
713 _E("Failed to send restart request");
714 return WIDGET_ERROR_IO_ERROR;
717 return WIDGET_ERROR_NONE;