1 // Copyright 2019 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "wrt/src/browser/wrt_notification.h"
7 #include <notification_internal.h>
9 #include "base/files/file_util.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/logging.h"
12 #include "base/notreached.h"
13 #include "base/path_service.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "electron/shell/browser/notifications/notification_delegate.h"
16 #include "tizen_src/chromium_impl/content/common/paths_efl.h"
17 #include "tizen_src/ewk/efl_integration/common/web_contents_utils.h"
18 #include "ui/gfx/codec/png_codec.h"
24 bool SetNotificationImage(notification_h noti,
25 notification_image_type_e type,
26 const SkBitmap& bitmap,
27 const base::FilePath& path) {
28 std::vector<unsigned char> data;
29 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &data)) {
30 LOG(ERROR) << "Bitmap color type " << bitmap.colorType();
34 size_t written = base::WriteFile(path,
35 reinterpret_cast<char*>(&*data.begin()), data.size());
37 if (written == data.size()) {
38 if (notification_set_image(noti, type, path.value().data()) ==
39 NOTIFICATION_ERROR_NONE) {
42 LOG(ERROR) << "Failed to set notification image." << path.value();
44 LOG(ERROR) << "Failed to write image file. " << path.value()
45 << ", written size:" << written << "/" << data.size();
47 base::DeleteFile(path);
51 void NotificationEventCallback(
52 notification_h noti, int event_type, void* userdata) {
53 auto thiz = static_cast<WRTNotification*>(userdata);
54 int notification_priv_id = NOTIFICATION_PRIV_ID_NONE;
55 if (!thiz || notification_get_id(noti, nullptr, ¬ification_priv_id) !=
56 NOTIFICATION_ERROR_NONE) {
60 if (event_type == NOTIFICATION_EVENT_TYPE_PRESSED) {
61 thiz->NotificationClicked();
63 thiz->NotificationDismissed();
66 const char* tag = nullptr;
67 int noti_err = notification_get_tag(noti, &tag);
68 if (tag && noti_err == NOTIFICATION_ERROR_NONE)
69 thiz->RemoveImageFiles(tag);
74 WRTNotification::WRTNotification(electron::NotificationDelegate* delegate,
75 electron::NotificationPresenter* presenter)
76 : electron::Notification(delegate, presenter) {}
78 WRTNotification::~WRTNotification() {}
80 void WRTNotification::Show(const electron::NotificationOptions& options) {
81 notification_h noti_h =
82 notification_new(NOTIFICATION_TYPE_NOTI, NOTIFICATION_GROUP_ID_DEFAULT,
83 NOTIFICATION_PRIV_ID_NONE);
85 LOG(ERROR) << "Can't create notification handle.";
89 std::unique_ptr<std::remove_pointer<notification_h>::type,
90 decltype(notification_free)*>
91 auto_release{noti_h, notification_free};
93 // Set notification title.
94 int ret = notification_set_text(
95 noti_h, NOTIFICATION_TEXT_TYPE_TITLE,
96 base::UTF16ToUTF8(options.title).c_str(), nullptr,
97 NOTIFICATION_VARIABLE_TYPE_NONE);
98 if (ret != NOTIFICATION_ERROR_NONE) {
99 LOG(ERROR) << "Can't set title" << ret;
103 // Set notification content.
104 ret = notification_set_text(noti_h, NOTIFICATION_TEXT_TYPE_CONTENT,
105 base::UTF16ToUTF8(options.msg).c_str(), nullptr,
106 NOTIFICATION_VARIABLE_TYPE_NONE);
107 if (ret != NOTIFICATION_ERROR_NONE) {
108 LOG(ERROR) << "Can't set content" << ret;
112 base::FilePath noti_path;
113 if (base::PathService::Get(PathsEfl::DIR_SHARED_NOTI_ICON, ¬i_path)) {
114 bool has_images = false;
115 const std::string tag_str = options.tag;
117 if (SetNotificationImage(
118 noti_h, NOTIFICATION_IMAGE_TYPE_ICON, options.icon,
119 noti_path.AppendASCII(tag_str + ".icon"))) {
123 // Set a tag to remove icon images after closing notification.
125 notification_set_tag(noti_h, tag_str.c_str());
127 LOG(ERROR) << "Failed to retrieve the notification resource path";
129 // Set notification type.
130 ret = notification_set_display_applist(
131 noti_h, NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY |
132 NOTIFICATION_DISPLAY_APP_TICKER |
133 NOTIFICATION_DISPLAY_APP_INDICATOR);
134 if (ret != NOTIFICATION_ERROR_NONE) {
135 LOG(ERROR) << "notification_set_display_applist is failed with " << ret;
139 // TODO: If application has been killed, currently there is no way to launch
140 // application to run service worker when notification closed. If platform
141 // support new API, we don't need to use |notification_post_with_event_cb|.
142 ret = notification_post_with_event_cb(noti_h, NotificationEventCallback,
144 if (ret != NOTIFICATION_ERROR_NONE) {
145 LOG(ERROR) << "notification_post_with_event_cb is failed with " << ret;
146 NotificationFailed();
150 int notification_priv_id = NOTIFICATION_PRIV_ID_NONE;
151 ret = notification_get_id(noti_h, nullptr, ¬ification_priv_id);
152 if (ret != NOTIFICATION_ERROR_NONE) {
153 LOG(ERROR) << "Can't get notification ID " << ret;
157 delegate()->NotificationDisplayed();
160 void WRTNotification::Dismiss() {
164 void WRTNotification::RemoveImageFiles(const std::string& tag) {
165 base::FilePath image_path;
166 if (!base::PathService::Get(PathsEfl::DIR_SHARED_NOTI_ICON, &image_path)) {
167 LOG(ERROR) << "Failed to retrieve the notification resource path";
172 // Remove all unused icons.
173 base::FileEnumerator enumerator(image_path, false,
174 base::FileEnumerator::FILES);
175 for (base::FilePath file = enumerator.Next(); !file.empty();
176 file = enumerator.Next()) {
177 const std::string file_str = file.BaseName().value();
178 size_t dot_at = file_str.find_last_of('.');
179 if (dot_at != std::string::npos) {
180 notification_h noti =
181 notification_load_by_tag(file_str.substr(0, dot_at).c_str());
183 notification_free(noti);
184 else if (!base::DeleteFile(file))
185 LOG(ERROR) << "Failed to delete icon. " << file_str;
191 if (!base::DeleteFile(image_path.AppendASCII(tag + ".icon"))) {
192 LOG(ERROR) << "Failed to delete icon. "
193 << image_path.AppendASCII(tag).value();
195 if (!base::DeleteFile(image_path.AppendASCII(tag + ".badge"))) {
196 LOG(ERROR) << "Failed to delete badge. "
197 << image_path.AppendASCII(tag).value();