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

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

Powered by Google App Engine
This is Rietveld 408576698