From 41084883cfe9206f3d2f716df387d7e79a4d2641 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 24 Dec 2015 21:55:18 +0800 Subject: [PATCH] Refactor the notification code --- brightray/browser/mac/cocoa_notification.h | 59 ++++++++ brightray/browser/mac/cocoa_notification.mm | 92 ++++++++++++ brightray/browser/mac/notification_delegate.h | 14 ++ .../browser/mac/notification_delegate.mm | 31 ++++ .../browser/mac/notification_presenter_mac.h | 31 ++++ .../browser/mac/notification_presenter_mac.mm | 48 +++++++ .../browser/notification_presenter_mac.h | 56 -------- .../browser/notification_presenter_mac.mm | 133 ------------------ brightray/filenames.gypi | 8 +- 9 files changed, 281 insertions(+), 191 deletions(-) create mode 100644 brightray/browser/mac/cocoa_notification.h create mode 100644 brightray/browser/mac/cocoa_notification.mm create mode 100644 brightray/browser/mac/notification_delegate.h create mode 100644 brightray/browser/mac/notification_delegate.mm create mode 100644 brightray/browser/mac/notification_presenter_mac.h create mode 100644 brightray/browser/mac/notification_presenter_mac.mm delete mode 100644 brightray/browser/notification_presenter_mac.h delete mode 100644 brightray/browser/notification_presenter_mac.mm diff --git a/brightray/browser/mac/cocoa_notification.h b/brightray/browser/mac/cocoa_notification.h new file mode 100644 index 000000000000..c1a54678e249 --- /dev/null +++ b/brightray/browser/mac/cocoa_notification.h @@ -0,0 +1,59 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef BROWSER_MAC_COCOA_NOTIFICATION_H_ +#define BROWSER_MAC_COCOA_NOTIFICATION_H_ + +#include + +#import + +#include "base/mac/scoped_nsobject.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "content/public/browser/desktop_notification_delegate.h" + +@class NotificationDelegate; +class SkBitmap; + +namespace brightray { + +class CocoaNotification { + public: + static CocoaNotification* FromNSNotification( + NSUserNotification* notification); + + CocoaNotification( + scoped_ptr delegate); + ~CocoaNotification(); + + void ShowNotification(const base::string16& title, + const base::string16& msg, + const SkBitmap& icon); + void DismissNotification(); + + void NotifyDisplayed(); + void NotifyClick(); + + base::WeakPtr GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + static void Cleanup(); + + scoped_ptr delegate_; + base::scoped_nsobject notification_; + + base::WeakPtrFactory weak_factory_; + + static base::scoped_nsobject notification_delegate_; + static std::set notifications_; + + DISALLOW_COPY_AND_ASSIGN(CocoaNotification); +}; + +} // namespace brightray + +#endif // BROWSER_MAC_COCOA_NOTIFICATION_H_ diff --git a/brightray/browser/mac/cocoa_notification.mm b/brightray/browser/mac/cocoa_notification.mm new file mode 100644 index 000000000000..5983cc48a08f --- /dev/null +++ b/brightray/browser/mac/cocoa_notification.mm @@ -0,0 +1,92 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "browser/mac/cocoa_notification.h" + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/mac/mac_util.h" +#include "base/stl_util.h" +#include "base/strings/sys_string_conversions.h" +#include "browser/mac/notification_delegate.h" +#include "skia/ext/skia_utils_mac.h" + +namespace brightray { + +// static +base::scoped_nsobject +CocoaNotification::notification_delegate_; + +// static +std::set CocoaNotification::notifications_; + +// static +CocoaNotification* CocoaNotification::FromNSNotification( + NSUserNotification* ns_notification) { + for (CocoaNotification* notification : notifications_) { + if ([notification->notification_ isEqual:ns_notification]) + return notification; + } + return nullptr; +} + +// static +void CocoaNotification::Cleanup() { + NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil; + notification_delegate_.reset(); + STLDeleteElements(¬ifications_); +} + +CocoaNotification::CocoaNotification( + scoped_ptr delegate) + : delegate_(delegate.Pass()), + weak_factory_(this) { + if (!notification_delegate_) { + notification_delegate_.reset([[NotificationDelegate alloc] init]); + NSUserNotificationCenter.defaultUserNotificationCenter.delegate = + notification_delegate_; + base::AtExitManager::RegisterTask(base::Bind(Cleanup)); + } + + notifications_.insert(this); +} + +CocoaNotification::~CocoaNotification() { + [NSUserNotificationCenter.defaultUserNotificationCenter + removeDeliveredNotification:notification_]; + notifications_.erase(this); +} + +void CocoaNotification::ShowNotification(const base::string16& title, + const base::string16& body, + const SkBitmap& icon) { + notification_.reset([[NSUserNotification alloc] init]); + [notification_ setTitle:base::SysUTF16ToNSString(title)]; + [notification_ setInformativeText:base::SysUTF16ToNSString(body)]; + + if ([notification_ respondsToSelector:@selector(setContentImage:)] && + !icon.drawsNothing()) { + NSImage* image = gfx::SkBitmapToNSImageWithColorSpace( + icon, base::mac::GetGenericRGBColorSpace()); + [notification_ setContentImage:image]; + } + + [NSUserNotificationCenter.defaultUserNotificationCenter + deliverNotification:notification_]; +} + +void CocoaNotification::DismissNotification() { + delete this; +} + +void CocoaNotification::NotifyDisplayed() { + delegate_->NotificationDisplayed(); +} + +void CocoaNotification::NotifyClick() { + delegate_->NotificationClick(); + delete this; +} + +} // namespace brightray diff --git a/brightray/browser/mac/notification_delegate.h b/brightray/browser/mac/notification_delegate.h new file mode 100644 index 000000000000..41acead8b117 --- /dev/null +++ b/brightray/browser/mac/notification_delegate.h @@ -0,0 +1,14 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef BROWSER_MAC_NOTIFICATION_DELEGATE_H_ +#define BROWSER_MAC_NOTIFICATION_DELEGATE_H_ + +#import + +@interface NotificationDelegate : NSObject { +} +@end + +#endif // BROWSER_MAC_NOTIFICATION_DELEGATE_H_ diff --git a/brightray/browser/mac/notification_delegate.mm b/brightray/browser/mac/notification_delegate.mm new file mode 100644 index 000000000000..6479eeb91dcc --- /dev/null +++ b/brightray/browser/mac/notification_delegate.mm @@ -0,0 +1,31 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "browser/mac/notification_delegate.h" + +#include "browser/mac/cocoa_notification.h" + +@implementation NotificationDelegate + +- (void)userNotificationCenter:(NSUserNotificationCenter*)center + didDeliverNotification:(NSUserNotification*)notif { + auto notification = brightray::CocoaNotification::FromNSNotification(notif); + if (notification) + notification->NotifyDisplayed(); +} + +- (void)userNotificationCenter:(NSUserNotificationCenter*)center + didActivateNotification:(NSUserNotification *)notif { + auto notification = brightray::CocoaNotification::FromNSNotification(notif); + if (notification) + notification->NotifyClick(); +} + +- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center + shouldPresentNotification:(NSUserNotification*)notification { + // Display notifications even if the app is active. + return YES; +} + +@end diff --git a/brightray/browser/mac/notification_presenter_mac.h b/brightray/browser/mac/notification_presenter_mac.h new file mode 100644 index 000000000000..9b2f61b7f03b --- /dev/null +++ b/brightray/browser/mac/notification_presenter_mac.h @@ -0,0 +1,31 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 Adam Roben . All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#ifndef BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_MAC_H_ +#define BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_MAC_H_ + +#include "browser/notification_presenter.h" + +namespace brightray { + +class NotificationPresenterMac : public NotificationPresenter { + public: + NotificationPresenterMac(); + ~NotificationPresenterMac(); + + // NotificationPresenter: + void ShowNotification( + const content::PlatformNotificationData&, + const SkBitmap& icon, + scoped_ptr delegate, + base::Closure* cancel_callback) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NotificationPresenterMac); +}; + +} // namespace brightray + +#endif diff --git a/brightray/browser/mac/notification_presenter_mac.mm b/brightray/browser/mac/notification_presenter_mac.mm new file mode 100644 index 000000000000..ead663bcbf86 --- /dev/null +++ b/brightray/browser/mac/notification_presenter_mac.mm @@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 Adam Roben . All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-CHROMIUM file. + +#import "browser/mac/notification_presenter_mac.h" + +#include "base/bind.h" +#include "browser/mac/cocoa_notification.h" +#include "content/public/common/platform_notification_data.h" + +namespace brightray { + +namespace { + +void RemoveNotification(base::WeakPtr notification) { + if (notification) + notification->DismissNotification(); +} + +} // namespace + +NotificationPresenter* NotificationPresenter::Create() { + return new NotificationPresenterMac; +} + +NotificationPresenterMac::NotificationPresenterMac() { +} + +NotificationPresenterMac::~NotificationPresenterMac() { +} + +void NotificationPresenterMac::ShowNotification( + const content::PlatformNotificationData& data, + const SkBitmap& icon, + scoped_ptr delegate, + base::Closure* cancel_callback) { + // This class manages itself. + auto notification = new CocoaNotification(delegate.Pass()); + notification->ShowNotification(data.title, data.body, icon); + + if (cancel_callback) { + *cancel_callback = base::Bind( + &RemoveNotification, notification->GetWeakPtr()); + } +} + +} // namespace brightray diff --git a/brightray/browser/notification_presenter_mac.h b/brightray/browser/notification_presenter_mac.h deleted file mode 100644 index 768bf2b6f1a2..000000000000 --- a/brightray/browser/notification_presenter_mac.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Copyright (c) 2013 Adam Roben . All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE-CHROMIUM file. - -#ifndef BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_MAC_H_ -#define BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_MAC_H_ - -#include "browser/notification_presenter.h" - -#include - -#import - -#include "base/mac/scoped_nsobject.h" - -@class BRYUserNotificationCenterDelegate; - -namespace brightray { - -class NotificationPresenterMac : public NotificationPresenter { - public: - NotificationPresenterMac(); - ~NotificationPresenterMac(); - - // NotificationPresenter: - void ShowNotification( - const content::PlatformNotificationData&, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) override; - - // Get the delegate accroding from the notification object. - content::DesktopNotificationDelegate* GetDelegateFromNotification( - NSUserNotification* notification); - - // Remove the notification object accroding to its delegate. - void RemoveNotification(content::DesktopNotificationDelegate* delegate); - - private: - void CancelNotification(content::DesktopNotificationDelegate* delegate); - - // The userInfo of NSUserNotification can not store pointers (because they are - // not in property list), so we have to track them in a C++ map. - // Also notice that the delegate acts as "ID" or "Key", because it is certain - // that each notification has a unique delegate. - typedef std::map> - NotificationsMap; - NotificationsMap notifications_map_; - - base::scoped_nsobject delegate_; -}; - -} // namespace brightray - -#endif diff --git a/brightray/browser/notification_presenter_mac.mm b/brightray/browser/notification_presenter_mac.mm deleted file mode 100644 index d7dfe0156634..000000000000 --- a/brightray/browser/notification_presenter_mac.mm +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Copyright (c) 2013 Adam Roben . All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE-CHROMIUM file. - -#import "browser/notification_presenter_mac.h" - -#include "base/bind.h" -#include "base/stl_util.h" -#include "base/mac/mac_util.h" -#include "base/strings/sys_string_conversions.h" -#include "content/public/common/platform_notification_data.h" -#include "content/public/browser/desktop_notification_delegate.h" -#include "skia/ext/skia_utils_mac.h" - -@interface BRYUserNotificationCenterDelegate : NSObject { - @private - brightray::NotificationPresenterMac* presenter_; -} -- (instancetype)initWithNotificationPresenter:(brightray::NotificationPresenterMac*)presenter; -@end - -namespace brightray { - -namespace { - -} // namespace - -NotificationPresenter* NotificationPresenter::Create() { - return new NotificationPresenterMac; -} - -NotificationPresenterMac::NotificationPresenterMac() - : delegate_([[BRYUserNotificationCenterDelegate alloc] initWithNotificationPresenter:this]) { - NSUserNotificationCenter.defaultUserNotificationCenter.delegate = delegate_; -} - -NotificationPresenterMac::~NotificationPresenterMac() { - NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil; -} - -void NotificationPresenterMac::ShowNotification( - const content::PlatformNotificationData& data, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) { - auto notification = [[NSUserNotification alloc] init]; - notification.title = base::SysUTF16ToNSString(data.title); - notification.informativeText = base::SysUTF16ToNSString(data.body); - - if ([notification respondsToSelector:@selector(setContentImage:)] && !icon.drawsNothing()) - notification.contentImage = gfx::SkBitmapToNSImageWithColorSpace(icon, base::mac::GetGenericRGBColorSpace()); - - notifications_map_[delegate.get()].reset(notification); - [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification]; - - if (cancel_callback) - *cancel_callback = base::Bind( - &NotificationPresenterMac::CancelNotification, - base::Unretained(this), - delegate.release()); -} - -content::DesktopNotificationDelegate* NotificationPresenterMac::GetDelegateFromNotification( - NSUserNotification* notification) { - for (NotificationsMap::const_iterator it = notifications_map_.begin(); - it != notifications_map_.end(); ++it) - if ([it->second isEqual:notification]) - return it->first; - return NULL; -} - -void NotificationPresenterMac::RemoveNotification(content::DesktopNotificationDelegate* delegate) { - if (ContainsKey(notifications_map_, delegate)) { - delete delegate; - notifications_map_.erase(delegate); - } -} - -void NotificationPresenterMac::CancelNotification(content::DesktopNotificationDelegate* delegate) { - if (!ContainsKey(notifications_map_, delegate)) - return; - - // Notifications in -deliveredNotifications aren't the same objects we passed to - // -deliverNotification:, but they will respond YES to -isEqual:. - auto notification = notifications_map_[delegate]; - auto center = NSUserNotificationCenter.defaultUserNotificationCenter; - for (NSUserNotification* deliveredNotification in center.deliveredNotifications) - if ([notification isEqual:deliveredNotification]) { - [center removeDeliveredNotification:deliveredNotification]; - delegate->NotificationClosed(); - break; - } - - RemoveNotification(delegate); -} - -} // namespace brightray - -@implementation BRYUserNotificationCenterDelegate - -- (instancetype)initWithNotificationPresenter:(brightray::NotificationPresenterMac*)presenter { - self = [super init]; - if (!self) - return nil; - - presenter_ = presenter; - return self; -} - -- (void)userNotificationCenter:(NSUserNotificationCenter*)center - didDeliverNotification:(NSUserNotification*)notification { - auto delegate = presenter_->GetDelegateFromNotification(notification); - if (delegate) - delegate->NotificationDisplayed(); -} - -- (void)userNotificationCenter:(NSUserNotificationCenter*)center - didActivateNotification:(NSUserNotification *)notification { - auto delegate = presenter_->GetDelegateFromNotification(notification); - if (delegate) { - delegate->NotificationClick(); - presenter_->RemoveNotification(delegate); - } -} - -- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center - shouldPresentNotification:(NSUserNotification*)notification { - // Display notifications even if the app is active. - return YES; -} - -@end diff --git a/brightray/filenames.gypi b/brightray/filenames.gypi index 91cb88876cce..2f7ed8d3680e 100644 --- a/brightray/filenames.gypi +++ b/brightray/filenames.gypi @@ -34,6 +34,12 @@ 'browser/mac/bry_application.mm', 'browser/mac/bry_inspectable_web_contents_view.h', 'browser/mac/bry_inspectable_web_contents_view.mm', + 'browser/mac/cocoa_notification.h', + 'browser/mac/cocoa_notification.mm', + 'browser/mac/notification_delegate.h', + 'browser/mac/notification_delegate.mm', + 'browser/mac/notification_presenter_mac.h', + 'browser/mac/notification_presenter_mac.mm', 'browser/media/media_capture_devices_dispatcher.cc', 'browser/media/media_capture_devices_dispatcher.h', 'browser/media/media_stream_devices_controller.cc', @@ -55,8 +61,6 @@ 'browser/network_delegate.cc', 'browser/network_delegate.h', 'browser/notification_presenter.h', - 'browser/notification_presenter_mac.h', - 'browser/notification_presenter_mac.mm', 'browser/permission_manager.cc', 'browser/permission_manager.h', 'browser/platform_notification_service_impl.cc',