OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/notifications/notification_platform_bridge_mac.h" | 5 #include "chrome/browser/notifications/notification_platform_bridge_mac.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/command_line.h" | |
12 #include "base/mac/bundle_locations.h" | |
9 #include "base/mac/foundation_util.h" | 13 #include "base/mac/foundation_util.h" |
10 #include "base/mac/mac_util.h" | 14 #include "base/mac/mac_util.h" |
11 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
13 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
14 #include "chrome/browser/notifications/native_notification_display_service.h" | 18 #include "chrome/browser/notifications/native_notification_display_service.h" |
15 #include "chrome/browser/notifications/notification.h" | 19 #include "chrome/browser/notifications/notification.h" |
16 #include "chrome/browser/notifications/notification_common.h" | 20 #include "chrome/browser/notifications/notification_common.h" |
17 #include "chrome/browser/notifications/notification_display_service_factory.h" | 21 #include "chrome/browser/notifications/notification_display_service_factory.h" |
18 #include "chrome/browser/notifications/persistent_notification_delegate.h" | 22 #include "chrome/browser/notifications/persistent_notification_delegate.h" |
19 #include "chrome/browser/notifications/platform_notification_service_impl.h" | 23 #include "chrome/browser/notifications/platform_notification_service_impl.h" |
20 #include "chrome/browser/profiles/profile.h" | 24 #include "chrome/browser/profiles/profile.h" |
21 #include "chrome/browser/profiles/profile_manager.h" | 25 #include "chrome/browser/profiles/profile_manager.h" |
22 #include "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h" | 26 #include "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h" |
27 #import "chrome/browser/ui/cocoa/notifications/notification_delivery.h" | |
23 #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h" | 28 #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h" |
24 #import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac .h" | 29 #import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac .h" |
30 #include "chrome/common/chrome_switches.h" | |
25 #include "chrome/grit/generated_resources.h" | 31 #include "chrome/grit/generated_resources.h" |
26 #include "components/url_formatter/elide_url.h" | 32 #include "components/url_formatter/elide_url.h" |
27 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificati onConstants.h" | 33 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificati onConstants.h" |
28 #include "ui/base/l10n/l10n_util_mac.h" | 34 #include "ui/base/l10n/l10n_util_mac.h" |
29 #include "url/gurl.h" | 35 #include "url/gurl.h" |
30 #include "url/origin.h" | 36 #include "url/origin.h" |
31 | 37 |
32 @class NSUserNotification; | 38 @class NSUserNotification; |
33 @class NSUserNotificationCenter; | 39 @class NSUserNotificationCenter; |
34 | 40 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 } | 72 } |
67 | 73 |
68 NotificationDisplayService* display_service = | 74 NotificationDisplayService* display_service = |
69 NotificationDisplayServiceFactory::GetForProfile(profile); | 75 NotificationDisplayServiceFactory::GetForProfile(profile); |
70 | 76 |
71 static_cast<NativeNotificationDisplayService*>(display_service) | 77 static_cast<NativeNotificationDisplayService*>(display_service) |
72 ->ProcessNotificationOperation(operation, notification_type, origin, | 78 ->ProcessNotificationOperation(operation, notification_type, origin, |
73 notification_id, action_index); | 79 notification_id, action_index); |
74 } | 80 } |
75 | 81 |
82 // Loads the profile and process the Notification response | |
83 void DoProcessNotificationResponse(NotificationCommon::Operation operation, | |
84 NotificationCommon::Type type, | |
85 const std::string& profile_id, | |
86 bool incognito, | |
87 const std::string& origin, | |
88 const std::string& notification_id, | |
89 int32_t button_index) { | |
90 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
91 ProfileManager* profileManager = g_browser_process->profile_manager(); | |
Peter Beverloo
2016/07/19 17:31:40
nit: profile_manager
| |
92 DCHECK(profileManager); | |
93 | |
94 profileManager->LoadProfile( | |
95 profile_id, incognito, base::Bind(&ProfileLoadedCallback, operation, type, | |
96 origin, notification_id, button_index)); | |
97 } | |
98 | |
76 } // namespace | 99 } // namespace |
77 | 100 |
78 // static | 101 // static |
79 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | 102 NotificationPlatformBridge* NotificationPlatformBridge::Create() { |
80 return new NotificationPlatformBridgeMac( | 103 return new NotificationPlatformBridgeMac( |
81 [NSUserNotificationCenter defaultUserNotificationCenter]); | 104 [NSUserNotificationCenter defaultUserNotificationCenter]); |
82 } | 105 } |
83 | 106 |
84 // A Cocoa class that represents the delegate of NSUserNotificationCenter and | 107 // A Cocoa class that represents the delegate of NSUserNotificationCenter and |
85 // can forward commands to C++. | 108 // can forward commands to C++. |
86 @interface NotificationCenterDelegate | 109 @interface NotificationCenterDelegate |
87 : NSObject<NSUserNotificationCenterDelegate> { | 110 : NSObject<NSUserNotificationCenterDelegate> { |
88 } | 111 } |
89 @end | 112 @end |
90 | 113 |
91 // ///////////////////////////////////////////////////////////////////////////// | 114 // ///////////////////////////////////////////////////////////////////////////// |
92 | 115 |
93 NotificationPlatformBridgeMac::NotificationPlatformBridgeMac( | 116 NotificationPlatformBridgeMac::NotificationPlatformBridgeMac( |
94 NSUserNotificationCenter* notification_center) | 117 NSUserNotificationCenter* notification_center) |
95 : delegate_([NotificationCenterDelegate alloc]), | 118 : delegate_([NotificationCenterDelegate alloc]), |
96 notification_center_(notification_center) { | 119 notification_center_(notification_center), |
120 notification_remote_dispatcher_( | |
121 [[NotificationRemoteDispatcher alloc] init]) { | |
97 [notification_center_ setDelegate:delegate_.get()]; | 122 [notification_center_ setDelegate:delegate_.get()]; |
98 } | 123 } |
99 | 124 |
100 NotificationPlatformBridgeMac::~NotificationPlatformBridgeMac() { | 125 NotificationPlatformBridgeMac::~NotificationPlatformBridgeMac() { |
101 [notification_center_ setDelegate:nil]; | 126 [notification_center_ setDelegate:nil]; |
102 | 127 |
103 // TODO(miguelg) lift this restriction if possible. | 128 // TODO(miguelg) lift this restriction if possible. |
129 // But make sure the ones shown by the XPC service are actually | |
Peter Beverloo
2016/07/19 17:31:40
Is this a continuation from the TODO on line 128?
| |
130 // removed. | |
104 [notification_center_ removeAllDeliveredNotifications]; | 131 [notification_center_ removeAllDeliveredNotifications]; |
105 } | 132 } |
106 | 133 |
107 void NotificationPlatformBridgeMac::Display( | 134 void NotificationPlatformBridgeMac::Display( |
108 NotificationCommon::Type notification_type, | 135 NotificationCommon::Type notification_type, |
109 const std::string& notification_id, | 136 const std::string& notification_id, |
110 const std::string& profile_id, | 137 const std::string& profile_id, |
111 bool incognito, | 138 bool incognito, |
112 const Notification& notification) { | 139 const Notification& notification) { |
113 base::scoped_nsobject<NotificationBuilder> builder( | 140 base::scoped_nsobject<NotificationBuilder> builder( |
(...skipping 20 matching lines...) Expand all Loading... | |
134 NSString* buttonOne = SysUTF16ToNSString(buttons[0].title); | 161 NSString* buttonOne = SysUTF16ToNSString(buttons[0].title); |
135 NSString* buttonTwo = nullptr; | 162 NSString* buttonTwo = nullptr; |
136 if (buttons.size() > 1) | 163 if (buttons.size() > 1) |
137 buttonTwo = SysUTF16ToNSString(buttons[1].title); | 164 buttonTwo = SysUTF16ToNSString(buttons[1].title); |
138 [builder setButtons:buttonOne secondaryButton:buttonTwo]; | 165 [builder setButtons:buttonOne secondaryButton:buttonTwo]; |
139 } | 166 } |
140 | 167 |
141 // Tag | 168 // Tag |
142 if (!notification.tag().empty()) { | 169 if (!notification.tag().empty()) { |
143 [builder setTag:base::SysUTF8ToNSString(notification.tag())]; | 170 [builder setTag:base::SysUTF8ToNSString(notification.tag())]; |
171 | |
144 // If renotify is needed, delete the notification with the same tag | 172 // If renotify is needed, delete the notification with the same tag |
145 // from the notification center before displaying this one. | 173 // from the notification center before displaying this one. |
146 // TODO(miguelg): This will need to work for alerts as well via XPC | 174 // TODO(miguelg): This will need to work for alerts as well via XPC |
147 // once supported. | 175 // once supported. |
148 if (notification.renotify()) { | 176 if (notification.renotify()) { |
149 NSUserNotificationCenter* notification_center = | 177 NSUserNotificationCenter* notification_center = |
150 [NSUserNotificationCenter defaultUserNotificationCenter]; | 178 [NSUserNotificationCenter defaultUserNotificationCenter]; |
151 for (NSUserNotification* existing_notification in | 179 for (NSUserNotification* existing_notification in |
152 [notification_center deliveredNotifications]) { | 180 [notification_center deliveredNotifications]) { |
153 NSString* identifier = | 181 NSString* identifier = |
154 [existing_notification valueForKey:@"identifier"]; | 182 [existing_notification valueForKey:@"identifier"]; |
155 if ([identifier | 183 if ([identifier |
156 isEqualToString:base::SysUTF8ToNSString(notification.tag())]) { | 184 isEqualToString:base::SysUTF8ToNSString(notification.tag())]) { |
157 [notification_center | 185 [notification_center |
158 removeDeliveredNotification:existing_notification]; | 186 removeDeliveredNotification:existing_notification]; |
159 break; | 187 break; |
160 } | 188 } |
161 } | 189 } |
162 } | 190 } |
163 } | 191 } |
164 | 192 |
165 [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())]; | 193 [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())]; |
166 [builder setNotificationId:base::SysUTF8ToNSString(notification_id)]; | 194 [builder setNotificationId:base::SysUTF8ToNSString(notification_id)]; |
167 [builder setProfileId:base::SysUTF8ToNSString(profile_id)]; | 195 [builder setProfileId:base::SysUTF8ToNSString(profile_id)]; |
168 [builder setIncognito:incognito]; | 196 [builder setIncognito:incognito]; |
169 [builder setNotificationType:[NSNumber numberWithInteger:notification_type]]; | 197 [builder setNotificationType:[NSNumber numberWithInteger:notification_type]]; |
170 | 198 if (notification.never_timeout() && |
Peter Beverloo
2016/07/19 17:31:40
nit:
// TODO(miguelg): Remove the command line
| |
171 NSUserNotification* toast = [builder buildUserNotification]; | 199 base::CommandLine::ForCurrentProcess()->HasSwitch( |
172 [notification_center_ deliverNotification:toast]; | 200 switches::kEnableNativeAlerts)) { |
201 NSDictionary* dict = [builder buildDictionary]; | |
202 [notification_remote_dispatcher_ dispatchNotification:dict]; | |
203 } else { | |
204 NSUserNotification* toast = [builder buildUserNotification]; | |
205 [notification_center_ deliverNotification:toast]; | |
206 } | |
173 } | 207 } |
174 | 208 |
175 void NotificationPlatformBridgeMac::Close(const std::string& profile_id, | 209 void NotificationPlatformBridgeMac::Close(const std::string& profile_id, |
176 const std::string& notification_id) { | 210 const std::string& notification_id) { |
177 NSString* candidate_id = base::SysUTF8ToNSString(notification_id); | 211 NSString* candidate_id = base::SysUTF8ToNSString(notification_id); |
178 | 212 |
179 NSString* current_profile_id = base::SysUTF8ToNSString(profile_id); | 213 NSString* current_profile_id = base::SysUTF8ToNSString(profile_id); |
180 for (NSUserNotification* toast in | 214 for (NSUserNotification* toast in |
181 [notification_center_ deliveredNotifications]) { | 215 [notification_center_ deliveredNotifications]) { |
182 NSString* toast_id = | 216 NSString* toast_id = |
(...skipping 26 matching lines...) Expand all Loading... | |
209 } | 243 } |
210 } | 244 } |
211 return true; | 245 return true; |
212 } | 246 } |
213 | 247 |
214 bool NotificationPlatformBridgeMac::SupportsNotificationCenter() const { | 248 bool NotificationPlatformBridgeMac::SupportsNotificationCenter() const { |
215 return true; | 249 return true; |
216 } | 250 } |
217 | 251 |
218 // static | 252 // static |
253 void NotificationPlatformBridgeMac::ProcessNotificationResponse( | |
254 NSDictionary* notificationResponseData) { | |
255 if (!NotificationPlatformBridgeMac::VerifyNotificationData( | |
256 notificationResponseData)) | |
Peter Beverloo
2016/07/19 17:31:40
nit: brackets around the return (this now is a mul
| |
257 return; | |
258 | |
259 NSNumber* buttonIndex = [notificationResponseData | |
260 objectForKey:notification_constants::kNotificationButtonIndex]; | |
261 NSNumber* operation = [notificationResponseData | |
262 objectForKey:notification_constants::kNotificationOperation]; | |
263 | |
264 std::string notificationOrigin = | |
265 base::SysNSStringToUTF8([notificationResponseData | |
266 objectForKey:notification_constants::kNotificationOrigin]); | |
267 std::string notificationId = base::SysNSStringToUTF8([notificationResponseData | |
268 objectForKey:notification_constants::kNotificationId]); | |
269 std::string profileId = base::SysNSStringToUTF8([notificationResponseData | |
270 objectForKey:notification_constants::kNotificationProfileId]); | |
271 NSNumber* isIncognito = [notificationResponseData | |
272 objectForKey:notification_constants::kNotificationIncognito]; | |
273 NSNumber* notificationType = [notificationResponseData | |
274 objectForKey:notification_constants::kNotificationType]; | |
275 | |
276 content::BrowserThread::PostTask( | |
277 content::BrowserThread::UI, FROM_HERE, | |
278 base::Bind(DoProcessNotificationResponse, | |
279 static_cast<NotificationCommon::Operation>( | |
280 operation.unsignedIntValue), | |
281 static_cast<NotificationCommon::Type>( | |
282 notificationType.unsignedIntValue), | |
283 profileId, [isIncognito boolValue], notificationOrigin, | |
284 notificationId, buttonIndex.intValue)); | |
285 } | |
286 | |
287 // static | |
219 bool NotificationPlatformBridgeMac::VerifyNotificationData( | 288 bool NotificationPlatformBridgeMac::VerifyNotificationData( |
220 NSDictionary* response) { | 289 NSDictionary* response) { |
221 if (![response | 290 if (![response |
222 objectForKey:notification_constants::kNotificationButtonIndex] || | 291 objectForKey:notification_constants::kNotificationButtonIndex] || |
223 ![response objectForKey:notification_constants::kNotificationOperation] || | 292 ![response objectForKey:notification_constants::kNotificationOperation] || |
224 ![response objectForKey:notification_constants::kNotificationId] || | 293 ![response objectForKey:notification_constants::kNotificationId] || |
225 ![response objectForKey:notification_constants::kNotificationProfileId] || | 294 ![response objectForKey:notification_constants::kNotificationProfileId] || |
226 ![response objectForKey:notification_constants::kNotificationIncognito] || | 295 ![response objectForKey:notification_constants::kNotificationIncognito] || |
227 ![response objectForKey:notification_constants::kNotificationType]) { | 296 ![response objectForKey:notification_constants::kNotificationType]) { |
228 LOG(ERROR) << "Missing required key"; | 297 LOG(ERROR) << "Missing required key"; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 } | 350 } |
282 | 351 |
283 return true; | 352 return true; |
284 } | 353 } |
285 | 354 |
286 // ///////////////////////////////////////////////////////////////////////////// | 355 // ///////////////////////////////////////////////////////////////////////////// |
287 | 356 |
288 @implementation NotificationCenterDelegate | 357 @implementation NotificationCenterDelegate |
289 - (void)userNotificationCenter:(NSUserNotificationCenter*)center | 358 - (void)userNotificationCenter:(NSUserNotificationCenter*)center |
290 didActivateNotification:(NSUserNotification*)notification { | 359 didActivateNotification:(NSUserNotification*)notification { |
291 NSDictionary* response = | 360 NSDictionary* notificationResponseData = |
292 [NotificationResponseBuilder buildDictionary:notification]; | 361 [NotificationResponseBuilder buildDictionary:notification]; |
293 if (!NotificationPlatformBridgeMac::VerifyNotificationData(response)) | 362 NotificationPlatformBridgeMac::ProcessNotificationResponse( |
294 return; | 363 notificationResponseData); |
295 | |
296 NSNumber* buttonIndex = | |
297 [response objectForKey:notification_constants::kNotificationButtonIndex]; | |
298 NSNumber* operation = | |
299 [response objectForKey:notification_constants::kNotificationOperation]; | |
300 | |
301 std::string notificationOrigin = base::SysNSStringToUTF8( | |
302 [response objectForKey:notification_constants::kNotificationOrigin]); | |
303 NSString* notificationId = | |
304 [response objectForKey:notification_constants::kNotificationId]; | |
305 std::string persistentNotificationId = | |
306 base::SysNSStringToUTF8(notificationId); | |
307 std::string profileId = base::SysNSStringToUTF8( | |
308 [response objectForKey:notification_constants::kNotificationProfileId]); | |
309 NSNumber* isIncognito = | |
310 [response objectForKey:notification_constants::kNotificationIncognito]; | |
311 NSNumber* notificationType = | |
312 [response objectForKey:notification_constants::kNotificationType]; | |
313 | |
314 ProfileManager* profileManager = g_browser_process->profile_manager(); | |
315 DCHECK(profileManager); | |
316 | |
317 profileManager->LoadProfile( | |
318 profileId, [isIncognito boolValue], | |
319 base::Bind( | |
320 &ProfileLoadedCallback, static_cast<NotificationCommon::Operation>( | |
321 operation.unsignedIntValue), | |
322 static_cast<NotificationCommon::Type>( | |
323 notificationType.unsignedIntValue), | |
324 notificationOrigin, persistentNotificationId, buttonIndex.intValue)); | |
325 } | 364 } |
326 | 365 |
327 - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center | 366 - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center |
328 shouldPresentNotification:(NSUserNotification*)nsNotification { | 367 shouldPresentNotification:(NSUserNotification*)nsNotification { |
329 // Always display notifications, regardless of whether the app is foreground. | 368 // Always display notifications, regardless of whether the app is foreground. |
330 return YES; | 369 return YES; |
331 } | 370 } |
332 | 371 |
333 @end | 372 @end |
373 | |
374 @implementation NotificationRemoteDispatcher | |
375 | |
376 @synthesize xpcConnection = _xpcConnection; | |
377 | |
378 - (instancetype)init { | |
379 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
380 switches::kEnableNativeAlerts)) { | |
381 _xpcConnection = [[NSXPCConnection alloc] | |
382 initWithServiceName: | |
383 [NSString | |
384 stringWithFormat:notification_constants::kAlertXPCServiceName, | |
385 [base::mac::OuterBundle() bundleIdentifier]]]; | |
386 _xpcConnection.remoteObjectInterface = | |
387 [NSXPCInterface interfaceWithProtocol:@protocol(NotificationDelivery)]; | |
388 _xpcConnection.interruptionHandler = ^{ | |
389 NSLog(@"connection interrupted: interruptionHandler: %@", _xpcConnection); | |
390 // TODO(miguelg): perhaps add some UMA here. | |
391 // We will be getting this handler both when the XPC server crashes or | |
392 // when it decides to close the connection. | |
393 }; | |
394 _xpcConnection.invalidationHandler = ^{ | |
395 NSLog(@"conn invalidationHandler %@", _xpcConnection); | |
396 // This means that the connection should be recreated if it needs | |
397 // to be used again. It should not really happen. | |
398 DCHECK(false) << "XPC Connection invalidated"; | |
399 }; | |
400 | |
401 _xpcConnection.exportedInterface = | |
402 [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)]; | |
403 _xpcConnection.exportedObject = self; | |
404 [_xpcConnection resume]; | |
405 } | |
406 | |
407 return self; | |
408 } | |
409 | |
410 - (void)dispatchNotification:(NSDictionary*)data { | |
411 [[_xpcConnection remoteObjectProxy] deliverNotification:data]; | |
412 } | |
413 | |
414 // NotificationReply implementation | |
415 - (void)notificationClick:(NSDictionary*)notificationResponseData { | |
416 NotificationPlatformBridgeMac::ProcessNotificationResponse( | |
417 notificationResponseData); | |
418 } | |
419 | |
420 @end | |
OLD | NEW |