[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / wrt_notification.cc
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.
4
5 #include "wrt/src/browser/wrt_notification.h"
6
7 #include <notification_internal.h>
8
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"
19
20 namespace wrt {
21
22 namespace {
23
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();
31     return false;
32   }
33
34   size_t written = base::WriteFile(path,
35       reinterpret_cast<char*>(&*data.begin()), data.size());
36
37   if (written == data.size()) {
38     if (notification_set_image(noti, type, path.value().data()) ==
39         NOTIFICATION_ERROR_NONE) {
40       return true;
41     }
42     LOG(ERROR) << "Failed to set notification image." << path.value();
43   } else {
44     LOG(ERROR) << "Failed to write image file. " << path.value()
45                << ", written size:" << written << "/" << data.size();
46   }
47   base::DeleteFile(path);
48   return false;
49 }
50
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, &notification_priv_id) !=
56       NOTIFICATION_ERROR_NONE) {
57     return;
58   }
59
60   if (event_type == NOTIFICATION_EVENT_TYPE_PRESSED) {
61     thiz->NotificationClicked();
62   } else {
63     thiz->NotificationDismissed();
64   }
65
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);
70 }
71
72 }  // namespace
73
74 WRTNotification::WRTNotification(electron::NotificationDelegate* delegate,
75                                  electron::NotificationPresenter* presenter)
76     : electron::Notification(delegate, presenter) {}
77
78 WRTNotification::~WRTNotification() {}
79
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);
84   if (!noti_h) {
85     LOG(ERROR) << "Can't create notification handle.";
86     return;
87   }
88
89   std::unique_ptr<std::remove_pointer<notification_h>::type,
90                   decltype(notification_free)*>
91       auto_release{noti_h, notification_free};
92
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;
100     return;
101   }
102
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;
109     return;
110   }
111
112   base::FilePath noti_path;
113   if (base::PathService::Get(PathsEfl::DIR_SHARED_NOTI_ICON, &noti_path)) {
114     bool has_images = false;
115     const std::string tag_str = options.tag;
116
117     if (SetNotificationImage(
118         noti_h, NOTIFICATION_IMAGE_TYPE_ICON, options.icon,
119         noti_path.AppendASCII(tag_str + ".icon"))) {
120       has_images = true;
121     }
122
123     // Set a tag to remove icon images after closing notification.
124     if (has_images)
125       notification_set_tag(noti_h, tag_str.c_str());
126   } else
127     LOG(ERROR) << "Failed to retrieve the notification resource path";
128
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;
136     return;
137   }
138
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,
143                                         this);
144   if (ret != NOTIFICATION_ERROR_NONE) {
145     LOG(ERROR) << "notification_post_with_event_cb is failed with " << ret;
146     NotificationFailed();
147     return;
148   }
149
150   int notification_priv_id = NOTIFICATION_PRIV_ID_NONE;
151   ret = notification_get_id(noti_h, nullptr, &notification_priv_id);
152   if (ret != NOTIFICATION_ERROR_NONE) {
153     LOG(ERROR) << "Can't get notification ID " << ret;
154     return;
155   }
156   if (delegate())
157     delegate()->NotificationDisplayed();
158 }
159
160 void WRTNotification::Dismiss() {
161   NOTREACHED();
162 }
163
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";
168     return;
169   }
170
171   if (tag.empty()) {
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());
182         if (noti)
183           notification_free(noti);
184         else if (!base::DeleteFile(file))
185           LOG(ERROR) << "Failed to delete icon. " << file_str;
186       }
187     }
188     return;
189   }
190
191   if (!base::DeleteFile(image_path.AppendASCII(tag + ".icon"))) {
192     LOG(ERROR) << "Failed to delete icon. "
193                << image_path.AppendASCII(tag).value();
194   }
195   if (!base::DeleteFile(image_path.AppendASCII(tag + ".badge"))) {
196     LOG(ERROR) << "Failed to delete badge. "
197                << image_path.AppendASCII(tag).value();
198   }
199 }
200
201 }  // namespace wrt