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 {
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 void SetIconifyTimer() {
244 iconify_timer_ = g_timeout_add(kIconifyTimeout,
245 [](gpointer user_data) -> gboolean{
246 AppWidgetContext* cxt = static_cast<AppWidgetContext*>(user_data);
247 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
248 ecore_evas_ecore_evas_get(evas_object_evas_get(cxt->win_)));
250 ecore_wl2_window_iconified_set(win, EINA_TRUE);
251 cxt->is_iconified_ = true;
252 _D("Set iconify true");
255 cxt->iconify_timer_ = 0;
256 return G_SOURCE_REMOVE;
260 void UnsetIconifyTimer() {
261 if (iconify_timer_) {
262 g_source_remove(iconify_timer_);
268 widget_instance_lifecycle_callback_s callback_;
270 Evas_Object* win_ = nullptr;
271 guint iconify_timer_ = 0;
272 bool is_iconified_ = false;
273 void* tag_ = nullptr;
276 std::unique_ptr<AppWidget> __app_widget;
277 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
281 API int widget_app_main(int argc, char** argv,
282 widget_app_lifecycle_callback_s* callback, void* user_data) {
284 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
286 return WIDGET_ERROR_FAULT;
289 return WIDGET_ERROR_NOT_SUPPORTED;
291 if (argc <= 0 || argv == nullptr || callback == nullptr) {
292 _E("Invalid parameter");
293 return WIDGET_ERROR_INVALID_PARAMETER;
296 if (callback->create == nullptr) {
297 _E("widget_app_create_cb() callback must be registered");
298 return WIDGET_ERROR_INVALID_PARAMETER;
302 __app_widget = std::make_unique<AppWidget>(callback, user_data);
303 for (auto& i : __pending_app_events)
304 __app_widget->AddEvent(i);
306 __app_widget->Run(argc, argv);
307 } catch (std::runtime_error& e) {
308 return WIDGET_ERROR_FAULT;
311 return WIDGET_ERROR_NONE;
314 API int widget_app_exit(void) {
316 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
318 return WIDGET_ERROR_FAULT;
321 return WIDGET_ERROR_NOT_SUPPORTED;
323 if (__app_widget.get() == nullptr)
324 return WIDGET_ERROR_FAULT;
326 __app_widget->Exit();
327 return WIDGET_ERROR_NONE;
330 API int widget_app_terminate_context(widget_context_h context) {
332 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
334 return WIDGET_ERROR_FAULT;
337 return WIDGET_ERROR_NOT_SUPPORTED;
339 if (context == nullptr) {
340 _E("Invalid parameter");
341 return WIDGET_ERROR_INVALID_PARAMETER;
344 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
346 return WIDGET_ERROR_NONE;
349 API int widget_app_foreach_context(widget_context_cb cb, void* data) {
351 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
353 return WIDGET_ERROR_FAULT;
356 return WIDGET_ERROR_NOT_SUPPORTED;
359 _E("Invalid parameter");
360 return WIDGET_ERROR_INVALID_PARAMETER;
363 if (__app_widget.get() == nullptr)
364 return WIDGET_ERROR_FAULT;
366 auto l = __app_widget->GetContexts();
368 if (!cb(reinterpret_cast<widget_context_h>(i.get()), data))
372 return WIDGET_ERROR_NONE;
375 API int widget_app_add_event_handler(app_event_handler_h* event_handler,
376 app_event_type_e event_type, app_event_cb callback, void* user_data) {
378 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
380 return WIDGET_ERROR_FAULT;
383 return WIDGET_ERROR_NOT_SUPPORTED;
385 if (event_handler == nullptr || callback == nullptr)
386 return WIDGET_ERROR_INVALID_PARAMETER;
388 if (event_type < APP_EVENT_LOW_MEMORY ||
389 event_type > APP_EVENT_TIME_ZONE_CHANGED)
390 return WIDGET_ERROR_INVALID_PARAMETER;
392 if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
393 return WIDGET_ERROR_NOT_SUPPORTED;
395 auto* app_event = new (std::nothrow) AppEvent(
396 ::__app_event_converter[event_type], callback, user_data);
397 if (app_event == nullptr) {
399 return WIDGET_ERROR_OUT_OF_MEMORY;
402 auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(app_event);
406 return WIDGET_ERROR_OUT_OF_MEMORY;
409 if (__app_widget.get() != nullptr)
410 __app_widget->AddEvent(*h);
412 __pending_app_events.push_back(*h);
414 *event_handler = reinterpret_cast<app_event_handler_h>(h);
415 return WIDGET_ERROR_NONE;
418 API int widget_app_remove_event_handler(app_event_handler_h event_handler) {
420 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
422 return WIDGET_ERROR_FAULT;
425 return WIDGET_ERROR_NOT_SUPPORTED;
427 if (event_handler == nullptr)
428 return WIDGET_ERROR_INVALID_PARAMETER;
430 auto* h = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
432 if (__app_widget.get() != nullptr) {
433 if (!__app_widget->RemoveEvent(*h))
434 return WIDGET_ERROR_INVALID_PARAMETER;
436 __pending_app_events.remove(*h);
440 return WIDGET_ERROR_NONE;
443 API const char* widget_app_get_id(widget_context_h context) {
445 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
447 set_last_result(WIDGET_ERROR_FAULT);
452 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
456 if (context == nullptr) {
457 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
461 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
462 const std::string& id = cxt->GetInstId();
463 set_last_result(WIDGET_ERROR_NONE);
467 API int widget_app_get_elm_win(widget_context_h context, Evas_Object** win) {
469 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
471 return WIDGET_ERROR_FAULT;
474 return WIDGET_ERROR_NOT_SUPPORTED;
476 if (context == nullptr || win == nullptr) {
477 _E("Invalid parameter");
478 return WIDGET_ERROR_INVALID_PARAMETER;
481 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
482 const std::string& id = cxt->GetInstId();
484 Evas_Object* ret_win = elm_win_add(nullptr, id.c_str(), ELM_WIN_BASIC);
485 if (ret_win == nullptr) {
486 _E("Failed to create window");
487 return WIDGET_ERROR_FAULT;
490 elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
491 int rots[3] = { 0, };
492 elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
494 Ecore_Wl2_Window* wl_win = ecore_evas_wayland2_window_get(
495 ecore_evas_ecore_evas_get(evas_object_evas_get(ret_win)));
496 if (wl_win == nullptr) {
497 _E("Failed to get wayland window");
498 evas_object_del(ret_win);
499 return WIDGET_ERROR_FAULT;
502 ecore_wl2_window_class_set(wl_win, id.c_str());
503 elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
504 cxt->WindowBind(id, wl_win);
506 /* Set data to use in accessibility */
507 std::string plug_id = id + ":" + std::to_string(getpid());
508 evas_object_data_set(ret_win, "___PLUGID", strdup(plug_id.c_str()));
509 evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL,
510 [](void *data, Evas *e, Evas_Object *obj, void *event_info) {
511 char* plug_id = static_cast<char*>(
512 evas_object_data_del(obj, "___PLUGID"));
516 int win_id = ecore_wl2_window_id_get(wl_win);
517 _D("Window created: %d", win_id);
519 cxt->SetWindow(ret_win);
521 return WIDGET_ERROR_NONE;
524 API widget_class_h widget_app_class_add(widget_class_h widget_class,
525 const char* class_id, widget_instance_lifecycle_callback_s callback,
528 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
530 set_last_result(WIDGET_ERROR_FAULT);
535 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
539 if (class_id == nullptr || callback.create == nullptr) {
540 _E("Invalid parameter");
541 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
545 if (__app_widget.get() == nullptr) {
546 set_last_result(WIDGET_ERROR_FAULT);
550 auto factory = std::shared_ptr<AppCoreMultiWindowBase::Context::IFactory>(
551 new (std::nothrow) AppWidgetContext::Factory(
552 class_id, callback, user_data));
553 if (factory.get() == nullptr) {
554 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
558 __app_widget->AddContextFactory(std::move(factory), class_id);
559 set_last_result(WIDGET_ERROR_NONE);
560 static int dummy = 1;
561 widget_class_h cls = reinterpret_cast<widget_class_h>(&dummy);
565 API widget_class_h widget_app_class_create(
566 widget_instance_lifecycle_callback_s callback, void* user_data) {
568 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
570 set_last_result(WIDGET_ERROR_FAULT);
575 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
579 if (callback.create == nullptr) {
580 _E("Invalid parameter");
581 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
585 char* appid = nullptr;
587 if (appid == nullptr) {
588 LOGE("app_get_id() is failed");
591 std::unique_ptr<char, decltype(std::free)*> ptr(appid, std::free);
593 return static_cast<widget_class_h>(
594 widget_app_class_add(nullptr, appid, callback, user_data));
597 API int widget_app_context_set_tag(widget_context_h context, void* tag) {
599 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
601 return WIDGET_ERROR_FAULT;
604 return WIDGET_ERROR_NOT_SUPPORTED;
606 if (context == nullptr) {
607 _E("Invalid parameter");
608 return WIDGET_ERROR_INVALID_PARAMETER;
611 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
613 return WIDGET_ERROR_NONE;
616 API int widget_app_context_get_tag(widget_context_h context, void** tag) {
618 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
620 return WIDGET_ERROR_FAULT;
623 return WIDGET_ERROR_NOT_SUPPORTED;
625 if (context == nullptr || tag == nullptr) {
626 _E("Invalid parameter");
627 return WIDGET_ERROR_INVALID_PARAMETER;
630 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
631 *tag = cxt->GetTag();
632 return WIDGET_ERROR_NONE;
635 API int widget_app_context_set_content_info(widget_context_h context,
636 bundle* content_info) {
638 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
640 return WIDGET_ERROR_FAULT;
643 return WIDGET_ERROR_NOT_SUPPORTED;
645 if (context == nullptr || content_info == nullptr) {
646 _E("Invalid parameter");
647 return WIDGET_ERROR_INVALID_PARAMETER;
650 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
651 ret = cxt->SetContents(tizen_base::Bundle(content_info));
652 if (ret != WIDGET_ERROR_NONE) {
653 _E("Failed to set content");
654 return static_cast<widget_error_e>(ret);
657 return WIDGET_ERROR_NONE;
660 API int widget_app_context_set_title(widget_context_h context,
663 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
665 return WIDGET_ERROR_FAULT;
668 return WIDGET_ERROR_NOT_SUPPORTED;
670 if (context == nullptr || title == nullptr) {
671 _E("Invalid parameter");
672 return WIDGET_ERROR_INVALID_PARAMETER;
675 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
676 if (cxt->GetWindow())
677 elm_win_title_set(cxt->GetWindow(), title);
679 return WIDGET_ERROR_NONE;
682 API int widget_app_restart(void) {
684 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
686 return WIDGET_ERROR_FAULT;
689 return WIDGET_ERROR_NOT_SUPPORTED;
691 if (__app_widget.get() == nullptr)
692 return WIDGET_ERROR_IO_ERROR;
694 std::string class_id;
695 auto l = __app_widget->GetContexts();
697 class_id = i->GetContextId();
701 if (class_id.empty())
702 return WIDGET_ERROR_IO_ERROR;
704 tizen_base::Bundle b;
705 int status = AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST;
706 std::vector<unsigned char> v;
707 auto* p = reinterpret_cast<const uint8_t*>(&status);
708 std::copy(p, p + sizeof(int), std::back_inserter(v));
710 b.Add(AUL_K_WIDGET_ID, class_id);
711 b.Add(AUL_K_WIDGET_STATUS, v);
713 std::string endpoint = __app_widget->GetViewerEndpoint();
714 ret = aul_app_com_send(endpoint.empty() ? nullptr : endpoint.c_str(),
716 if (ret != AUL_R_OK) {
717 _E("Failed to send restart request");
718 return WIDGET_ERROR_IO_ERROR;
721 return WIDGET_ERROR_NONE;