| Index: chrome/browser/notifications/notification_platform_bridge_mac.mm
|
| diff --git a/chrome/browser/notifications/notification_platform_bridge_mac.mm b/chrome/browser/notifications/notification_platform_bridge_mac.mm
|
| index 08fefce8bcc7e130114c3ca7f3e03986004b5f58..8e05003c2ef4f12c2a96dbc1c3624ed86ee269a7 100644
|
| --- a/chrome/browser/notifications/notification_platform_bridge_mac.mm
|
| +++ b/chrome/browser/notifications/notification_platform_bridge_mac.mm
|
| @@ -6,8 +6,12 @@
|
|
|
| #include <utility>
|
|
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/mac/bundle_locations.h"
|
| #include "base/mac/foundation_util.h"
|
| #include "base/mac/mac_util.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "chrome/browser/browser_process.h"
|
| @@ -20,10 +24,14 @@
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/profiles/profile_manager.h"
|
| #include "chrome/browser/ui/cocoa/notifications/notification_builder_mac.h"
|
| +#import "chrome/browser/ui/cocoa/notifications/notification_delivery.h"
|
| #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h"
|
| #import "chrome/browser/ui/cocoa/notifications/notification_response_builder_mac.h"
|
| +#include "chrome/common/features.h"
|
| +#include "chrome/grit/generated_resources.h"
|
| #include "components/url_formatter/elide_url.h"
|
| #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationConstants.h"
|
| +#include "ui/base/l10n/l10n_util_mac.h"
|
| #include "url/gurl.h"
|
| #include "url/origin.h"
|
|
|
| @@ -71,6 +79,23 @@ void ProfileLoadedCallback(NotificationCommon::Operation operation,
|
| notification_id, action_index);
|
| }
|
|
|
| +// Loads the profile and process the Notification response
|
| +void DoProcessNotificationResponse(NotificationCommon::Operation operation,
|
| + NotificationCommon::Type type,
|
| + const std::string& profile_id,
|
| + bool incognito,
|
| + const std::string& origin,
|
| + const std::string& notification_id,
|
| + int32_t button_index) {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| + ProfileManager* profileManager = g_browser_process->profile_manager();
|
| + DCHECK(profileManager);
|
| +
|
| + profileManager->LoadProfile(
|
| + profile_id, incognito, base::Bind(&ProfileLoadedCallback, operation, type,
|
| + origin, notification_id, button_index));
|
| +}
|
| +
|
| } // namespace
|
|
|
| // static
|
| @@ -86,19 +111,34 @@ NotificationPlatformBridge* NotificationPlatformBridge::Create() {
|
| }
|
| @end
|
|
|
| +// Interface to communicate with the Alert XPC service.
|
| +@interface NotificationRemoteDispatcher : NSObject
|
| +
|
| +- (void)dispatchNotification:(NSDictionary*)data;
|
| +
|
| +@end
|
| +
|
| // /////////////////////////////////////////////////////////////////////////////
|
|
|
| NotificationPlatformBridgeMac::NotificationPlatformBridgeMac(
|
| NSUserNotificationCenter* notification_center)
|
| : delegate_([NotificationCenterDelegate alloc]),
|
| - notification_center_(notification_center) {
|
| + notification_center_(notification_center),
|
| +#if BUILDFLAG(ENABLE_XPC_NOTIFICATIONS)
|
| + notification_remote_dispatcher_(
|
| + [[NotificationRemoteDispatcher alloc] init])
|
| +#else
|
| + notification_remote_dispatcher_(nullptr)
|
| +#endif // ENABLE_XPC_NOTIFICATIONS
|
| +{
|
| [notification_center_ setDelegate:delegate_.get()];
|
| }
|
|
|
| NotificationPlatformBridgeMac::~NotificationPlatformBridgeMac() {
|
| [notification_center_ setDelegate:nil];
|
|
|
| - // TODO(miguelg) lift this restriction if possible.
|
| + // TODO(miguelg) remove only alerts shown by the XPC service.
|
| + // TODO(miguelg) do not remove banners if possible.
|
| [notification_center_ removeAllDeliveredNotifications];
|
| }
|
|
|
| @@ -139,6 +179,7 @@ void NotificationPlatformBridgeMac::Display(
|
| // Tag
|
| if (!notification.tag().empty()) {
|
| [builder setTag:base::SysUTF8ToNSString(notification.tag())];
|
| +
|
| // If renotify is needed, delete the notification with the same tag
|
| // from the notification center before displaying this one.
|
| // TODO(miguelg): This will need to work for alerts as well via XPC
|
| @@ -166,8 +207,21 @@ void NotificationPlatformBridgeMac::Display(
|
| [builder setIncognito:incognito];
|
| [builder setNotificationType:[NSNumber numberWithInteger:notification_type]];
|
|
|
| +#if BUILDFLAG(ENABLE_XPC_NOTIFICATIONS)
|
| + // Send persistent notifications to the XPC service so they
|
| + // can be displayed as alerts. Chrome itself can only display
|
| + // banners.
|
| + if (notification.never_timeout()) {
|
| + NSDictionary* dict = [builder buildDictionary];
|
| + [notification_remote_dispatcher_ dispatchNotification:dict];
|
| + } else {
|
| + NSUserNotification* toast = [builder buildUserNotification];
|
| + [notification_center_ deliverNotification:toast];
|
| + }
|
| +#else
|
| NSUserNotification* toast = [builder buildUserNotification];
|
| [notification_center_ deliverNotification:toast];
|
| +#endif // ENABLE_XPC_NOTIFICATIONS
|
| }
|
|
|
| void NotificationPlatformBridgeMac::Close(const std::string& profile_id,
|
| @@ -214,6 +268,39 @@ bool NotificationPlatformBridgeMac::SupportsNotificationCenter() const {
|
| }
|
|
|
| // static
|
| +void NotificationPlatformBridgeMac::ProcessNotificationResponse(
|
| + NSDictionary* response) {
|
| + if (!NotificationPlatformBridgeMac::VerifyNotificationData(response))
|
| + return;
|
| +
|
| + NSNumber* button_index =
|
| + [response objectForKey:notification_constants::kNotificationButtonIndex];
|
| + NSNumber* operation =
|
| + [response objectForKey:notification_constants::kNotificationOperation];
|
| +
|
| + std::string notification_origin = base::SysNSStringToUTF8(
|
| + [response objectForKey:notification_constants::kNotificationOrigin]);
|
| + std::string notification_id = base::SysNSStringToUTF8(
|
| + [response objectForKey:notification_constants::kNotificationId]);
|
| + std::string profile_id = base::SysNSStringToUTF8(
|
| + [response objectForKey:notification_constants::kNotificationProfileId]);
|
| + NSNumber* is_incognito =
|
| + [response objectForKey:notification_constants::kNotificationIncognito];
|
| + NSNumber* notification_type =
|
| + [response objectForKey:notification_constants::kNotificationType];
|
| +
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::UI, FROM_HERE,
|
| + base::Bind(DoProcessNotificationResponse,
|
| + static_cast<NotificationCommon::Operation>(
|
| + operation.unsignedIntValue),
|
| + static_cast<NotificationCommon::Type>(
|
| + notification_type.unsignedIntValue),
|
| + profile_id, [is_incognito boolValue], notification_origin,
|
| + notification_id, button_index.intValue));
|
| +}
|
| +
|
| +// static
|
| bool NotificationPlatformBridgeMac::VerifyNotificationData(
|
| NSDictionary* response) {
|
| if (![response
|
| @@ -282,44 +369,13 @@ bool NotificationPlatformBridgeMac::VerifyNotificationData(
|
| }
|
|
|
| // /////////////////////////////////////////////////////////////////////////////
|
| -
|
| @implementation NotificationCenterDelegate
|
| - (void)userNotificationCenter:(NSUserNotificationCenter*)center
|
| didActivateNotification:(NSUserNotification*)notification {
|
| - NSDictionary* response =
|
| + NSDictionary* notificationResponse =
|
| [NotificationResponseBuilder buildDictionary:notification];
|
| - if (!NotificationPlatformBridgeMac::VerifyNotificationData(response))
|
| - return;
|
| -
|
| - NSNumber* buttonIndex =
|
| - [response objectForKey:notification_constants::kNotificationButtonIndex];
|
| - NSNumber* operation =
|
| - [response objectForKey:notification_constants::kNotificationOperation];
|
| -
|
| - std::string notificationOrigin = base::SysNSStringToUTF8(
|
| - [response objectForKey:notification_constants::kNotificationOrigin]);
|
| - NSString* notificationId =
|
| - [response objectForKey:notification_constants::kNotificationId];
|
| - std::string persistentNotificationId =
|
| - base::SysNSStringToUTF8(notificationId);
|
| - std::string profileId = base::SysNSStringToUTF8(
|
| - [response objectForKey:notification_constants::kNotificationProfileId]);
|
| - NSNumber* isIncognito =
|
| - [response objectForKey:notification_constants::kNotificationIncognito];
|
| - NSNumber* notificationType =
|
| - [response objectForKey:notification_constants::kNotificationType];
|
| -
|
| - ProfileManager* profileManager = g_browser_process->profile_manager();
|
| - DCHECK(profileManager);
|
| -
|
| - profileManager->LoadProfile(
|
| - profileId, [isIncognito boolValue],
|
| - base::Bind(
|
| - &ProfileLoadedCallback, static_cast<NotificationCommon::Operation>(
|
| - operation.unsignedIntValue),
|
| - static_cast<NotificationCommon::Type>(
|
| - notificationType.unsignedIntValue),
|
| - notificationOrigin, persistentNotificationId, buttonIndex.intValue));
|
| + NotificationPlatformBridgeMac::ProcessNotificationResponse(
|
| + notificationResponse);
|
| }
|
|
|
| - (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
|
| @@ -329,3 +385,52 @@ bool NotificationPlatformBridgeMac::VerifyNotificationData(
|
| }
|
|
|
| @end
|
| +
|
| +@implementation NotificationRemoteDispatcher {
|
| + // The connection to the XPC server in charge of delivering alerts.
|
| + base::scoped_nsobject<NSXPCConnection> xpcConnection_;
|
| +}
|
| +
|
| +- (instancetype)init {
|
| + if ((self = [super init])) {
|
| + xpcConnection_.reset([[NSXPCConnection alloc]
|
| + initWithServiceName:
|
| + [NSString
|
| + stringWithFormat:notification_constants::kAlertXPCServiceName,
|
| + [base::mac::OuterBundle() bundleIdentifier]]]);
|
| + xpcConnection_.get().remoteObjectInterface =
|
| + [NSXPCInterface interfaceWithProtocol:@protocol(NotificationDelivery)];
|
| +
|
| + xpcConnection_.get().interruptionHandler = ^{
|
| + LOG(WARNING) << "connection interrupted: interruptionHandler: ";
|
| + // TODO(miguelg): perhaps add some UMA here.
|
| + // We will be getting this handler both when the XPC server crashes or
|
| + // when it decides to close the connection.
|
| + };
|
| + xpcConnection_.get().invalidationHandler = ^{
|
| + LOG(WARNING) << "connection invalidationHandler received";
|
| + // This means that the connection should be recreated if it needs
|
| + // to be used again. It should not really happen.
|
| + DCHECK(false) << "XPC Connection invalidated";
|
| + };
|
| +
|
| + xpcConnection_.get().exportedInterface =
|
| + [NSXPCInterface interfaceWithProtocol:@protocol(NotificationReply)];
|
| + xpcConnection_.get().exportedObject = self;
|
| + [xpcConnection_ resume];
|
| + }
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (void)dispatchNotification:(NSDictionary*)data {
|
| + [[xpcConnection_ remoteObjectProxy] deliverNotification:data];
|
| +}
|
| +
|
| +// NotificationReply implementation
|
| +- (void)notificationClick:(NSDictionary*)notificationResponseData {
|
| + NotificationPlatformBridgeMac::ProcessNotificationResponse(
|
| + notificationResponseData);
|
| +}
|
| +
|
| +@end
|
|
|