Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: chrome/browser/chromeos/extensions/file_manager/desktop_notifications.cc

Issue 23945002: file_manager: Move non-binding code to c/b/chromeos/file_manager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. 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 "chrome/browser/chromeos/extensions/file_manager/desktop_notifications. h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/stl_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
12 #include "chrome/browser/notifications/desktop_notification_service.h"
13 #include "chrome/browser/notifications/notification_delegate.h"
14 #include "grit/generated_resources.h"
15 #include "grit/theme_resources.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18
19 namespace file_manager {
20 namespace {
21
22 struct NotificationTypeInfo {
23 DesktopNotifications::NotificationType type;
24 const char* notification_id_prefix;
25 int icon_id;
26 int title_id;
27 int message_id;
28 };
29
30 // Information about notification types.
31 // The order of notification types in the array must match the order of types in
32 // NotificationType enum (i.e. the following MUST be satisfied:
33 // kNotificationTypes[type].type == type).
34 const NotificationTypeInfo kNotificationTypes[] = {
35 {
36 DesktopNotifications::DEVICE, // type
37 "Device_", // notification_id_prefix
38 IDR_FILES_APP_ICON, // icon_id
39 IDS_REMOVABLE_DEVICE_DETECTION_TITLE, // title_id
40 IDS_REMOVABLE_DEVICE_SCANNING_MESSAGE // message_id
41 },
42 {
43 DesktopNotifications::DEVICE_FAIL, // type
44 "DeviceFail_", // notification_id_prefix
45 IDR_FILES_APP_ICON, // icon_id
46 IDS_REMOVABLE_DEVICE_DETECTION_TITLE, // title_id
47 IDS_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE // message_id
48 },
49 {
50 DesktopNotifications::DEVICE_EXTERNAL_STORAGE_DISABLED, // type
51 "DeviceFail_", // nottification_id_prefix; same as for DEVICE_FAIL.
52 IDR_FILES_APP_ICON, // icon_id
53 IDS_REMOVABLE_DEVICE_DETECTION_TITLE, // title_id
54 IDS_EXTERNAL_STORAGE_DISABLED_MESSAGE // message_id
55 },
56 {
57 DesktopNotifications::FORMAT_START, // type
58 "FormatStart_", // notification_id_prefix
59 IDR_FILES_APP_ICON, // icon_id
60 IDS_FORMATTING_OF_DEVICE_PENDING_TITLE, // title_id
61 IDS_FORMATTING_OF_DEVICE_PENDING_MESSAGE // message_id
62 },
63 {
64 DesktopNotifications::FORMAT_START_FAIL, // type
65 "FormatComplete_", // notification_id_prefix
66 IDR_FILES_APP_ICON, // icon_id
67 IDS_FORMATTING_OF_DEVICE_FAILED_TITLE, // title_id
68 IDS_FORMATTING_STARTED_FAILURE_MESSAGE // message_id
69 },
70 {
71 DesktopNotifications::FORMAT_SUCCESS, // type
72 "FormatComplete_", // notification_id_prefix
73 IDR_FILES_APP_ICON, // icon_id
74 IDS_FORMATTING_OF_DEVICE_FINISHED_TITLE, // title_id
75 IDS_FORMATTING_FINISHED_SUCCESS_MESSAGE // message_id
76 },
77 {
78 DesktopNotifications::FORMAT_FAIL, // type
79 "FormatComplete_", // notifications_id_prefix
80 IDR_FILES_APP_ICON, // icon_id
81 IDS_FORMATTING_OF_DEVICE_FAILED_TITLE, // title_id
82 IDS_FORMATTING_FINISHED_FAILURE_MESSAGE // message_id
83 },
84 };
85
86 int GetIconId(DesktopNotifications::NotificationType type) {
87 DCHECK_GE(type, 0);
88 DCHECK_LT(static_cast<size_t>(type), arraysize(kNotificationTypes));
89 DCHECK(kNotificationTypes[type].type == type);
90
91 return kNotificationTypes[type].icon_id;
92 }
93
94 string16 GetTitle(DesktopNotifications::NotificationType type) {
95 DCHECK_GE(type, 0);
96 DCHECK_LT(static_cast<size_t>(type), arraysize(kNotificationTypes));
97 DCHECK(kNotificationTypes[type].type == type);
98
99 int id = kNotificationTypes[type].title_id;
100 if (id < 0)
101 return string16();
102 return l10n_util::GetStringUTF16(id);
103 }
104
105 string16 GetMessage(DesktopNotifications::NotificationType type) {
106 DCHECK_GE(type, 0);
107 DCHECK_LT(static_cast<size_t>(type), arraysize(kNotificationTypes));
108 DCHECK(kNotificationTypes[type].type == type);
109
110 int id = kNotificationTypes[type].message_id;
111 if (id < 0)
112 return string16();
113 return l10n_util::GetStringUTF16(id);
114 }
115
116 std::string GetNotificationId(DesktopNotifications::NotificationType type,
117 const std::string& path) {
118 DCHECK_GE(type, 0);
119 DCHECK_LT(static_cast<size_t>(type), arraysize(kNotificationTypes));
120 DCHECK(kNotificationTypes[type].type == type);
121
122 std::string id_prefix(kNotificationTypes[type].notification_id_prefix);
123 return id_prefix.append(path);
124 }
125
126 } // namespace
127
128 // Manages file browser notifications. Generates a desktop notification on
129 // construction and removes it from the host when closed. Owned by the host.
130 class DesktopNotifications::NotificationMessage {
131 public:
132 class Delegate : public NotificationDelegate {
133 public:
134 Delegate(const base::WeakPtr<DesktopNotifications>& host,
135 const std::string& id)
136 : host_(host),
137 id_(id) {}
138 virtual void Display() OVERRIDE {}
139 virtual void Error() OVERRIDE {}
140 virtual void Close(bool by_user) OVERRIDE {
141 if (host_)
142 host_->RemoveNotificationById(id_);
143 }
144 virtual void Click() OVERRIDE {
145 // TODO(tbarzic): Show more info page once we have one.
146 }
147 virtual std::string id() const OVERRIDE { return id_; }
148 virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
149 return NULL;
150 }
151
152 private:
153 virtual ~Delegate() {}
154
155 base::WeakPtr<DesktopNotifications> host_;
156 std::string id_;
157
158 DISALLOW_COPY_AND_ASSIGN(Delegate);
159 };
160
161 NotificationMessage(DesktopNotifications* host,
162 Profile* profile,
163 NotificationType type,
164 const std::string& notification_id,
165 const string16& message)
166 : message_(message) {
167 const gfx::Image& icon =
168 ResourceBundle::GetSharedInstance().GetNativeImageNamed(
169 GetIconId(type));
170 // TODO(mukai): refactor here to invoke NotificationUIManager directly.
171 const string16 replace_id = UTF8ToUTF16(notification_id);
172 DesktopNotificationService::AddIconNotification(
173 util::GetFileManagerBaseUrl(), GetTitle(type),
174 message, icon, replace_id,
175 new Delegate(host->AsWeakPtr(), notification_id), profile);
176 }
177
178 ~NotificationMessage() {}
179
180 // Used in test.
181 string16 message() { return message_; }
182
183 private:
184 string16 message_;
185
186 DISALLOW_COPY_AND_ASSIGN(NotificationMessage);
187 };
188
189 struct DesktopNotifications::MountRequestsInfo {
190 bool mount_success_exists;
191 bool fail_message_finalized;
192 bool fail_notification_shown;
193 bool non_parent_device_failed;
194 bool device_notification_hidden;
195
196 MountRequestsInfo() : mount_success_exists(false),
197 fail_message_finalized(false),
198 fail_notification_shown(false),
199 non_parent_device_failed(false),
200 device_notification_hidden(false) {
201 }
202 };
203
204 DesktopNotifications::DesktopNotifications(Profile* profile)
205 : profile_(profile) {
206 }
207
208 DesktopNotifications::~DesktopNotifications() {
209 STLDeleteContainerPairSecondPointers(notification_map_.begin(),
210 notification_map_.end());
211 }
212
213 void DesktopNotifications::RegisterDevice(const std::string& path) {
214 mount_requests_.insert(MountRequestsMap::value_type(path,
215 MountRequestsInfo()));
216 }
217
218 void DesktopNotifications::UnregisterDevice(const std::string& path) {
219 mount_requests_.erase(path);
220 }
221
222 void DesktopNotifications::ManageNotificationsOnMountCompleted(
223 const std::string& system_path, const std::string& label, bool is_parent,
224 bool success, bool is_unsupported) {
225 MountRequestsMap::iterator it = mount_requests_.find(system_path);
226 if (it == mount_requests_.end())
227 return;
228
229 // We have to hide device scanning notification if we haven't done it already.
230 if (!it->second.device_notification_hidden) {
231 HideNotification(DEVICE, system_path);
232 it->second.device_notification_hidden = true;
233 }
234
235 // Check if there is fail notification for parent device. If so, disregard it.
236 // (parent device contains partition table, which is unmountable).
237 if (!is_parent && it->second.fail_notification_shown &&
238 !it->second.non_parent_device_failed) {
239 HideNotification(DEVICE_FAIL, system_path);
240 it->second.fail_notification_shown = false;
241 }
242
243 // If notification can't change any more, no need to continue.
244 if (it->second.fail_message_finalized)
245 return;
246
247 // Do we have a multi-partition device for which at least one mount failed.
248 bool fail_on_multipartition_device =
249 success ? it->second.non_parent_device_failed
250 : it->second.mount_success_exists ||
251 it->second.non_parent_device_failed;
252
253 base::string16 message;
254 if (fail_on_multipartition_device) {
255 it->second.fail_message_finalized = true;
256 message = label.empty() ?
257 l10n_util::GetStringUTF16(
258 IDS_MULTIPART_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE) :
259 l10n_util::GetStringFUTF16(
260 IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE, UTF8ToUTF16(label));
261 } else if (!success) {
262 // First device failed.
263 if (!is_unsupported) {
264 message = label.empty() ?
265 l10n_util::GetStringUTF16(IDS_DEVICE_UNKNOWN_DEFAULT_MESSAGE) :
266 l10n_util::GetStringFUTF16(IDS_DEVICE_UNKNOWN_MESSAGE,
267 UTF8ToUTF16(label));
268 } else {
269 message = label.empty() ?
270 l10n_util::GetStringUTF16(IDS_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE) :
271 l10n_util::GetStringFUTF16(IDS_DEVICE_UNSUPPORTED_MESSAGE,
272 UTF8ToUTF16(label));
273 }
274 }
275
276 if (success) {
277 it->second.mount_success_exists = true;
278 } else {
279 it->second.non_parent_device_failed |= !is_parent;
280 }
281
282 if (message.empty())
283 return;
284
285 if (it->second.fail_notification_shown) {
286 HideNotification(DEVICE_FAIL, system_path);
287 } else {
288 it->second.fail_notification_shown = true;
289 }
290
291 ShowNotificationWithMessage(DEVICE_FAIL, system_path, message);
292 }
293
294 void DesktopNotifications::ShowNotification(NotificationType type,
295 const std::string& path) {
296 ShowNotificationWithMessage(type, path, GetMessage(type));
297 }
298
299 void DesktopNotifications::ShowNotificationWithMessage(
300 NotificationType type,
301 const std::string& path,
302 const string16& message) {
303 std::string notification_id = GetNotificationId(type, path);
304 hidden_notifications_.erase(notification_id);
305 ShowNotificationById(type, notification_id, message);
306 }
307
308 void DesktopNotifications::ShowNotificationDelayed(
309 NotificationType type,
310 const std::string& path,
311 base::TimeDelta delay) {
312 std::string notification_id = GetNotificationId(type, path);
313 hidden_notifications_.erase(notification_id);
314 base::MessageLoop::current()->PostDelayedTask(
315 FROM_HERE,
316 base::Bind(&DesktopNotifications::ShowNotificationById, AsWeakPtr(),
317 type, notification_id, GetMessage(type)),
318 delay);
319 }
320
321 void DesktopNotifications::HideNotification(NotificationType type,
322 const std::string& path) {
323 std::string notification_id = GetNotificationId(type, path);
324 HideNotificationById(notification_id);
325 }
326
327 void DesktopNotifications::HideNotificationDelayed(
328 NotificationType type, const std::string& path, base::TimeDelta delay) {
329 base::MessageLoop::current()->PostDelayedTask(
330 FROM_HERE,
331 base::Bind(&DesktopNotifications::HideNotification, AsWeakPtr(),
332 type, path),
333 delay);
334 }
335
336 void DesktopNotifications::ShowNotificationById(
337 NotificationType type,
338 const std::string& notification_id,
339 const string16& message) {
340 if (hidden_notifications_.find(notification_id) !=
341 hidden_notifications_.end()) {
342 // Notification was hidden after a delayed show was requested.
343 hidden_notifications_.erase(notification_id);
344 return;
345 }
346 if (notification_map_.find(notification_id) != notification_map_.end()) {
347 // Remove any existing notification with |notification_id|.
348 // Will trigger Delegate::Close which will call RemoveNotificationById.
349 DesktopNotificationService::RemoveNotification(notification_id);
350 DCHECK(notification_map_.find(notification_id) == notification_map_.end());
351 }
352 // Create a new notification with |notification_id|.
353 NotificationMessage* new_message =
354 new NotificationMessage(this, profile_, type, notification_id, message);
355 notification_map_[notification_id] = new_message;
356 }
357
358 void DesktopNotifications::HideNotificationById(
359 const std::string& notification_id) {
360 NotificationMap::iterator it = notification_map_.find(notification_id);
361 if (it != notification_map_.end()) {
362 // Will trigger Delegate::Close which will call RemoveNotificationById.
363 DesktopNotificationService::RemoveNotification(notification_id);
364 } else {
365 // Mark as hidden so it does not get shown from a delayed task.
366 hidden_notifications_.insert(notification_id);
367 }
368 }
369
370 void DesktopNotifications::RemoveNotificationById(
371 const std::string& notification_id) {
372 NotificationMap::iterator it = notification_map_.find(notification_id);
373 if (it != notification_map_.end()) {
374 NotificationMessage* notification = it->second;
375 notification_map_.erase(it);
376 delete notification;
377 }
378 }
379
380 string16 DesktopNotifications::GetNotificationMessageForTest(
381 const std::string& id) const {
382 NotificationMap::const_iterator it = notification_map_.find(id);
383 if (it == notification_map_.end())
384 return string16();
385 return it->second->message();
386 }
387
388 } // namespace file_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698