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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/notifications/notification_ui_manager_mac.mm
diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..90da4704dc03d23197df8990da50843903539710
--- /dev/null
+++ b/chrome/browser/notifications/notification_ui_manager_mac.mm
@@ -0,0 +1,261 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/notification_ui_manager_mac.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/persistent_notification_delegate.h"
+#include "chrome/browser/notifications/platform_notification_service_impl.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "url/gurl.h"
+
+@class NSUserNotification;
+@class NSUserNotificationCenter;
+
+// The mapping from web notifications to NsUserNotification works as follows
+
+// notification#title in NSUserNotification.title
+// notification#message in NSUserNotification.subtitle
+// notification#context_message in NSUserNotification.informativeText
+// notification#tag in NSUserNotification.identifier (10.9)
+// notification#icon in NSUserNotification.contentImage (10.9)
+
+// TODO(miguelg) implement the following features
+// - Sound names can be implemented by setting soundName in NSUserNotification
+// NSUserNotificationDefaultSoundName gives you the platform default.
+// - notification.requireInteraction can be implemented by removing the
+// notification and adding it again in "notification center only mode" in
+// the shouldPresentNotification delegate method.
+// This also requires refactoring the popup_timer class so it does not require
+// a notification center.
+// - One Action can be implemented using the actionButton
+// - more than one action is only possible in 10.10 and using a private API.
+
+namespace {
+
+// Keys in NSUserNotification.userInfo to map chrome notifications to
+// native ones.
+NSString* const kNotificationOriginKey = @"notification_origin";
+NSString* const kNotificationPersistentIdKey = @"notification_persistent_id";
+NSString* const kNotificationDelegateIdKey = @"notification_delegate_id";
+NSString* const kNotificationProfileIdKey = @"notification_profile_id";
+
+} // namespace
+
+// static
+NotificationUIManager*
+NotificationUIManager::CreateNativeNotificationManager() {
+ return new NotificationUIManagerMac();
+}
+
+// A Cocoa class that represents the delegate of NSUserNotificationCenter and
+// can forward commands to C++.
+@interface NotificationCenterDelegate
+ : NSObject<NSUserNotificationCenterDelegate> {
+ @private
+ NotificationUIManagerMac* manager_; // Weak, owns self.
+}
+- (id)initWithManager:(NotificationUIManagerMac*)manager;
+@end
+
+// /////////////////////////////////////////////////////////////////////////////
+
+NotificationUIManagerMac::NotificationUIManagerMac()
+ : delegate_([[NotificationCenterDelegate alloc] initWithManager:this]) {
+ [[NSUserNotificationCenter defaultUserNotificationCenter]
+ setDelegate:delegate_.get()];
+}
+
+NotificationUIManagerMac::~NotificationUIManagerMac() {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
+ CancelAll();
+}
+
+void NotificationUIManagerMac::Add(const Notification& notification,
+ Profile* profile) {
+ // The Mac notification UI manager only supports Web Notifications, which
+ // have a PersistentNotificationDelegate. The persistent id of the
+ // notification is exposed through it's interface.
+ PersistentNotificationDelegate* delegate =
+ static_cast<PersistentNotificationDelegate*>(notification.delegate());
+ DCHECK(delegate);
+
+ base::scoped_nsobject<NSUserNotification> toast(
+ [[NSUserNotification alloc] init]);
+ [toast setTitle:base::SysUTF16ToNSString(notification.title())];
+ [toast setSubtitle:base::SysUTF16ToNSString(notification.message())];
+
+ // TODO(miguelg): try to elide the origin perhaps See NSString
+ // stringWithFormat. It seems that the informativeText font is constant.
+ NSString* informativeText =
+ notification.context_message().empty()
+ ? base::SysUTF8ToNSString(notification.origin_url().spec())
+ : base::SysUTF16ToNSString(notification.context_message());
+ [toast setInformativeText:informativeText];
+
+ // TODO(miguelg): Implement support for buttons
+ toast.get().hasActionButton = NO;
+
+ // Some functionality is only available in 10.9+
+ // Icon
+ if ([toast respondsToSelector:@selector(setContentImage:)]) {
+ [toast setValue:notification.icon().ToNSImage() forKey:@"contentImage"];
+ }
+
+ // Tag
+ if ([toast respondsToSelector:@selector(setIdentifier:)] &&
+ !notification.tag().empty()) {
+ [toast setValue:base::SysUTF8ToNSString(notification.tag())
+ forKey:@"identifier"];
+ }
+
+ int64_t persistent_notification_id = delegate->persistent_notification_id();
+ int64_t profile_id = reinterpret_cast<int64_t>(GetProfileID(profile));
+
+ toast.get().userInfo = @{
+ kNotificationOriginKey :
+ base::SysUTF8ToNSString(notification.origin_url().spec()),
+ kNotificationPersistentIdKey :
+ [NSNumber numberWithLongLong:persistent_notification_id],
+ kNotificationDelegateIdKey :
+ base::SysUTF8ToNSString(notification.delegate_id()),
+ kNotificationProfileIdKey : [NSNumber numberWithLongLong:profile_id]
+ };
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter]
+ deliverNotification:toast];
+}
+
+bool NotificationUIManagerMac::Update(const Notification& notification,
+ Profile* profile) {
+ NOTREACHED();
+ return false;
+}
+
+const Notification* NotificationUIManagerMac::FindById(
+ const std::string& delegate_id,
+ ProfileID profile_id) const {
+ NOTREACHED();
+ return nil;
+}
+
+bool NotificationUIManagerMac::CancelById(const std::string& delegate_id,
+ ProfileID profile_id) {
+ int64_t persistent_notification_id = 0;
+ // TODO(peter): Use the |delegate_id| directly when notification ids are being
+ // generated by content/ instead of us.
+ if (!base::StringToInt64(delegate_id, &persistent_notification_id))
+ return false;
+
+ NSUserNotificationCenter* notificationCenter =
+ [NSUserNotificationCenter defaultUserNotificationCenter];
+ for (NSUserNotification* toast in
+ [notificationCenter deliveredNotifications]) {
+ NSNumber* toast_id =
+ [toast.userInfo objectForKey:kNotificationPersistentIdKey];
+ if (toast_id.longLongValue == persistent_notification_id) {
+ [notificationCenter removeDeliveredNotification:toast];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::set<std::string>
+NotificationUIManagerMac::GetAllIdsByProfileAndSourceOrigin(
+ ProfileID profile_id,
+ const GURL& source) {
+ NOTREACHED();
+ return std::set<std::string>();
+}
+
+std::set<std::string> NotificationUIManagerMac::GetAllIdsByProfile(
+ ProfileID profile_id) {
+ // ProfileID in mac is not safe to use across browser restarts
+ // 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.
+ std::set<std::string> delegate_ids;
+ NSUserNotificationCenter* notificationCenter =
+ [NSUserNotificationCenter defaultUserNotificationCenter];
+ for (NSUserNotification* toast in
+ [notificationCenter deliveredNotifications]) {
+ NSNumber* toast_profile_id =
+ [toast.userInfo objectForKey:kNotificationProfileIdKey];
+ if (toast_profile_id.longLongValue ==
+ reinterpret_cast<int64_t>(profile_id)) {
+ delegate_ids.insert(base::SysNSStringToUTF8(
+ [toast.userInfo objectForKey:kNotificationDelegateIdKey]));
+ }
+ }
+ return delegate_ids;
+}
+
+bool NotificationUIManagerMac::CancelAllBySourceOrigin(
+ const GURL& source_origin) {
+ NOTREACHED();
+ return false;
+}
+
+bool NotificationUIManagerMac::CancelAllByProfile(ProfileID profile_id) {
+ NOTREACHED();
+ return false;
+}
+
+void NotificationUIManagerMac::CancelAll() {
+ [[NSUserNotificationCenter defaultUserNotificationCenter]
+ removeAllDeliveredNotifications];
+}
+
+// Mac notifications are only supported from 10.8 onwards.
+bool NotificationUIManagerMac::AcceptNativeNotifications() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableNativeNotifications) &&
+ base::mac::IsOSMountainLionOrLater();
+}
+
+// /////////////////////////////////////////////////////////////////////////////
+
+@implementation NotificationCenterDelegate
+
+- (id)initWithManager:(NotificationUIManagerMac*)manager {
+ if ((self = [super init])) {
+ DCHECK(manager);
+ manager_ = manager;
+ }
+ return self;
+}
+
+- (void)userNotificationCenter:(NSUserNotificationCenter*)center
+ didActivateNotification:(NSUserNotification*)notification {
+ std::string notificationOrigin = base::SysNSStringToUTF8(
+ [notification.userInfo objectForKey:kNotificationOriginKey]);
+ NSNumber* persistentNotificationId =
+ [notification.userInfo objectForKey:kNotificationPersistentIdKey];
+
+ GURL origin(notificationOrigin);
+
+ // TODO(miguelg):We cannot ship like this since we could be
+ // delivering messages to the wrong profile.
+ PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
+ ProfileManager::GetLastUsedProfile(),
+ persistentNotificationId.longLongValue, origin,
+ -1 /* buttons not yet implemented */);
+}
+
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
+ shouldPresentNotification:(NSUserNotification*)nsNotification {
+ // Always display notifications, regardless of whether the app is foreground.
+ return YES;
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698