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 = 7;
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,
55 class AppWidget : public WidgetBase {
57 AppWidget(widget_app_lifecycle_callback_s* callback, void* user_data)
58 : callback_(callback), user_data_(user_data) {}
60 int OnCreate() override {
61 WidgetBase::OnCreate();
62 if (callback_ && callback_->create) {
63 if (callback_->create(user_data_) == nullptr) {
64 _E("Failed to create widget");
68 _D("Widget app is created");
69 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
76 int OnTerminate() override {
77 if (callback_ && callback_->terminate) {
78 callback_->terminate(user_data_);
79 WidgetBase::OnTerminate();
80 _D("Widget app is terminated");
81 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
85 WidgetBase::OnTerminate();
89 void OnLoopInit(int argc, char** argv) override {
93 void OnLoopFinish() override {
97 void OnLoopRun() override {
101 void OnLoopExit() override {
105 int OnTrimMemory() override {
107 elm_cache_all_flush();
108 return WidgetBase::OnTrimMemory();
112 widget_app_lifecycle_callback_s* callback_;
116 class AppWidgetContext : public WidgetContext {
118 class Factory : public AppCoreMultiWindowBase::Context::IFactory {
120 Factory(std::string widget_id,
121 widget_instance_lifecycle_callback_s callback, void* user_data)
122 : widget_id_(std::move(widget_id)),
124 user_data_(user_data) {
127 std::unique_ptr<Context> Create(std::string inst_id,
128 AppCoreMultiWindowBase* app) override {
129 return std::unique_ptr<Context>(
130 new AppWidgetContext(widget_id_, std::move(inst_id), app,
131 callback_, user_data_));
135 std::string widget_id_;
136 widget_instance_lifecycle_callback_s callback_;
140 AppWidgetContext(std::string context_id, std::string inst_id,
141 AppCoreMultiWindowBase* app,
142 widget_instance_lifecycle_callback_s callback, void* user_data)
143 : WidgetContext(std::move(context_id), std::move(inst_id), app),
144 callback_(callback), user_data_(user_data) {}
146 bool OnCreate(const tizen_base::Bundle& contents, int w, int h) override {
148 if (callback_.create) {
149 ret = callback_.create(reinterpret_cast<widget_context_h>(this),
150 contents.GetHandle(), w, h, user_data_);
151 aul_widget_write_log(LOG_TAG, "[%s:%d] ret : %d",
152 __FUNCTION__, __LINE__, ret);
158 void OnDestroy(DestroyType reason,
159 const tizen_base::Bundle& contents) override {
160 if (callback_.destroy) {
161 callback_.destroy(reinterpret_cast<widget_context_h>(this),
162 reason == DestroyType::PERMANENT ? WIDGET_APP_DESTROY_TYPE_PERMANENT :
163 WIDGET_APP_DESTROY_TYPE_TEMPORARY, contents.GetHandle(), user_data_);
164 aul_widget_write_log(LOG_TAG, "[%s:%d]", __FUNCTION__, __LINE__);
170 void OnPause() override {
174 WidgetContext::OnPause();
175 if (callback_.pause) {
176 callback_.pause(reinterpret_cast<widget_context_h>(this), user_data_);
180 void OnResume() override {
184 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
185 ecore_evas_ecore_evas_get(evas_object_evas_get(win_)));
187 ecore_wl2_window_iconified_set(win, EINA_FALSE);
188 is_iconified_ = false;
189 _D("Set iconify false");
193 WidgetContext::OnResume();
194 if (callback_.resume) {
195 callback_.resume(reinterpret_cast<widget_context_h>(this), user_data_);
199 void OnResize(int w, int h) override {
200 WidgetContext::OnResize(w, h);
203 evas_object_resize(win_, w, h);
205 _E("Failed to find window");
207 if (callback_.resize) {
208 callback_.resize(reinterpret_cast<widget_context_h>(this),
213 void OnUpdate(const tizen_base::Bundle& contents, bool force) override {
214 WidgetContext::OnUpdate(contents, force);
215 if (callback_.update) {
216 callback_.update(reinterpret_cast<widget_context_h>(this),
217 contents.GetHandle(), force, user_data_);
221 void SetTag(void* tag) {
225 void* GetTag() const {
229 Evas_Object* GetWindow() const {
233 void SetWindow(Evas_Object* win) {
238 void SetIconifyTimer() {
242 iconify_timer_ = g_timeout_add(kIconifyTimeout,
243 [](gpointer user_data) -> gboolean{
244 AppWidgetContext* cxt = static_cast<AppWidgetContext*>(user_data);
245 Ecore_Wl2_Window* win = ecore_evas_wayland2_window_get(
246 ecore_evas_ecore_evas_get(evas_object_evas_get(cxt->win_)));
248 ecore_wl2_window_iconified_set(win, EINA_TRUE);
249 cxt->is_iconified_ = true;
250 _D("Set iconify true");
253 cxt->iconify_timer_ = 0;
254 return G_SOURCE_REMOVE;
258 void UnsetIconifyTimer() {
259 if (iconify_timer_) {
260 g_source_remove(iconify_timer_);
266 widget_instance_lifecycle_callback_s callback_;
268 Evas_Object* win_ = nullptr;
269 guint iconify_timer_ = 0;
270 bool is_iconified_ = false;
271 void* tag_ = nullptr;
274 std::unique_ptr<AppWidget> __app_widget;
275 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
279 API int widget_app_main(int argc, char** argv,
280 widget_app_lifecycle_callback_s* callback, void* user_data) {
282 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
284 return WIDGET_ERROR_FAULT;
287 return WIDGET_ERROR_NOT_SUPPORTED;
289 if (argc <= 0 || argv == nullptr || callback == nullptr) {
290 _E("Invalid parameter");
291 return WIDGET_ERROR_INVALID_PARAMETER;
294 if (callback->create == nullptr) {
295 _E("widget_app_create_cb() callback must be registered");
296 return WIDGET_ERROR_INVALID_PARAMETER;
300 __app_widget = std::make_unique<AppWidget>(callback, user_data);
301 for (auto& i : __pending_app_events)
302 __app_widget->AddEvent(i);
304 __app_widget->Run(argc, argv);
305 } catch (std::runtime_error& e) {
306 return WIDGET_ERROR_FAULT;
309 return WIDGET_ERROR_NONE;
312 API int widget_app_exit(void) {
314 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
316 return WIDGET_ERROR_FAULT;
319 return WIDGET_ERROR_NOT_SUPPORTED;
321 if (__app_widget.get() == nullptr)
322 return WIDGET_ERROR_FAULT;
324 __app_widget->Exit();
325 return WIDGET_ERROR_NONE;
328 API int widget_app_terminate_context(widget_context_h context) {
330 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
332 return WIDGET_ERROR_FAULT;
335 return WIDGET_ERROR_NOT_SUPPORTED;
337 if (context == nullptr) {
338 _E("Invalid parameter");
339 return WIDGET_ERROR_INVALID_PARAMETER;
342 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
344 return WIDGET_ERROR_NONE;
347 API int widget_app_foreach_context(widget_context_cb cb, void* data) {
349 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
351 return WIDGET_ERROR_FAULT;
354 return WIDGET_ERROR_NOT_SUPPORTED;
357 _E("Invalid parameter");
358 return WIDGET_ERROR_INVALID_PARAMETER;
361 if (__app_widget.get() == nullptr)
362 return WIDGET_ERROR_FAULT;
364 auto l = __app_widget->GetContexts();
366 if (!cb(reinterpret_cast<widget_context_h>(i.get()), data))
370 return WIDGET_ERROR_NONE;
373 API int widget_app_add_event_handler(app_event_handler_h* event_handler,
374 app_event_type_e event_type, app_event_cb callback, void* user_data) {
376 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
378 return WIDGET_ERROR_FAULT;
381 return WIDGET_ERROR_NOT_SUPPORTED;
383 if (event_handler == nullptr || callback == nullptr)
384 return WIDGET_ERROR_INVALID_PARAMETER;
386 if (event_type < APP_EVENT_LOW_MEMORY ||
387 event_type > APP_EVENT_REGION_FORMAT_CHANGED)
388 return WIDGET_ERROR_INVALID_PARAMETER;
390 if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
391 return WIDGET_ERROR_NOT_SUPPORTED;
393 auto* app_event = new (std::nothrow) AppEvent(
394 ::__app_event_converter[event_type], callback, user_data);
395 if (app_event == nullptr) {
397 return WIDGET_ERROR_OUT_OF_MEMORY;
400 auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(app_event);
404 return WIDGET_ERROR_OUT_OF_MEMORY;
407 if (__app_widget.get() != nullptr)
408 __app_widget->AddEvent(*h);
410 __pending_app_events.push_back(*h);
412 *event_handler = reinterpret_cast<app_event_handler_h>(h);
413 return WIDGET_ERROR_NONE;
416 API int widget_app_remove_event_handler(app_event_handler_h event_handler) {
418 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
420 return WIDGET_ERROR_FAULT;
423 return WIDGET_ERROR_NOT_SUPPORTED;
425 if (event_handler == nullptr)
426 return WIDGET_ERROR_INVALID_PARAMETER;
428 auto* h = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
430 if (__app_widget.get() != nullptr) {
431 if (!__app_widget->RemoveEvent(*h))
432 return WIDGET_ERROR_INVALID_PARAMETER;
434 __pending_app_events.remove(*h);
438 return WIDGET_ERROR_NONE;
441 API const char* widget_app_get_id(widget_context_h context) {
443 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
445 set_last_result(WIDGET_ERROR_FAULT);
450 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
454 if (context == nullptr) {
455 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
459 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
460 const std::string& id = cxt->GetInstId();
461 set_last_result(WIDGET_ERROR_NONE);
465 API int widget_app_get_elm_win(widget_context_h context, Evas_Object** win) {
467 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
469 return WIDGET_ERROR_FAULT;
472 return WIDGET_ERROR_NOT_SUPPORTED;
474 if (context == nullptr || win == nullptr) {
475 _E("Invalid parameter");
476 return WIDGET_ERROR_INVALID_PARAMETER;
479 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
480 const std::string& id = cxt->GetInstId();
482 Evas_Object* ret_win = elm_win_add(nullptr, id.c_str(), ELM_WIN_BASIC);
483 if (ret_win == nullptr) {
484 _E("Failed to create window");
485 return WIDGET_ERROR_FAULT;
488 elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
489 int rots[3] = { 0, };
490 elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
492 Ecore_Wl2_Window* wl_win = ecore_evas_wayland2_window_get(
493 ecore_evas_ecore_evas_get(evas_object_evas_get(ret_win)));
494 if (wl_win == nullptr) {
495 _E("Failed to get wayland window");
496 evas_object_del(ret_win);
497 return WIDGET_ERROR_FAULT;
500 ecore_wl2_window_class_set(wl_win, id.c_str());
501 elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
502 cxt->WindowBind(id, wl_win);
504 /* Set data to use in accessibility */
505 std::string plug_id = id + ":" + std::to_string(getpid());
506 evas_object_data_set(ret_win, "___PLUGID", strdup(plug_id.c_str()));
507 evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL,
508 [](void *data, Evas *e, Evas_Object *obj, void *event_info) {
509 char* plug_id = static_cast<char*>(
510 evas_object_data_del(obj, "___PLUGID"));
514 int win_id = ecore_wl2_window_id_get(wl_win);
515 _D("Window created: %d", win_id);
517 cxt->SetWindow(ret_win);
519 return WIDGET_ERROR_NONE;
522 API widget_class_h widget_app_class_add(widget_class_h widget_class,
523 const char* class_id, widget_instance_lifecycle_callback_s callback,
526 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
528 set_last_result(WIDGET_ERROR_FAULT);
533 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
537 if (class_id == nullptr || callback.create == nullptr) {
538 _E("Invalid parameter");
539 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
543 if (__app_widget.get() == nullptr) {
544 set_last_result(WIDGET_ERROR_FAULT);
548 auto factory = std::shared_ptr<AppCoreMultiWindowBase::Context::IFactory>(
549 new (std::nothrow) AppWidgetContext::Factory(
550 class_id, callback, user_data));
551 if (factory.get() == nullptr) {
552 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
556 __app_widget->AddContextFactory(std::move(factory), class_id);
557 set_last_result(WIDGET_ERROR_NONE);
558 static int dummy = 1;
559 widget_class_h cls = reinterpret_cast<widget_class_h>(&dummy);
563 API widget_class_h widget_app_class_create(
564 widget_instance_lifecycle_callback_s callback, void* user_data) {
566 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
568 set_last_result(WIDGET_ERROR_FAULT);
573 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
577 if (callback.create == nullptr) {
578 _E("Invalid parameter");
579 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
583 char* appid = nullptr;
585 if (appid == nullptr) {
586 LOGE("app_get_id() is failed");
589 std::unique_ptr<char, decltype(std::free)*> ptr(appid, std::free);
591 return static_cast<widget_class_h>(
592 widget_app_class_add(nullptr, appid, callback, user_data));
595 API int widget_app_context_set_tag(widget_context_h context, void* tag) {
597 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
599 return WIDGET_ERROR_FAULT;
602 return WIDGET_ERROR_NOT_SUPPORTED;
604 if (context == nullptr) {
605 _E("Invalid parameter");
606 return WIDGET_ERROR_INVALID_PARAMETER;
609 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
611 return WIDGET_ERROR_NONE;
614 API int widget_app_context_get_tag(widget_context_h context, void** tag) {
616 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
618 return WIDGET_ERROR_FAULT;
621 return WIDGET_ERROR_NOT_SUPPORTED;
623 if (context == nullptr || tag == nullptr) {
624 _E("Invalid parameter");
625 return WIDGET_ERROR_INVALID_PARAMETER;
628 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
629 *tag = cxt->GetTag();
630 return WIDGET_ERROR_NONE;
633 API int widget_app_context_set_content_info(widget_context_h context,
634 bundle* content_info) {
636 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
638 return WIDGET_ERROR_FAULT;
641 return WIDGET_ERROR_NOT_SUPPORTED;
643 if (context == nullptr || content_info == nullptr) {
644 _E("Invalid parameter");
645 return WIDGET_ERROR_INVALID_PARAMETER;
648 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
649 ret = cxt->SetContents(tizen_base::Bundle(content_info));
650 if (ret != WIDGET_ERROR_NONE) {
651 _E("Failed to set content");
652 return static_cast<widget_error_e>(ret);
655 return WIDGET_ERROR_NONE;
658 API int widget_app_context_set_title(widget_context_h context,
661 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
663 return WIDGET_ERROR_FAULT;
666 return WIDGET_ERROR_NOT_SUPPORTED;
668 if (context == nullptr || title == nullptr) {
669 _E("Invalid parameter");
670 return WIDGET_ERROR_INVALID_PARAMETER;
673 auto* cxt = reinterpret_cast<AppWidgetContext*>(context);
674 if (cxt->GetWindow())
675 elm_win_title_set(cxt->GetWindow(), title);
677 return WIDGET_ERROR_NONE;
680 API int widget_app_restart(void) {
682 int ret = system_info_get_platform_bool(kFeatureShellAppWidget, &feature);
684 return WIDGET_ERROR_FAULT;
687 return WIDGET_ERROR_NOT_SUPPORTED;
689 if (__app_widget.get() == nullptr)
690 return WIDGET_ERROR_IO_ERROR;
692 std::string class_id;
693 auto l = __app_widget->GetContexts();
695 class_id = i->GetContextId();
699 if (class_id.empty())
700 return WIDGET_ERROR_IO_ERROR;
702 tizen_base::Bundle b;
703 int status = AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST;
704 std::vector<unsigned char> v;
705 auto* p = reinterpret_cast<const uint8_t*>(&status);
706 std::copy(p, p + sizeof(int), std::back_inserter(v));
708 b.Add(AUL_K_WIDGET_ID, class_id);
709 b.Add(AUL_K_WIDGET_STATUS, v);
711 std::string endpoint = __app_widget->GetViewerEndpoint();
712 ret = aul_app_com_send(endpoint.empty() ? nullptr : endpoint.c_str(),
714 if (ret != AUL_R_OK) {
715 _E("Failed to send restart request");
716 return WIDGET_ERROR_IO_ERROR;
719 return WIDGET_ERROR_NONE;