diff --git a/brightray/browser/browser_client.cc b/brightray/browser/browser_client.cc index 18b5fd855e..465cbce439 100644 --- a/brightray/browser/browser_client.cc +++ b/brightray/browser/browser_client.cc @@ -4,15 +4,19 @@ #include "browser/browser_client.h" +#include "base/path_service.h" #include "browser/browser_context.h" #include "browser/browser_main_parts.h" #include "browser/devtools_manager_delegate.h" #include "browser/media/media_capture_devices_dispatcher.h" -#include "browser/platform_notification_service_impl.h" - -#include "base/path_service.h" +#include "browser/notification_presenter.h" +#include "browser/platform_notification_service.h" #include "content/public/common/url_constants.h" +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif + namespace brightray { namespace { @@ -38,6 +42,20 @@ BrowserContext* BrowserClient::browser_context() { return browser_main_parts_->browser_context(); } +NotificationPresenter* BrowserClient::GetNotificationPresenter() { + #if defined(OS_WIN) + // Bail out if on Windows 7 or even lower, no operating will follow + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return nullptr; + #endif + + if (!notification_presenter_) { + // Create a new presenter if on OS X, Linux, or Windows 8+ + notification_presenter_.reset(NotificationPresenter::Create()); + } + return notification_presenter_.get(); +} + BrowserMainParts* BrowserClient::OverrideCreateBrowserMainParts( const content::MainFunctionParams&) { return new BrowserMainParts; @@ -65,7 +83,9 @@ content::MediaObserver* BrowserClient::GetMediaObserver() { } content::PlatformNotificationService* BrowserClient::GetPlatformNotificationService() { - return PlatformNotificationServiceImpl::GetInstance(); + if (!notification_service_) + notification_service_.reset(new PlatformNotificationService(this)); + return notification_service_.get(); } void BrowserClient::GetAdditionalAllowedSchemesForFileSystem( diff --git a/brightray/browser/browser_client.h b/brightray/browser/browser_client.h index 0612e56d25..bb6575c9b2 100644 --- a/brightray/browser/browser_client.h +++ b/brightray/browser/browser_client.h @@ -13,6 +13,8 @@ namespace brightray { class BrowserContext; class BrowserMainParts; class NetLog; +class NotificationPresenter; +class PlatformNotificationService; class BrowserClient : public content::ContentBrowserClient { public: @@ -24,6 +26,8 @@ class BrowserClient : public content::ContentBrowserClient { BrowserContext* browser_context(); BrowserMainParts* browser_main_parts() { return browser_main_parts_; } + NotificationPresenter* GetNotificationPresenter(); + protected: // Subclasses should override this to provide their own BrowserMainParts // implementation. The lifetime of the returned instance is managed by the @@ -51,6 +55,9 @@ class BrowserClient : public content::ContentBrowserClient { NetLog net_log_; private: + scoped_ptr notification_service_; + scoped_ptr notification_presenter_; + DISALLOW_COPY_AND_ASSIGN(BrowserClient); }; diff --git a/brightray/browser/linux/libnotify_notification.cc b/brightray/browser/linux/libnotify_notification.cc new file mode 100644 index 0000000000..98aa3ffd8a --- /dev/null +++ b/brightray/browser/linux/libnotify_notification.cc @@ -0,0 +1,157 @@ +// 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/linux/libnotify_notification.h" + +#include "base/files/file_enumerator.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "browser/notification_delegate.h" +#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" +#include "common/application_info.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace brightray { + +namespace { + +bool unity_has_result = false; +bool unity_result = false; + +bool UnityIsRunning() { + if (getenv("ELECTRON_USE_UBUNTU_NOTIFIER")) + return true; + + if (unity_has_result) + return unity_result; + + unity_has_result = true; + + // Look for the presence of libunity as our hint that we're under Ubuntu. + base::FileEnumerator enumerator(base::FilePath("/usr/lib"), + false, base::FileEnumerator::FILES); + base::FilePath haystack; + while (!((haystack = enumerator.Next()).empty())) { + if (base::StartsWith(haystack.value(), "/usr/lib/libunity-", + base::CompareCase::SENSITIVE)) { + unity_result = true; + break; + } + } + + return unity_result; +} + +void log_and_clear_error(GError* error, const char* context) { + LOG(ERROR) << context + << ": domain=" << error->domain + << " code=" << error->code + << " message=\"" << error->message << '"'; + g_error_free(error); +} + +} // namespace + +// static +Notification* Notification::Create(NotificationDelegate* delegate, + NotificationPresenter* presenter) { + return new LibnotifyNotification(delegate, presenter); +} + +// static +LibNotifyLoader LibnotifyNotification::libnotify_loader_; + +// static +bool LibnotifyNotification::Initialize() { + if (!libnotify_loader_.Load("libnotify.so.4") && + !libnotify_loader_.Load("libnotify.so.1") && + !libnotify_loader_.Load("libnotify.so")) { + return false; + } + if (!libnotify_loader_.notify_is_initted() && + !libnotify_loader_.notify_init(GetApplicationName().c_str())) { + return false; + } + return true; +} + +LibnotifyNotification::LibnotifyNotification(NotificationDelegate* delegate, + NotificationPresenter* presenter) + : Notification(delegate, presenter), + notification_(nullptr) { +} + +LibnotifyNotification::~LibnotifyNotification() { + g_object_unref(notification_); +} + +void LibnotifyNotification::Show(const base::string16& title, + const base::string16& body, + const GURL& icon_url, + const SkBitmap& icon) { + notification_ = libnotify_loader_.notify_notification_new( + base::UTF16ToUTF8(title).c_str(), + base::UTF16ToUTF8(body).c_str(), + nullptr); + + g_signal_connect( + notification_, "closed", G_CALLBACK(OnNotificationClosedThunk), this); + + // NB: On Unity, adding a notification action will cause the notification + // to display as a modal dialog box. Testing for distros that have "Unity + // Zen Nature" is difficult, we will test for the presence of the indicate + // dbus service + if (!UnityIsRunning()) { + libnotify_loader_.notify_notification_add_action( + notification_, "default", "View", OnNotificationViewThunk, this, + nullptr); + } + + if (!icon.drawsNothing()) { + GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(icon); + libnotify_loader_.notify_notification_set_image_from_pixbuf( + notification_, pixbuf); + libnotify_loader_.notify_notification_set_timeout( + notification_, NOTIFY_EXPIRES_DEFAULT); + g_object_unref(pixbuf); + } + + GError* error = nullptr; + libnotify_loader_.notify_notification_show(notification_, &error); + if (error) { + log_and_clear_error(error, "notify_notification_show"); + NotificationFailed(); + return; + } + + delegate()->NotificationDisplayed(); +} + +void LibnotifyNotification::Dismiss() { + GError* error = nullptr; + libnotify_loader_.notify_notification_close(notification_, &error); + if (error) { + log_and_clear_error(error, "notify_notification_close"); + Destroy(); + } +} + +void LibnotifyNotification::OnNotificationClosed( + NotifyNotification* notification) { + delegate()->NotificationClosed(); + Destroy(); +} + +void LibnotifyNotification::OnNotificationView( + NotifyNotification* notification, char* action) { + delegate()->NotificationClick(); + Destroy(); +} + +void LibnotifyNotification::NotificationFailed() { + delegate()->NotificationFailed(); + Destroy(); +} + +} // namespace brightray diff --git a/brightray/browser/linux/libnotify_notification.h b/brightray/browser/linux/libnotify_notification.h new file mode 100644 index 0000000000..be2f4280bc --- /dev/null +++ b/brightray/browser/linux/libnotify_notification.h @@ -0,0 +1,46 @@ +// 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_LINUX_LIBNOTIFY_NOTIFICATION_H_ +#define BROWSER_LINUX_LIBNOTIFY_NOTIFICATION_H_ + +#include "browser/linux/libnotify_loader.h" +#include "browser/notification.h" +#include "ui/base/glib/glib_signal.h" + +namespace brightray { + +class LibnotifyNotification : public Notification { + public: + LibnotifyNotification(NotificationDelegate* delegate, + NotificationPresenter* presenter); + virtual ~LibnotifyNotification(); + + static bool Initialize(); + + // Notification: + void Show(const base::string16& title, + const base::string16& msg, + const GURL& icon_url, + const SkBitmap& icon) override; + void Dismiss() override; + + private: + CHROMEG_CALLBACK_0(LibnotifyNotification, void, OnNotificationClosed, + NotifyNotification*); + CHROMEG_CALLBACK_1(LibnotifyNotification, void, OnNotificationView, + NotifyNotification*, char*); + + void NotificationFailed(); + + static LibNotifyLoader libnotify_loader_; + + NotifyNotification* notification_; + + DISALLOW_COPY_AND_ASSIGN(LibnotifyNotification); +}; + +} // namespace brightray + +#endif // BROWSER_LINUX_LIBNOTIFY_NOTIFICATION_H_ diff --git a/brightray/browser/linux/notification_presenter_linux.cc b/brightray/browser/linux/notification_presenter_linux.cc index 253ec26fe0..c846fca665 100644 --- a/brightray/browser/linux/notification_presenter_linux.cc +++ b/brightray/browser/linux/notification_presenter_linux.cc @@ -5,175 +5,21 @@ #include "browser/linux/notification_presenter_linux.h" -#include "base/bind.h" -#include "base/logging.h" -#include "base/files/file_enumerator.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "common/application_info.h" -#include "content/public/browser/desktop_notification_delegate.h" -#include "content/public/common/platform_notification_data.h" -#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" -#include "third_party/skia/include/core/SkBitmap.h" +#include "browser/linux/libnotify_notification.h" namespace brightray { -namespace { - -bool unity_has_result = false; -bool unity_result = false; - -bool UnityIsRunning() { - if (getenv("ELECTRON_USE_UBUNTU_NOTIFIER")) - return true; - - if (unity_has_result) - return unity_result; - - unity_has_result = true; - - // Look for the presence of libunity as our hint that we're under Ubuntu. - base::FileEnumerator enumerator(base::FilePath("/usr/lib"), - false, base::FileEnumerator::FILES); - base::FilePath haystack; - while (!((haystack = enumerator.Next()).empty())) { - if (base::StartsWith(haystack.value(), "/usr/lib/libunity-", base::CompareCase::SENSITIVE)) { - unity_result = true; - break; - } - } - - return unity_result; -} - -void log_and_clear_error(GError* error, const char* context) { - LOG(ERROR) << context - << ": domain=" << error->domain - << " code=" << error->code - << " message=\"" << error->message << '"'; - g_error_free(error); -} - -content::DesktopNotificationDelegate* GetDelegateFromNotification( - NotifyNotification* notification) { - return static_cast( - g_object_get_data(G_OBJECT(notification), "delegate")); -} - -} // namespace - // static NotificationPresenter* NotificationPresenter::Create() { - scoped_ptr presenter( - new NotificationPresenterLinux); - if (presenter->Init()) - return presenter.release(); - else + if (!LibnotifyNotification::Initialize()) return nullptr; + return new NotificationPresenterLinux; } -NotificationPresenterLinux::NotificationPresenterLinux() - : notifications_(nullptr) { +NotificationPresenterLinux::NotificationPresenterLinux() { } NotificationPresenterLinux::~NotificationPresenterLinux() { - // unref any outstanding notifications, and then free the list. - if (notifications_) - g_list_free_full(notifications_, g_object_unref); -} - -bool NotificationPresenterLinux::Init() { - if (!libnotify_loader_.Load("libnotify.so.4") && - !libnotify_loader_.Load("libnotify.so.1") && - !libnotify_loader_.Load("libnotify.so")) { - return false; - } - if (!libnotify_loader_.notify_is_initted() && - !libnotify_loader_.notify_init(GetApplicationName().c_str())) { - return false; - } - return true; -} - -void NotificationPresenterLinux::ShowNotification( - const content::PlatformNotificationData& data, - const SkBitmap& icon, - scoped_ptr delegate_ptr, - base::Closure* cancel_callback) { - std::string title = base::UTF16ToUTF8(data.title); - std::string body = base::UTF16ToUTF8(data.body); - NotifyNotification* notification = libnotify_loader_.notify_notification_new( - title.c_str(), body.c_str(), nullptr); - - content::DesktopNotificationDelegate* delegate = delegate_ptr.release(); - - g_object_set_data_full(G_OBJECT(notification), "delegate", delegate, operator delete); - g_signal_connect(notification, "closed", G_CALLBACK(OnNotificationClosedThunk), this); - - // NB: On Unity, adding a notification action will cause the notification - // to display as a modal dialog box. Testing for distros that have "Unity - // Zen Nature" is difficult, we will test for the presence of the indicate - // dbus service - if (!UnityIsRunning()) { - libnotify_loader_.notify_notification_add_action( - notification, "default", "View", OnNotificationViewThunk, this, nullptr); - } - - if (!icon.drawsNothing()) { - GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(icon); - libnotify_loader_.notify_notification_set_image_from_pixbuf( - notification, pixbuf); - libnotify_loader_.notify_notification_set_timeout( - notification, NOTIFY_EXPIRES_DEFAULT); - g_object_unref(pixbuf); - } - - GError* error = nullptr; - libnotify_loader_.notify_notification_show(notification, &error); - if (error) { - log_and_clear_error(error, "notify_notification_show"); - g_object_unref(notification); - return; - } - - notifications_ = g_list_append(notifications_, notification); - delegate->NotificationDisplayed(); - - if (cancel_callback) - *cancel_callback = base::Bind( - &NotificationPresenterLinux::CancelNotification, - base::Unretained(this), - notification); -} - -void NotificationPresenterLinux::CancelNotification(NotifyNotification* notification) { - GError* error = nullptr; - libnotify_loader_.notify_notification_close(notification, &error); - if (error) - log_and_clear_error(error, "notify_notification_close"); - - GetDelegateFromNotification(notification)->NotificationClosed(); - DeleteNotification(notification); -} - -void NotificationPresenterLinux::DeleteNotification(NotifyNotification* notification) { - notifications_ = g_list_remove(notifications_, notification); - g_object_unref(notification); -} - -void NotificationPresenterLinux::OnNotificationClosed(NotifyNotification* notification) { - if (!notification) - return; - GetDelegateFromNotification(notification)->NotificationClosed(); - DeleteNotification(notification); -} - -void NotificationPresenterLinux::OnNotificationView( - NotifyNotification* notification, char* action) { - if (!notification) - return; - GetDelegateFromNotification(notification)->NotificationClick(); - DeleteNotification(notification); } } // namespace brightray diff --git a/brightray/browser/linux/notification_presenter_linux.h b/brightray/browser/linux/notification_presenter_linux.h index d70d1c468a..ef43679948 100644 --- a/brightray/browser/linux/notification_presenter_linux.h +++ b/brightray/browser/linux/notification_presenter_linux.h @@ -6,12 +6,7 @@ #ifndef BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_LINUX_H_ #define BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_LINUX_H_ -#include - -#include "base/compiler_specific.h" -#include "browser/linux/libnotify_loader.h" #include "browser/notification_presenter.h" -#include "ui/base/glib/glib_signal.h" namespace brightray { @@ -20,34 +15,8 @@ class NotificationPresenterLinux : public NotificationPresenter { NotificationPresenterLinux(); ~NotificationPresenterLinux(); - bool Init(); - void RemoveNotification(NotifyNotification *notification); - private: - // NotificationPresenter: - void ShowNotification( - const content::PlatformNotificationData&, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) override; - - void CancelNotification(NotifyNotification* notification); - void DeleteNotification(NotifyNotification* notification); - - CHROMEG_CALLBACK_0(NotificationPresenterLinux, void, OnNotificationClosed, NotifyNotification*); - CHROMEG_CALLBACK_1(NotificationPresenterLinux, void, OnNotificationView, NotifyNotification*, - char*); - - LibNotifyLoader libnotify_loader_; - - // A list of all open NotifyNotification objects. - // We do lookups here both by NotifyNotification object (when the user - // clicks a notification) and by the ID - // tuple (when the browser asks to dismiss a notification). So it's not - // a map. - // Entries in this list count as refs, so removal from this list should - // always go with g_object_unref(). - GList* notifications_; + DISALLOW_COPY_AND_ASSIGN(NotificationPresenterLinux); }; } // namespace brightray diff --git a/brightray/browser/mac/cocoa_notification.h b/brightray/browser/mac/cocoa_notification.h new file mode 100644 index 0000000000..b170956821 --- /dev/null +++ b/brightray/browser/mac/cocoa_notification.h @@ -0,0 +1,42 @@ +// 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_ + +#import + +#include "base/mac/scoped_nsobject.h" +#include "base/memory/scoped_ptr.h" +#include "browser/notification.h" + +namespace brightray { + +class CocoaNotification : public Notification { + public: + CocoaNotification(NotificationDelegate* delegate, + NotificationPresenter* presenter); + ~CocoaNotification(); + + // Notification: + void Show(const base::string16& title, + const base::string16& msg, + const GURL& icon_url, + const SkBitmap& icon) override; + void Dismiss() override; + + void NotifyDisplayed(); + void NotifyClick(); + + NSUserNotification* notification() const { return notification_; } + + private: + base::scoped_nsobject notification_; + + 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 0000000000..24174e226a --- /dev/null +++ b/brightray/browser/mac/cocoa_notification.mm @@ -0,0 +1,66 @@ +// 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/mac/mac_util.h" +#include "base/strings/sys_string_conversions.h" +#include "browser/notification_delegate.h" +#include "browser/notification_presenter.h" +#include "skia/ext/skia_utils_mac.h" + +namespace brightray { + +// static +Notification* Notification::Create(NotificationDelegate* delegate, + NotificationPresenter* presenter) { + return new CocoaNotification(delegate, presenter); +} + +CocoaNotification::CocoaNotification(NotificationDelegate* delegate, + NotificationPresenter* presenter) + : Notification(delegate, presenter) { +} + +CocoaNotification::~CocoaNotification() { + [NSUserNotificationCenter.defaultUserNotificationCenter + removeDeliveredNotification:notification_]; +} + +void CocoaNotification::Show(const base::string16& title, + const base::string16& body, + const GURL& icon_url, + 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::Dismiss() { + [NSUserNotificationCenter.defaultUserNotificationCenter + removeDeliveredNotification:notification_]; + delegate()->NotificationClosed(); + Destroy(); +} + +void CocoaNotification::NotifyDisplayed() { + delegate()->NotificationDisplayed(); +} + +void CocoaNotification::NotifyClick() { + delegate()->NotificationClick(); + Destroy(); +} + +} // namespace brightray diff --git a/brightray/browser/mac/notification_center_delegate.h b/brightray/browser/mac/notification_center_delegate.h new file mode 100644 index 0000000000..6bee83d411 --- /dev/null +++ b/brightray/browser/mac/notification_center_delegate.h @@ -0,0 +1,22 @@ +// 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 + +namespace brightray { +class NotificationPresenterMac; +} + +@interface NotificationCenterDelegate : + NSObject { + @private + brightray::NotificationPresenterMac* presenter_; +} +- (instancetype)initWithPresenter:(brightray::NotificationPresenterMac*)presenter; +@end + +#endif // BROWSER_MAC_NOTIFICATION_DELEGATE_H_ diff --git a/brightray/browser/mac/notification_center_delegate.mm b/brightray/browser/mac/notification_center_delegate.mm new file mode 100644 index 0000000000..53537bdc31 --- /dev/null +++ b/brightray/browser/mac/notification_center_delegate.mm @@ -0,0 +1,41 @@ +// 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_center_delegate.h" + +#include "browser/mac/cocoa_notification.h" +#include "browser/mac/notification_presenter_mac.h" + +@implementation NotificationCenterDelegate + +- (instancetype)initWithPresenter:(brightray::NotificationPresenterMac*)presenter { + self = [super init]; + if (!self) + return nil; + + presenter_ = presenter; + return self; +} + +- (void)userNotificationCenter:(NSUserNotificationCenter*)center + didDeliverNotification:(NSUserNotification*)notif { + auto notification = presenter_->GetNotification(notif); + if (notification) + notification->NotifyDisplayed(); +} + +- (void)userNotificationCenter:(NSUserNotificationCenter*)center + didActivateNotification:(NSUserNotification *)notif { + auto notification = presenter_->GetNotification(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 0000000000..825a1dada2 --- /dev/null +++ b/brightray/browser/mac/notification_presenter_mac.h @@ -0,0 +1,33 @@ +// 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 "base/mac/scoped_nsobject.h" +#include "browser/mac/notification_center_delegate.h" +#include "browser/notification_presenter.h" + +namespace brightray { + +class CocoaNotification; + +class NotificationPresenterMac : public NotificationPresenter { + public: + CocoaNotification* GetNotification(NSUserNotification* notif); + + NotificationPresenterMac(); + ~NotificationPresenterMac(); + + private: + base::scoped_nsobject + notification_center_delegate_; + + 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 0000000000..a37e9182fc --- /dev/null +++ b/brightray/browser/mac/notification_presenter_mac.mm @@ -0,0 +1,38 @@ +// 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_presenter_mac.h" + +#include "browser/mac/cocoa_notification.h" +#include "browser/mac/notification_center_delegate.h" + +namespace brightray { + +// static +NotificationPresenter* NotificationPresenter::Create() { + return new NotificationPresenterMac; +} + +CocoaNotification* NotificationPresenterMac::GetNotification( + NSUserNotification* ns_notification) { + for (Notification* notification : notifications()) { + auto native_notification = static_cast(notification); + if ([native_notification->notification() isEqual:ns_notification]) + return native_notification; + } + return nullptr; +} + +NotificationPresenterMac::NotificationPresenterMac() + : notification_center_delegate_( + [[NotificationCenterDelegate alloc] initWithPresenter:this]) { + NSUserNotificationCenter.defaultUserNotificationCenter.delegate = + notification_center_delegate_; +} + +NotificationPresenterMac::~NotificationPresenterMac() { + NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil; +} + +} // namespace brightray diff --git a/brightray/browser/notification.cc b/brightray/browser/notification.cc new file mode 100644 index 0000000000..6384737c21 --- /dev/null +++ b/brightray/browser/notification.cc @@ -0,0 +1,27 @@ +// 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/notification.h" + +#include "browser/notification_delegate.h" +#include "browser/notification_presenter.h" + +namespace brightray { + +Notification::Notification(NotificationDelegate* delegate, + NotificationPresenter* presenter) + : delegate_(delegate), + presenter_(presenter), + weak_factory_(this) { +} + +Notification::~Notification() { + delegate()->NotificationDestroyed(); +} + +void Notification::Destroy() { + presenter()->RemoveNotification(this); +} + +} // namespace brightray diff --git a/brightray/browser/notification.h b/brightray/browser/notification.h new file mode 100644 index 0000000000..9d0deccbf4 --- /dev/null +++ b/brightray/browser/notification.h @@ -0,0 +1,63 @@ +// 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_NOTIFICATION_H_ +#define BROWSER_NOTIFICATION_H_ + +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" + +class GURL; +class SkBitmap; + +namespace brightray { + +class NotificationDelegate; +class NotificationPresenter; + +class Notification { + public: + // Shows the notification. + virtual void Show(const base::string16& title, + const base::string16& msg, + const GURL& icon_url, + const SkBitmap& icon) = 0; + // Closes the notification, this instance will be destroyed after the + // notification gets closed. + virtual void Dismiss() = 0; + + base::WeakPtr GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + NotificationDelegate* delegate() const { return delegate_; } + NotificationPresenter* presenter() const { return presenter_; } + + protected: + Notification(NotificationDelegate* delegate, + NotificationPresenter* presenter); + virtual ~Notification(); + + // delete this. + void Destroy(); + + private: + friend class NotificationPresenter; + + // Can only be called by NotificationPresenter, the caller is responsible of + // freeing the returned instance. + static Notification* Create(NotificationDelegate* delegate, + NotificationPresenter* presenter); + + NotificationDelegate* delegate_; + NotificationPresenter* presenter_; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(Notification); +}; + +} // namespace brightray + +#endif // BROWSER_NOTIFICATION_H_ diff --git a/brightray/browser/notification_delegate.h b/brightray/browser/notification_delegate.h new file mode 100644 index 0000000000..93512f7175 --- /dev/null +++ b/brightray/browser/notification_delegate.h @@ -0,0 +1,23 @@ +// 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_NOTIFICATION_DELEGATE_H_ +#define BROWSER_NOTIFICATION_DELEGATE_H_ + +#include "content/public/browser/desktop_notification_delegate.h" + +namespace brightray { + +class NotificationDelegate : public content::DesktopNotificationDelegate { + public: + // The native Notification object is destroyed. + virtual void NotificationDestroyed() {} + + // Failed to send the notification. + virtual void NotificationFailed() {} +}; + +} // namespace brightray + +#endif // BROWSER_NOTIFICATION_DELEGATE_H_ diff --git a/brightray/browser/notification_delegate_adapter.cc b/brightray/browser/notification_delegate_adapter.cc new file mode 100644 index 0000000000..da9a70aab3 --- /dev/null +++ b/brightray/browser/notification_delegate_adapter.cc @@ -0,0 +1,33 @@ +// 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/notification_delegate_adapter.h" + +namespace brightray { + +NotificationDelegateAdapter::NotificationDelegateAdapter( + scoped_ptr delegate) + : delegate_(delegate.Pass()) { +} + +NotificationDelegateAdapter::~NotificationDelegateAdapter() { +} + +void NotificationDelegateAdapter::NotificationDestroyed() { + delete this; +} + +void NotificationDelegateAdapter::NotificationDisplayed() { + delegate_->NotificationDisplayed(); +} + +void NotificationDelegateAdapter::NotificationClosed() { + delegate_->NotificationClosed(); +} + +void NotificationDelegateAdapter::NotificationClick() { + delegate_->NotificationClick(); +} + +} // namespace brightray diff --git a/brightray/browser/notification_delegate_adapter.h b/brightray/browser/notification_delegate_adapter.h new file mode 100644 index 0000000000..b48c7376cb --- /dev/null +++ b/brightray/browser/notification_delegate_adapter.h @@ -0,0 +1,36 @@ +// 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_NOTIFICATION_DELEGATE_ADAPTER_H_ +#define BROWSER_NOTIFICATION_DELEGATE_ADAPTER_H_ + +#include "base/memory/scoped_ptr.h" +#include "browser/notification_delegate.h" + +namespace brightray { + +// Adapt the content::DesktopNotificationDelegate to NotificationDelegate. +class NotificationDelegateAdapter : public NotificationDelegate { + public: + explicit NotificationDelegateAdapter( + scoped_ptr delegate); + ~NotificationDelegateAdapter() override; + + // NotificationDelegate: + void NotificationDestroyed() override; + + // content::DesktopNotificationDelegate: + void NotificationDisplayed() override; + void NotificationClosed() override; + void NotificationClick() override; + + private: + scoped_ptr delegate_; + + DISALLOW_COPY_AND_ASSIGN(NotificationDelegateAdapter); +}; + +} // namespace brightray + +#endif // BROWSER_NOTIFICATION_DELEGATE_ADAPTER_H_ diff --git a/brightray/browser/notification_presenter.cc b/brightray/browser/notification_presenter.cc new file mode 100644 index 0000000000..ad46e292a2 --- /dev/null +++ b/brightray/browser/notification_presenter.cc @@ -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/notification_presenter.h" + +#include "browser/notification.h" + +namespace brightray { + +NotificationPresenter::NotificationPresenter() { +} + +NotificationPresenter::~NotificationPresenter() { + for (Notification* notification : notifications_) + delete notification; +} + +base::WeakPtr NotificationPresenter::CreateNotification( + NotificationDelegate* delegate) { + Notification* notification = Notification::Create(delegate, this); + notifications_.insert(notification); + return notification->GetWeakPtr(); +} + +void NotificationPresenter::RemoveNotification(Notification* notification) { + notifications_.erase(notification); + delete notification; +} + +} // namespace brightray diff --git a/brightray/browser/notification_presenter.h b/brightray/browser/notification_presenter.h index 6c1a66fc59..b3dac3005d 100644 --- a/brightray/browser/notification_presenter.h +++ b/brightray/browser/notification_presenter.h @@ -1,29 +1,41 @@ +// 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 BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_H_ #define BRIGHTRAY_BROWSER_NOTIFICATION_PRESENTER_H_ -#include "base/callback_forward.h" -#include "base/memory/scoped_ptr.h" +#include -class SkBitmap; - -namespace content { -class DesktopNotificationDelegate; -struct PlatformNotificationData; -} +#include "base/memory/weak_ptr.h" namespace brightray { +class Notification; +class NotificationDelegate; + class NotificationPresenter { public: - virtual ~NotificationPresenter() {} - static NotificationPresenter* Create(); - virtual void ShowNotification( - const content::PlatformNotificationData&, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) = 0; + virtual ~NotificationPresenter(); + + base::WeakPtr CreateNotification( + NotificationDelegate* delegate); + + std::set notifications() const { return notifications_; } + + protected: + NotificationPresenter(); + + private: + friend class Notification; + + void RemoveNotification(Notification* notification); + + std::set notifications_; + + DISALLOW_COPY_AND_ASSIGN(NotificationPresenter); }; } // namespace brightray diff --git a/brightray/browser/notification_presenter_mac.h b/brightray/browser/notification_presenter_mac.h deleted file mode 100644 index 768bf2b6f1..0000000000 --- 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 d7dfe01566..0000000000 --- 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/browser/platform_notification_service.cc b/brightray/browser/platform_notification_service.cc new file mode 100644 index 0000000000..7d91ce5f2e --- /dev/null +++ b/brightray/browser/platform_notification_service.cc @@ -0,0 +1,84 @@ +// Copyright (c) 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-CHROMIUM file. + +#include "browser/platform_notification_service.h" + +#include "browser/browser_client.h" +#include "browser/notification.h" +#include "browser/notification_delegate_adapter.h" +#include "browser/notification_presenter.h" +#include "content/public/common/platform_notification_data.h" + +namespace brightray { + +namespace { + +void RemoveNotification(base::WeakPtr notification) { + if (notification) + notification->Dismiss(); +} + +} // namespace + +PlatformNotificationService::PlatformNotificationService( + BrowserClient* browser_client) + : browser_client_(browser_client) { +} + +PlatformNotificationService::~PlatformNotificationService() {} + +blink::WebNotificationPermission PlatformNotificationService::CheckPermissionOnUIThread( + content::BrowserContext* browser_context, + const GURL& origin, + int render_process_id) { + return blink::WebNotificationPermissionAllowed; +} + +blink::WebNotificationPermission PlatformNotificationService::CheckPermissionOnIOThread( + content::ResourceContext* resource_context, + const GURL& origin, + int render_process_id) { + return blink::WebNotificationPermissionAllowed; +} + +void PlatformNotificationService::DisplayNotification( + content::BrowserContext* browser_context, + const GURL& origin, + const SkBitmap& icon, + const content::PlatformNotificationData& data, + scoped_ptr delegate, + base::Closure* cancel_callback) { + auto presenter = browser_client_->GetNotificationPresenter(); + if (!presenter) + return; + scoped_ptr adapter( + new NotificationDelegateAdapter(delegate.Pass())); + auto notification = presenter->CreateNotification(adapter.get()); + if (notification) { + ignore_result(adapter.release()); // it will release itself automatically. + notification->Show(data.title, data.body, data.icon, icon); + *cancel_callback = base::Bind(&RemoveNotification, notification); + } +} + +void PlatformNotificationService::DisplayPersistentNotification( + content::BrowserContext* browser_context, + int64_t service_worker_registration_id, + const GURL& origin, + const SkBitmap& icon, + const content::PlatformNotificationData& notification_data) { +} + +void PlatformNotificationService::ClosePersistentNotification( + content::BrowserContext* browser_context, + int64_t persistent_notification_id) { +} + +bool PlatformNotificationService::GetDisplayedPersistentNotifications( + content::BrowserContext* browser_context, + std::set* displayed_notifications) { + return false; +} + +} // namespace brightray diff --git a/brightray/browser/platform_notification_service_impl.h b/brightray/browser/platform_notification_service.h similarity index 67% rename from brightray/browser/platform_notification_service_impl.h rename to brightray/browser/platform_notification_service.h index 9b657d5395..0c598965df 100644 --- a/brightray/browser/platform_notification_service_impl.h +++ b/brightray/browser/platform_notification_service.h @@ -2,31 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-CHROMIUM file. -#ifndef BROWSER_PLATFORM_NOTIFICATION_SERVICE_IMPL_H_ -#define BROWSER_PLATFORM_NOTIFICATION_SERVICE_IMPL_H_ +#ifndef BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_ +#define BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_ -#include "base/memory/singleton.h" #include "content/public/browser/platform_notification_service.h" namespace brightray { -class NotificationPresenter; +class BrowserClient; -class PlatformNotificationServiceImpl +class PlatformNotificationService : public content::PlatformNotificationService { public: - // Returns the active instance of the service in the browser process. Safe to - // be called from any thread. - static PlatformNotificationServiceImpl* GetInstance(); - - NotificationPresenter* notification_presenter(); - - private: - friend struct base::DefaultSingletonTraits; - - PlatformNotificationServiceImpl(); - ~PlatformNotificationServiceImpl() override; + explicit PlatformNotificationService(BrowserClient* browser_client); + ~PlatformNotificationService() override; + protected: // content::PlatformNotificationService: blink::WebNotificationPermission CheckPermissionOnUIThread( content::BrowserContext* browser_context, @@ -56,11 +47,12 @@ class PlatformNotificationServiceImpl content::BrowserContext* browser_context, std::set* displayed_notifications) override; - scoped_ptr notification_presenter_; + private: + BrowserClient* browser_client_; - DISALLOW_COPY_AND_ASSIGN(PlatformNotificationServiceImpl); + DISALLOW_COPY_AND_ASSIGN(PlatformNotificationService); }; } // namespace brightray -#endif // BROWSER_PLATFORM_NOTIFICATION_SERVICE_IMPL_H_ +#endif // BROWSER_PLATFORM_NOTIFICATION_SERVICE_H_ diff --git a/brightray/browser/platform_notification_service_impl.cc b/brightray/browser/platform_notification_service_impl.cc deleted file mode 100644 index 98c41b3bae..0000000000 --- a/brightray/browser/platform_notification_service_impl.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 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-CHROMIUM file. - -#include "browser/platform_notification_service_impl.h" - -#include "browser/notification_presenter.h" - -#include "content/public/browser/desktop_notification_delegate.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - -namespace brightray { - -// static -PlatformNotificationServiceImpl* -PlatformNotificationServiceImpl::GetInstance() { - return base::Singleton::get(); -} - -PlatformNotificationServiceImpl::PlatformNotificationServiceImpl() {} -PlatformNotificationServiceImpl::~PlatformNotificationServiceImpl() {} - -NotificationPresenter* PlatformNotificationServiceImpl::notification_presenter() { - #if defined(OS_WIN) - // Bail out if on Windows 7 or even lower, no operating will follow - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return nullptr; - #endif - - if (!notification_presenter_) { - // Create a new presenter if on OS X, Linux, or Windows 8+ - notification_presenter_.reset(NotificationPresenter::Create()); - } - return notification_presenter_.get(); -} - -blink::WebNotificationPermission PlatformNotificationServiceImpl::CheckPermissionOnUIThread( - content::BrowserContext* browser_context, - const GURL& origin, - int render_process_id) { - return blink::WebNotificationPermissionAllowed; -} - -blink::WebNotificationPermission PlatformNotificationServiceImpl::CheckPermissionOnIOThread( - content::ResourceContext* resource_context, - const GURL& origin, - int render_process_id) { - return blink::WebNotificationPermissionAllowed; -} - -void PlatformNotificationServiceImpl::DisplayNotification( - content::BrowserContext* browser_context, - const GURL& origin, - const SkBitmap& icon, - const content::PlatformNotificationData& notification_data, - scoped_ptr delegate, - base::Closure* cancel_callback) { - auto presenter = notification_presenter(); - if (presenter) - presenter->ShowNotification(notification_data, icon, delegate.Pass(), cancel_callback); -} - -void PlatformNotificationServiceImpl::DisplayPersistentNotification( - content::BrowserContext* browser_context, - int64_t service_worker_registration_id, - const GURL& origin, - const SkBitmap& icon, - const content::PlatformNotificationData& notification_data) { -} - -void PlatformNotificationServiceImpl::ClosePersistentNotification( - content::BrowserContext* browser_context, - int64_t persistent_notification_id) { -} - -bool PlatformNotificationServiceImpl::GetDisplayedPersistentNotifications( - content::BrowserContext* browser_context, - std::set* displayed_notifications) { - return false; -} - -} // namespace brightray diff --git a/brightray/browser/win/notification_presenter_win.cc b/brightray/browser/win/notification_presenter_win.cc index 29534d94be..d3d4f7dc24 100644 --- a/brightray/browser/win/notification_presenter_win.cc +++ b/brightray/browser/win/notification_presenter_win.cc @@ -31,11 +31,6 @@ bool SaveIconToPath(const SkBitmap& bitmap, const base::FilePath& path) { return base::WriteFile(path, data, size) == size; } -void RemoveNotification(base::WeakPtr notification) { - if (notification) - notification->DismissNotification(); -} - } // namespace // static @@ -58,23 +53,7 @@ bool NotificationPresenterWin::Init() { return temp_dir_.CreateUniqueTempDir(); } -void NotificationPresenterWin::ShowNotification( - const content::PlatformNotificationData& data, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) { - // This class manages itself. - auto notification = new WindowsToastNotification(delegate.Pass()); - notification->ShowNotification( - data.title, data.body, SaveIconToFilesystem(icon, data.icon)); - - if (cancel_callback) { - *cancel_callback = base::Bind( - &RemoveNotification, notification->GetWeakPtr()); - } -} - -std::wstring NotificationPresenterWin::SaveIconToFilesystem( +base::string16 NotificationPresenterWin::SaveIconToFilesystem( const SkBitmap& icon, const GURL& origin) { std::string filename = base::MD5String(origin.spec()) + ".png"; base::FilePath path = temp_dir_.path().Append(base::UTF8ToUTF16(filename)); diff --git a/brightray/browser/win/notification_presenter_win.h b/brightray/browser/win/notification_presenter_win.h index 21152c9cab..7bcf1a9909 100644 --- a/brightray/browser/win/notification_presenter_win.h +++ b/brightray/browser/win/notification_presenter_win.h @@ -16,12 +16,12 @@ #ifndef BRIGHTRAY_BROWSER_WIN_NOTIFICATION_PRESENTER_WIN_H_ #define BRIGHTRAY_BROWSER_WIN_NOTIFICATION_PRESENTER_WIN_H_ -#include - #include "base/files/scoped_temp_dir.h" +#include "base/strings/string16.h" #include "browser/notification_presenter.h" class GURL; +class SkBitmap; namespace brightray { @@ -32,15 +32,9 @@ class NotificationPresenterWin : public NotificationPresenter { bool Init(); - void ShowNotification( - const content::PlatformNotificationData&, - const SkBitmap& icon, - scoped_ptr delegate, - base::Closure* cancel_callback) override; + base::string16 SaveIconToFilesystem(const SkBitmap& icon, const GURL& origin); private: - std::wstring SaveIconToFilesystem(const SkBitmap& icon, const GURL& origin); - base::ScopedTempDir temp_dir_; DISALLOW_COPY_AND_ASSIGN(NotificationPresenterWin); diff --git a/brightray/browser/win/windows_toast_notification.cc b/brightray/browser/win/windows_toast_notification.cc index f2d77edf67..d08b888e4a 100644 --- a/brightray/browser/win/windows_toast_notification.cc +++ b/brightray/browser/win/windows_toast_notification.cc @@ -8,9 +8,10 @@ #include #include "base/strings/utf_string_conversions.h" +#include "browser/notification_delegate.h" #include "browser/win/scoped_hstring.h" +#include "browser/win/notification_presenter_win.h" #include "common/application_info.h" -#include "content/public/browser/desktop_notification_delegate.h" using namespace ABI::Windows::Data::Xml::Dom; @@ -31,6 +32,12 @@ bool GetAppUserModelId(ScopedHString* app_id) { } // namespace +// static +Notification* Notification::Create(NotificationDelegate* delegate, + NotificationPresenter* presenter) { + return new WindowsToastNotification(delegate, presenter); +} + // static ComPtr WindowsToastNotification::toast_manager_; @@ -61,61 +68,83 @@ bool WindowsToastNotification::Initialize() { } WindowsToastNotification::WindowsToastNotification( - scoped_ptr delegate) - : delegate_(delegate.Pass()), - weak_factory_(this) { + NotificationDelegate* delegate, + NotificationPresenter* presenter) + : Notification(delegate, presenter) { } WindowsToastNotification::~WindowsToastNotification() { + // Remove the notification on exit. + if (toast_notification_) { + RemoveCallbacks(toast_notification_.Get()); + Dismiss(); + } } -void WindowsToastNotification::ShowNotification( - const std::wstring& title, - const std::wstring& msg, - const std::wstring& icon_path) { +void WindowsToastNotification::Show( + const base::string16& title, + const base::string16& msg, + const GURL& icon_url, + const SkBitmap& icon) { + auto presenter_win = static_cast(presenter()); + std::wstring icon_path = presenter_win->SaveIconToFilesystem(icon, icon_url); + ComPtr toast_xml; - if(FAILED(GetToastXml(toast_manager_.Get(), title, msg, icon_path, &toast_xml))) + if(FAILED(GetToastXml(toast_manager_.Get(), title, msg, icon_path, &toast_xml))) { + NotificationFailed(); return; + } ScopedHString toast_str( RuntimeClass_Windows_UI_Notifications_ToastNotification); - if (!toast_str.success()) + if (!toast_str.success()) { + NotificationFailed(); return; + } ComPtr toast_factory; if (FAILED(Windows::Foundation::GetActivationFactory(toast_str, - &toast_factory))) + &toast_factory))) { + NotificationFailed(); return; + } if (FAILED(toast_factory->CreateToastNotification(toast_xml.Get(), - &toast_notification_))) + &toast_notification_))) { + NotificationFailed(); return; + } - if (FAILED(SetupCallbacks(toast_notification_.Get()))) + if (FAILED(SetupCallbacks(toast_notification_.Get()))) { + NotificationFailed(); return; + } - if (FAILED(toast_notifier_->Show(toast_notification_.Get()))) + if (FAILED(toast_notifier_->Show(toast_notification_.Get()))) { + NotificationFailed(); return; + } - delegate_->NotificationDisplayed(); + delegate()->NotificationDisplayed(); } -void WindowsToastNotification::DismissNotification() { +void WindowsToastNotification::Dismiss() { toast_notifier_->Hide(toast_notification_.Get()); } void WindowsToastNotification::NotificationClicked() { - delegate_->NotificationClick(); - delete this; + delegate()->NotificationClick(); + Destroy(); } void WindowsToastNotification::NotificationDismissed() { - delegate_->NotificationClosed(); - delete this; + delegate()->NotificationClosed(); + Destroy(); } void WindowsToastNotification::NotificationFailed() { - delete this; + delegate()->NotificationFailed(); + Destroy(); } bool WindowsToastNotification::GetToastXml( @@ -263,16 +292,27 @@ bool WindowsToastNotification::AppendTextToXml( return SUCCEEDED(node->AppendChild(text_node.Get(), &append_node)); } -bool WindowsToastNotification::SetupCallbacks(ABI::Windows::UI::Notifications::IToastNotification* toast) { - EventRegistrationToken activatedToken, dismissedToken, failedToken; +bool WindowsToastNotification::SetupCallbacks( + ABI::Windows::UI::Notifications::IToastNotification* toast) { event_handler_ = Make(this); - if (FAILED(toast->add_Activated(event_handler_.Get(), &activatedToken))) + if (FAILED(toast->add_Activated(event_handler_.Get(), &activated_token_))) return false; - if (FAILED(toast->add_Dismissed(event_handler_.Get(), &dismissedToken))) + if (FAILED(toast->add_Dismissed(event_handler_.Get(), &dismissed_token_))) return false; - return SUCCEEDED(toast->add_Failed(event_handler_.Get(), &failedToken)); + return SUCCEEDED(toast->add_Failed(event_handler_.Get(), &failed_token_)); +} + +bool WindowsToastNotification::RemoveCallbacks( + ABI::Windows::UI::Notifications::IToastNotification* toast) { + if (FAILED(toast->remove_Activated(activated_token_))) + return false; + + if (FAILED(toast->remove_Dismissed(dismissed_token_))) + return false; + + return SUCCEEDED(toast->remove_Failed(failed_token_)); } /* diff --git a/brightray/browser/win/windows_toast_notification.h b/brightray/browser/win/windows_toast_notification.h index a5c0a3d1d2..02e0566699 100644 --- a/brightray/browser/win/windows_toast_notification.h +++ b/brightray/browser/win/windows_toast_notification.h @@ -10,10 +10,7 @@ #include #include -#include "base/bind.h" -#include "base/memory/weak_ptr.h" -#include "content/public/browser/desktop_notification_delegate.h" -#include "content/public/common/platform_notification_data.h" +#include "browser/notification.h" using namespace Microsoft::WRL; @@ -31,23 +28,22 @@ using DesktopToastFailedEventHandler = ABI::Windows::Foundation::ITypedEventHandler; -class WindowsToastNotification { +class WindowsToastNotification : public Notification { public: - // Should be called before using this class. + // Should only be called by NotificationPresenterWin. static bool Initialize(); - WindowsToastNotification( - scoped_ptr delegate); + WindowsToastNotification(NotificationDelegate* delegate, + NotificationPresenter* presenter); ~WindowsToastNotification(); - void ShowNotification(const std::wstring& title, - const std::wstring& msg, - const std::wstring& icon_path); - void DismissNotification(); - - base::WeakPtr GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } + protected: + // Notification: + void Show(const base::string16& title, + const base::string16& msg, + const GURL& icon_url, + const SkBitmap& icon) override; + void Dismiss() override; private: friend class ToastEventHandler; @@ -76,16 +72,18 @@ class WindowsToastNotification { ABI::Windows::Data::Xml::Dom::IXmlNode* node, const std::wstring& text); bool SetupCallbacks(ABI::Windows::UI::Notifications::IToastNotification* toast); + bool RemoveCallbacks(ABI::Windows::UI::Notifications::IToastNotification* toast); static ComPtr toast_manager_; static ComPtr toast_notifier_; - scoped_ptr delegate_; + EventRegistrationToken activated_token_; + EventRegistrationToken dismissed_token_; + EventRegistrationToken failed_token_; + ComPtr event_handler_; ComPtr toast_notification_; - base::WeakPtrFactory weak_factory_; - DISALLOW_COPY_AND_ASSIGN(WindowsToastNotification); }; diff --git a/brightray/filenames.gypi b/brightray/filenames.gypi index 91cb88876c..26c02679c0 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_center_delegate.h', + 'browser/mac/notification_center_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', @@ -54,15 +60,21 @@ 'browser/net_log.h', 'browser/network_delegate.cc', 'browser/network_delegate.h', + 'browser/notification_delegate.h', + 'browser/notification_delegate_adapter.cc', + 'browser/notification_delegate_adapter.h', + 'browser/notification_presenter.cc', 'browser/notification_presenter.h', - 'browser/notification_presenter_mac.h', - 'browser/notification_presenter_mac.mm', + 'browser/notification.cc', + 'browser/notification.h', 'browser/permission_manager.cc', 'browser/permission_manager.h', - 'browser/platform_notification_service_impl.cc', - 'browser/platform_notification_service_impl.h', + 'browser/platform_notification_service.cc', + 'browser/platform_notification_service.h', 'browser/linux/libnotify_loader.h', 'browser/linux/libnotify_loader.cc', + 'browser/linux/libnotify_notification.h', + 'browser/linux/libnotify_notification.cc', 'browser/linux/notification_presenter_linux.h', 'browser/linux/notification_presenter_linux.cc', 'browser/win/notification_presenter_win.h',