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

Side by Side Diff: chrome/browser/notifications/notification_platform_bridge_mac.mm

Issue 2158463003: Initial client side implementation of the XPC service (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 4 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
OLDNEW
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/mac/bundle_locations.h"
9 #include "base/mac/foundation_util.h" 12 #include "base/mac/foundation_util.h"
10 #include "base/mac/mac_util.h" 13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_nsobject.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/features.h"
31 #include "chrome/grit/generated_resources.h"
25 #include "components/url_formatter/elide_url.h" 32 #include "components/url_formatter/elide_url.h"
26 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificati onConstants.h" 33 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificati onConstants.h"
34 #include "ui/base/l10n/l10n_util_mac.h"
27 #include "url/gurl.h" 35 #include "url/gurl.h"
28 #include "url/origin.h" 36 #include "url/origin.h"
29 37
30 @class NSUserNotification; 38 @class NSUserNotification;
31 @class NSUserNotificationCenter; 39 @class NSUserNotificationCenter;
32 40
33 // The mapping from web notifications to NsUserNotification works as follows 41 // The mapping from web notifications to NsUserNotification works as follows
34 42
35 // notification#title in NSUserNotification.title 43 // notification#title in NSUserNotification.title
36 // notification#message in NSUserNotification.informativeText 44 // notification#message in NSUserNotification.informativeText
(...skipping 27 matching lines...) Expand all
64 } 72 }
65 73
66 NotificationDisplayService* display_service = 74 NotificationDisplayService* display_service =
67 NotificationDisplayServiceFactory::GetForProfile(profile); 75 NotificationDisplayServiceFactory::GetForProfile(profile);
68 76
69 static_cast<NativeNotificationDisplayService*>(display_service) 77 static_cast<NativeNotificationDisplayService*>(display_service)
70 ->ProcessNotificationOperation(operation, notification_type, origin, 78 ->ProcessNotificationOperation(operation, notification_type, origin,
71 notification_id, action_index); 79 notification_id, action_index);
72 } 80 }
73 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();
92 DCHECK(profileManager);
93
94 profileManager->LoadProfile(
95 profile_id, incognito, base::Bind(&ProfileLoadedCallback, operation, type,
96 origin, notification_id, button_index));
97 }
98
74 } // namespace 99 } // namespace
75 100
76 // static 101 // static
77 NotificationPlatformBridge* NotificationPlatformBridge::Create() { 102 NotificationPlatformBridge* NotificationPlatformBridge::Create() {
78 return new NotificationPlatformBridgeMac( 103 return new NotificationPlatformBridgeMac(
79 [NSUserNotificationCenter defaultUserNotificationCenter]); 104 [NSUserNotificationCenter defaultUserNotificationCenter]);
80 } 105 }
81 106
82 // A Cocoa class that represents the delegate of NSUserNotificationCenter and 107 // A Cocoa class that represents the delegate of NSUserNotificationCenter and
83 // can forward commands to C++. 108 // can forward commands to C++.
84 @interface NotificationCenterDelegate 109 @interface NotificationCenterDelegate
85 : NSObject<NSUserNotificationCenterDelegate> { 110 : NSObject<NSUserNotificationCenterDelegate> {
86 } 111 }
87 @end 112 @end
88 113
114 // Interface to communicate with the Alert XPC service.
115 @interface NotificationRemoteDispatcher : NSObject
116
117 - (instancetype)init;
Robert Sesek 2016/09/12 15:33:47 You don't have to re-declare init if there's no ar
Miguel Garcia 2016/09/12 16:57:59 Done.
118 - (void)dispatchNotification:(NSDictionary*)data;
119
120 @end
121
89 // ///////////////////////////////////////////////////////////////////////////// 122 // /////////////////////////////////////////////////////////////////////////////
90 123
91 NotificationPlatformBridgeMac::NotificationPlatformBridgeMac( 124 NotificationPlatformBridgeMac::NotificationPlatformBridgeMac(
92 NSUserNotificationCenter* notification_center) 125 NSUserNotificationCenter* notification_center)
93 : delegate_([NotificationCenterDelegate alloc]), 126 : delegate_([NotificationCenterDelegate alloc]),
94 notification_center_(notification_center) { 127 notification_center_(notification_center),
128 notification_remote_dispatcher_(
129 [[NotificationRemoteDispatcher alloc] init]) {
95 [notification_center_ setDelegate:delegate_.get()]; 130 [notification_center_ setDelegate:delegate_.get()];
96 } 131 }
97 132
98 NotificationPlatformBridgeMac::~NotificationPlatformBridgeMac() { 133 NotificationPlatformBridgeMac::~NotificationPlatformBridgeMac() {
99 [notification_center_ setDelegate:nil]; 134 [notification_center_ setDelegate:nil];
100 135
101 // TODO(miguelg) lift this restriction if possible. 136 // TODO(miguelg) remove only alerts shown by the XPC service.
137 // TODO(miguelg) do not remove banners if possible.
102 [notification_center_ removeAllDeliveredNotifications]; 138 [notification_center_ removeAllDeliveredNotifications];
103 } 139 }
104 140
105 void NotificationPlatformBridgeMac::Display( 141 void NotificationPlatformBridgeMac::Display(
106 NotificationCommon::Type notification_type, 142 NotificationCommon::Type notification_type,
107 const std::string& notification_id, 143 const std::string& notification_id,
108 const std::string& profile_id, 144 const std::string& profile_id,
109 bool incognito, 145 bool incognito,
110 const Notification& notification) { 146 const Notification& notification) {
111 base::scoped_nsobject<NotificationBuilder> builder( 147 base::scoped_nsobject<NotificationBuilder> builder(
(...skipping 20 matching lines...) Expand all
132 NSString* buttonOne = SysUTF16ToNSString(buttons[0].title); 168 NSString* buttonOne = SysUTF16ToNSString(buttons[0].title);
133 NSString* buttonTwo = nullptr; 169 NSString* buttonTwo = nullptr;
134 if (buttons.size() > 1) 170 if (buttons.size() > 1)
135 buttonTwo = SysUTF16ToNSString(buttons[1].title); 171 buttonTwo = SysUTF16ToNSString(buttons[1].title);
136 [builder setButtons:buttonOne secondaryButton:buttonTwo]; 172 [builder setButtons:buttonOne secondaryButton:buttonTwo];
137 } 173 }
138 174
139 // Tag 175 // Tag
140 if (!notification.tag().empty()) { 176 if (!notification.tag().empty()) {
141 [builder setTag:base::SysUTF8ToNSString(notification.tag())]; 177 [builder setTag:base::SysUTF8ToNSString(notification.tag())];
178
142 // If renotify is needed, delete the notification with the same tag 179 // If renotify is needed, delete the notification with the same tag
143 // from the notification center before displaying this one. 180 // from the notification center before displaying this one.
144 // TODO(miguelg): This will need to work for alerts as well via XPC 181 // TODO(miguelg): This will need to work for alerts as well via XPC
145 // once supported. 182 // once supported.
146 if (notification.renotify()) { 183 if (notification.renotify()) {
147 NSUserNotificationCenter* notification_center = 184 NSUserNotificationCenter* notification_center =
148 [NSUserNotificationCenter defaultUserNotificationCenter]; 185 [NSUserNotificationCenter defaultUserNotificationCenter];
149 for (NSUserNotification* existing_notification in 186 for (NSUserNotification* existing_notification in
150 [notification_center deliveredNotifications]) { 187 [notification_center deliveredNotifications]) {
151 NSString* identifier = 188 NSString* identifier =
152 [existing_notification valueForKey:@"identifier"]; 189 [existing_notification valueForKey:@"identifier"];
153 if ([identifier 190 if ([identifier
154 isEqualToString:base::SysUTF8ToNSString(notification.tag())]) { 191 isEqualToString:base::SysUTF8ToNSString(notification.tag())]) {
155 [notification_center 192 [notification_center
156 removeDeliveredNotification:existing_notification]; 193 removeDeliveredNotification:existing_notification];
157 break; 194 break;
158 } 195 }
159 } 196 }
160 } 197 }
161 } 198 }
162 199
163 [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())]; 200 [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())];
164 [builder setNotificationId:base::SysUTF8ToNSString(notification_id)]; 201 [builder setNotificationId:base::SysUTF8ToNSString(notification_id)];
165 [builder setProfileId:base::SysUTF8ToNSString(profile_id)]; 202 [builder setProfileId:base::SysUTF8ToNSString(profile_id)];
166 [builder setIncognito:incognito]; 203 [builder setIncognito:incognito];
167 [builder setNotificationType:[NSNumber numberWithInteger:notification_type]]; 204 [builder setNotificationType:[NSNumber numberWithInteger:notification_type]];
168 205
206 #if BUILDFLAG(ENABLE_XPC_NOTIFICATIONS)
207 if (notification.never_timeout()) {
Robert Sesek 2016/09/12 15:33:47 This could use some commentary.
Miguel Garcia 2016/09/12 16:57:59 Done.
208 NSDictionary* dict = [builder buildDictionary];
209 [notification_remote_dispatcher_ dispatchNotification:dict];
210 } else {
211 NSUserNotification* toast = [builder buildUserNotification];
212 [notification_center_ deliverNotification:toast];
213 }
214 #else
169 NSUserNotification* toast = [builder buildUserNotification]; 215 NSUserNotification* toast = [builder buildUserNotification];
170 [notification_center_ deliverNotification:toast]; 216 [notification_center_ deliverNotification:toast];
217 #endif // ENABLE_XPC_NOTIFICATIONS
171 } 218 }
172 219
173 void NotificationPlatformBridgeMac::Close(const std::string& profile_id, 220 void NotificationPlatformBridgeMac::Close(const std::string& profile_id,
174 const std::string& notification_id) { 221 const std::string& notification_id) {
175 NSString* candidate_id = base::SysUTF8ToNSString(notification_id); 222 NSString* candidate_id = base::SysUTF8ToNSString(notification_id);
176 223
177 NSString* current_profile_id = base::SysUTF8ToNSString(profile_id); 224 NSString* current_profile_id = base::SysUTF8ToNSString(profile_id);
178 for (NSUserNotification* toast in 225 for (NSUserNotification* toast in
179 [notification_center_ deliveredNotifications]) { 226 [notification_center_ deliveredNotifications]) {
180 NSString* toast_id = 227 NSString* toast_id =
(...skipping 26 matching lines...) Expand all
207 } 254 }
208 } 255 }
209 return true; 256 return true;
210 } 257 }
211 258
212 bool NotificationPlatformBridgeMac::SupportsNotificationCenter() const { 259 bool NotificationPlatformBridgeMac::SupportsNotificationCenter() const {
213 return true; 260 return true;
214 } 261 }
215 262
216 // static 263 // static
264 void NotificationPlatformBridgeMac::ProcessNotificationResponse(
265 NSDictionary* response) {
266 if (!NotificationPlatformBridgeMac::VerifyNotificationData(response))
267 return;
268
269 NSNumber* buttonIndex =
Robert Sesek 2016/09/12 15:33:47 under_score all these names
Miguel Garcia 2016/09/12 16:57:59 Done.
270 [response objectForKey:notification_constants::kNotificationButtonIndex];
271 NSNumber* operation =
272 [response objectForKey:notification_constants::kNotificationOperation];
273
274 std::string notificationOrigin = base::SysNSStringToUTF8(
275 [response objectForKey:notification_constants::kNotificationOrigin]);
276 std::string notificationId = base::SysNSStringToUTF8(
277 [response objectForKey:notification_constants::kNotificationId]);
278 std::string profileId = base::SysNSStringToUTF8(
279 [response objectForKey:notification_constants::kNotificationProfileId]);
280 NSNumber* isIncognito =
281 [response objectForKey:notification_constants::kNotificationIncognito];
282 NSNumber* notificationType =
283 [response objectForKey:notification_constants::kNotificationType];
284
285 content::BrowserThread::PostTask(
286 content::BrowserThread::UI, FROM_HERE,
287 base::Bind(DoProcessNotificationResponse,
288 static_cast<NotificationCommon::Operation>(
289 operation.unsignedIntValue),
290 static_cast<NotificationCommon::Type>(
291 notificationType.unsignedIntValue),
292 profileId, [isIncognito boolValue], notificationOrigin,
293 notificationId, buttonIndex.intValue));
294 }
295
296 // static
217 bool NotificationPlatformBridgeMac::VerifyNotificationData( 297 bool NotificationPlatformBridgeMac::VerifyNotificationData(
218 NSDictionary* response) { 298 NSDictionary* response) {
219 if (![response 299 if (![response
220 objectForKey:notification_constants::kNotificationButtonIndex] || 300 objectForKey:notification_constants::kNotificationButtonIndex] ||
221 ![response objectForKey:notification_constants::kNotificationOperation] || 301 ![response objectForKey:notification_constants::kNotificationOperation] ||
222 ![response objectForKey:notification_constants::kNotificationId] || 302 ![response objectForKey:notification_constants::kNotificationId] ||
223 ![response objectForKey:notification_constants::kNotificationProfileId] || 303 ![response objectForKey:notification_constants::kNotificationProfileId] ||
224 ![response objectForKey:notification_constants::kNotificationIncognito] || 304 ![response objectForKey:notification_constants::kNotificationIncognito] ||
225 ![response objectForKey:notification_constants::kNotificationType]) { 305 ![response objectForKey:notification_constants::kNotificationType]) {
226 LOG(ERROR) << "Missing required key"; 306 LOG(ERROR) << "Missing required key";
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 std::string notificationOrigin = base::SysNSStringToUTF8(origin); 355 std::string notificationOrigin = base::SysNSStringToUTF8(origin);
276 GURL url(notificationOrigin); 356 GURL url(notificationOrigin);
277 if (!url.is_valid()) 357 if (!url.is_valid())
278 return false; 358 return false;
279 } 359 }
280 360
281 return true; 361 return true;
282 } 362 }
283 363
284 // ///////////////////////////////////////////////////////////////////////////// 364 // /////////////////////////////////////////////////////////////////////////////
285
286 @implementation NotificationCenterDelegate 365 @implementation NotificationCenterDelegate
287 - (void)userNotificationCenter:(NSUserNotificationCenter*)center 366 - (void)userNotificationCenter:(NSUserNotificationCenter*)center
288 didActivateNotification:(NSUserNotification*)notification { 367 didActivateNotification:(NSUserNotification*)notification {
289 NSDictionary* response = 368 NSDictionary* notification_response =
Robert Sesek 2016/09/12 15:33:47 but camelCase here ;-)
Miguel Garcia 2016/09/12 16:57:59 Done.
290 [NotificationResponseBuilder buildDictionary:notification]; 369 [NotificationResponseBuilder buildDictionary:notification];
291 if (!NotificationPlatformBridgeMac::VerifyNotificationData(response)) 370 NotificationPlatformBridgeMac::ProcessNotificationResponse(
292 return; 371 notification_response);
293
294 NSNumber* buttonIndex =
295 [response objectForKey:notification_constants::kNotificationButtonIndex];
296 NSNumber* operation =
297 [response objectForKey:notification_constants::kNotificationOperation];
298
299 std::string notificationOrigin = base::SysNSStringToUTF8(
300 [response objectForKey:notification_constants::kNotificationOrigin]);
301 NSString* notificationId =
302 [response objectForKey:notification_constants::kNotificationId];
303 std::string persistentNotificationId =
304 base::SysNSStringToUTF8(notificationId);
305 std::string profileId = base::SysNSStringToUTF8(
306 [response objectForKey:notification_constants::kNotificationProfileId]);
307 NSNumber* isIncognito =
308 [response objectForKey:notification_constants::kNotificationIncognito];
309 NSNumber* notificationType =
310 [response objectForKey:notification_constants::kNotificationType];
311
312 ProfileManager* profileManager = g_browser_process->profile_manager();
313 DCHECK(profileManager);
314
315 profileManager->LoadProfile(
316 profileId, [isIncognito boolValue],
317 base::Bind(
318 &ProfileLoadedCallback, static_cast<NotificationCommon::Operation>(
319 operation.unsignedIntValue),
320 static_cast<NotificationCommon::Type>(
321 notificationType.unsignedIntValue),
322 notificationOrigin, persistentNotificationId, buttonIndex.intValue));
323 } 372 }
324 373
325 - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center 374 - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
326 shouldPresentNotification:(NSUserNotification*)nsNotification { 375 shouldPresentNotification:(NSUserNotification*)nsNotification {
327 // Always display notifications, regardless of whether the app is foreground. 376 // Always display notifications, regardless of whether the app is foreground.
328 return YES; 377 return YES;
329 } 378 }
330 379
331 @end 380 @end
381
382 @implementation NotificationRemoteDispatcher {
383 // The connection to the XPC server in charge of delivering alerts.
384 base::scoped_nsobject<NSXPCConnection> xpcConnection_;
385 }
386
387 - (instancetype)init {
388 if ((self = [super init])) {
389 #if BUILDFLAG(ENABLE_XPC_NOTIFICATIONS)
Robert Sesek 2016/09/12 15:33:47 Why not move this #if to be around the instantiati
Miguel Garcia 2016/09/12 16:57:59 I shied away from that because the instantiation w
390 xpcConnection_.reset([[NSXPCConnection alloc]
391 initWithServiceName:
392 [NSString
393 stringWithFormat:notification_constants::kAlertXPCServiceName,
394 [base::mac::OuterBundle() bundleIdentifier]]]);
395 xpcConnection_.get().remoteObjectInterface =
396 [NSXPCInterface interfaceWithProtocol:@protocol(NotificationDelivery)];
397
398 xpcConnection_.get().interruptionHandler = ^{
399 LOG(WARNING) << "connection interrupted: interruptionHandler: ";
400 // TODO(miguelg): perhaps add some UMA here.
401 // We will be getting this handler both when the XPC server crashes or
402 // when it decides to close the connection.
403 };
404 xpcConnection_.get().invalidationHandler = ^{
405 LOG(WARNING) << "connection invalidationHandler received";
406 // This means that the connection should be recreated if it needs
407 // to be used again. It should not really happen.
408 DCHECK(false) << "XPC Connection invalidated";
409 };
410
411 xpcConnection_.get().exportedInterface =
412 [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)];
413 xpcConnection_.get().exportedObject = self;
414 [xpcConnection_ resume];
415 #endif // ENABLE_XPC_NOTIFICATIONS
416 }
417
418 return self;
419 }
420
421 - (void)dispatchNotification:(NSDictionary*)data {
422 [[xpcConnection_ remoteObjectProxy] deliverNotification:data];
423 }
424
425 // NotificationReply implementation
426 - (void)notificationClick:(NSDictionary*)notificationResponseData {
427 NotificationPlatformBridgeMac::ProcessNotificationResponse(
428 notificationResponseData);
429 }
430
431 @end
OLDNEW
« no previous file with comments | « chrome/browser/notifications/notification_platform_bridge_mac.h ('k') | chrome/browser/ui/cocoa/notifications/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698