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

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

Issue 1509923002: Implement native web notifications for mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 11 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/notifications/notification_ui_manager_mac.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/mac/foundation_util.h"
11 #include "base/mac/mac_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "chrome/browser/notifications/notification.h"
15 #include "chrome/browser/notifications/persistent_notification_delegate.h"
16 #include "chrome/browser/notifications/platform_notification_service_impl.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "url/gurl.h"
21
22 @class NSUserNotification;
23 @class NSUserNotificationCenter;
24
25 // The mapping from web notifications to NsUserNotification works as follows
26
27 // notification#title in NSUserNotification.title
28 // notification#message in NSUserNotification.subtitle
29 // notification#context_message in NSUserNotification.informativeText
30 // notification#tag in NSUserNotification.identifier (10.9)
31 // notification#icon in NSUserNotification.contentImage (10.9)
32
33 // TODO(miguelg) implement the following features
34 // - Sound names can be implemented by setting soundName in NSUserNotification
35 // NSUserNotificationDefaultSoundName gives you the platform default.
36 // - notification.requireInteraction can be implemented by removing the
37 // notification and adding it again in "notification center only mode" in
38 // the shouldPresentNotification delegate method.
39 // This also requires refactoring the popup_timer class so it does not require
40 // a notification center.
41 // - One Action can be implemented using the actionButton
42 // - more than one action is only possible in 10.10 and using a private API.
43
44 namespace {
45
46 // Keys in NSUserNotification.userInfo to map chrome notifications to
47 // native ones.
48 NSString* const kNotificationOriginKey = @"notification_origin";
49 NSString* const kNotificationPersistentIdKey = @"notification_persistent_id";
50 NSString* const kNotificationDelegateIdKey = @"notification_delegate_id";
51 NSString* const kNotificationProfileIdKey = @"notification_profile_id";
52
53 } // namespace
54
55 // static
56 NotificationUIManager*
57 NotificationUIManager::CreateNativeNotificationManager() {
58 return new NotificationUIManagerMac();
59 }
60
61 // A Cocoa class that represents the delegate of NSUserNotificationCenter and
62 // can forward commands to C++.
63 @interface NotificationCenterDelegate
64 : NSObject<NSUserNotificationCenterDelegate> {
65 @private
66 NotificationUIManagerMac* manager_; // Weak, owns self.
67 }
68 - (id)initWithManager:(NotificationUIManagerMac*)manager;
69 @end
70
71 // /////////////////////////////////////////////////////////////////////////////
72
73 NotificationUIManagerMac::NotificationUIManagerMac()
74 : delegate_([[NotificationCenterDelegate alloc] initWithManager:this]) {
75 [[NSUserNotificationCenter defaultUserNotificationCenter]
76 setDelegate:delegate_.get()];
77 }
78
79 NotificationUIManagerMac::~NotificationUIManagerMac() {
80 [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
81 CancelAll();
82 }
83
84 void NotificationUIManagerMac::Add(const Notification& notification,
85 Profile* profile) {
86 // The Mac notification UI manager only supports Web Notifications, which
87 // have a PersistentNotificationDelegate. The persistent id of the
88 // notification is exposed through it's interface.
89 PersistentNotificationDelegate* delegate =
90 static_cast<PersistentNotificationDelegate*>(notification.delegate());
91 DCHECK(delegate);
92
93 base::scoped_nsobject<NSUserNotification> toast(
94 [[NSUserNotification alloc] init]);
95 [toast setTitle:base::SysUTF16ToNSString(notification.title())];
96 [toast setSubtitle:base::SysUTF16ToNSString(notification.message())];
97
98 // TODO(miguelg): try to elide the origin perhaps See NSString
99 // stringWithFormat. It seems that the informativeText font is constant.
100 NSString* informativeText =
101 notification.context_message().empty()
102 ? base::SysUTF8ToNSString(notification.origin_url().spec())
103 : base::SysUTF16ToNSString(notification.context_message());
104 [toast setInformativeText:informativeText];
105
106 // TODO(miguelg): Implement support for buttons
107 toast.get().hasActionButton = NO;
108
109 // Some functionality is only available in 10.9+
110 // Icon
111 if ([toast respondsToSelector:@selector(setContentImage:)]) {
112 [toast setValue:notification.icon().ToNSImage() forKey:@"contentImage"];
113 }
114
115 // Tag
116 if ([toast respondsToSelector:@selector(setIdentifier:)] &&
117 !notification.tag().empty()) {
118 [toast setValue:base::SysUTF8ToNSString(notification.tag())
119 forKey:@"identifier"];
120 }
121
122 int64_t persistent_notification_id = delegate->persistent_notification_id();
123 int64_t profile_id = reinterpret_cast<int64_t>(GetProfileID(profile));
124
125 toast.get().userInfo = @{
126 kNotificationOriginKey :
127 base::SysUTF8ToNSString(notification.origin_url().spec()),
128 kNotificationPersistentIdKey :
129 [NSNumber numberWithLongLong:persistent_notification_id],
130 kNotificationDelegateIdKey :
131 base::SysUTF8ToNSString(notification.delegate_id()),
132 kNotificationProfileIdKey : [NSNumber numberWithLongLong:profile_id]
133 };
134
135 [[NSUserNotificationCenter defaultUserNotificationCenter]
136 deliverNotification:toast];
137 }
138
139 bool NotificationUIManagerMac::Update(const Notification& notification,
140 Profile* profile) {
141 NOTREACHED();
142 return false;
143 }
144
145 const Notification* NotificationUIManagerMac::FindById(
146 const std::string& delegate_id,
147 ProfileID profile_id) const {
148 NOTREACHED();
149 return nil;
150 }
151
152 bool NotificationUIManagerMac::CancelById(const std::string& delegate_id,
153 ProfileID profile_id) {
154 int64_t persistent_notification_id = 0;
155 // TODO(peter): Use the |delegate_id| directly when notification ids are being
156 // generated by content/ instead of us.
157 if (!base::StringToInt64(delegate_id, &persistent_notification_id))
158 return false;
159
160 NSUserNotificationCenter* notificationCenter =
161 [NSUserNotificationCenter defaultUserNotificationCenter];
162 for (NSUserNotification* toast in
163 [notificationCenter deliveredNotifications]) {
164 NSNumber* toast_id =
165 [toast.userInfo objectForKey:kNotificationPersistentIdKey];
166 if (toast_id.longLongValue == persistent_notification_id) {
167 [notificationCenter removeDeliveredNotification:toast];
168 return true;
169 }
170 }
171
172 return false;
173 }
174
175 std::set<std::string>
176 NotificationUIManagerMac::GetAllIdsByProfileAndSourceOrigin(
177 ProfileID profile_id,
178 const GURL& source) {
179 NOTREACHED();
180 return std::set<std::string>();
181 }
182
183 std::set<std::string> NotificationUIManagerMac::GetAllIdsByProfile(
184 ProfileID profile_id) {
185 // ProfileID in mac is not safe to use across browser restarts
186 // Therefore because when chrome quits we cancel all pending notifications.
Peter Beverloo 2016/01/08 05:14:26 Please do follow up with the profile changes you r
Miguel Garcia 2016/01/08 11:46:55 Acknowledged.
187 std::set<std::string> delegate_ids;
188 NSUserNotificationCenter* notificationCenter =
189 [NSUserNotificationCenter defaultUserNotificationCenter];
190 for (NSUserNotification* toast in
191 [notificationCenter deliveredNotifications]) {
192 NSNumber* toast_profile_id =
193 [toast.userInfo objectForKey:kNotificationProfileIdKey];
194 if (toast_profile_id.longLongValue ==
195 reinterpret_cast<int64_t>(profile_id)) {
196 delegate_ids.insert(base::SysNSStringToUTF8(
197 [toast.userInfo objectForKey:kNotificationDelegateIdKey]));
198 }
199 }
200 return delegate_ids;
201 }
202
203 bool NotificationUIManagerMac::CancelAllBySourceOrigin(
204 const GURL& source_origin) {
205 NOTREACHED();
206 return false;
207 }
208
209 bool NotificationUIManagerMac::CancelAllByProfile(ProfileID profile_id) {
210 NOTREACHED();
211 return false;
212 }
213
214 void NotificationUIManagerMac::CancelAll() {
215 [[NSUserNotificationCenter defaultUserNotificationCenter]
216 removeAllDeliveredNotifications];
217 }
218
219 // Mac notifications are only supported from 10.8 onwards.
220 bool NotificationUIManagerMac::AcceptNativeNotifications() {
221 return base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kEnableNativeNotifications) &&
223 base::mac::IsOSMountainLionOrLater();
224 }
225
226 // /////////////////////////////////////////////////////////////////////////////
227
228 @implementation NotificationCenterDelegate
229
230 - (id)initWithManager:(NotificationUIManagerMac*)manager {
231 if ((self = [super init])) {
232 DCHECK(manager);
233 manager_ = manager;
234 }
235 return self;
236 }
237
238 - (void)userNotificationCenter:(NSUserNotificationCenter*)center
239 didActivateNotification:(NSUserNotification*)notification {
240 std::string notificationOrigin = base::SysNSStringToUTF8(
241 [notification.userInfo objectForKey:kNotificationOriginKey]);
242 NSNumber* persistentNotificationId =
243 [notification.userInfo objectForKey:kNotificationPersistentIdKey];
244
245 GURL origin(notificationOrigin);
246
247 // TODO(miguelg):We cannot ship like this since we could be
248 // delivering messages to the wrong profile.
249 PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
250 ProfileManager::GetLastUsedProfile(),
251 persistentNotificationId.longLongValue, origin,
252 -1 /* buttons not yet implemented */);
253 }
254
255 - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
256 shouldPresentNotification:(NSUserNotification*)nsNotification {
257 // Always display notifications, regardless of whether the app is foreground.
258 return YES;
259 }
260
261 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698