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

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: Created 4 years, 5 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/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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698