Commit 1e734077 authored by Mohamed Adel's avatar Mohamed Adel Committed by Commit Bot

Support images in UNNotification

- Moves setIcon from notification_builder_base to
notification_builder_mac as it is not shared between the builders.

- Adds setImagePath in unnotification_builder_mac to set the path of
the image that will be attached to the notification

Bug: 1136930
Change-Id: I9f5acfac73fc6dd738c4326d865059506e332ee0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463828
Commit-Queue: Mohamed Adel <adelm@google.com>
Reviewed-by: default avatarRichard Knoll <knollr@chromium.org>
Reviewed-by: default avatarRayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816963}
parent 9f8ff139
...@@ -185,6 +185,9 @@ void NotificationPlatformBridgeMac::Display( ...@@ -185,6 +185,9 @@ void NotificationPlatformBridgeMac::Display(
is_persistent, notification, requires_attribution))]; is_persistent, notification, requires_attribution))];
if (!notification.icon().IsEmpty()) { if (!notification.icon().IsEmpty()) {
// TODO(crbug/1138176): Resize images by adding a transparent border so that
// its dimensions are uniform and do not get resized once sent to the
// notification center
[builder setIcon:notification.icon().ToNSImage()]; [builder setIcon:notification.icon().ToNSImage()];
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "chrome/browser/notifications/notification_common.h" #include "chrome/browser/notifications/notification_common.h"
#include "chrome/browser/notifications/notification_image_retainer.h"
#include "chrome/browser/notifications/notification_platform_bridge.h" #include "chrome/browser/notifications/notification_platform_bridge.h"
@class UNNotificationCenterDelegate; @class UNNotificationCenterDelegate;
...@@ -60,6 +61,9 @@ class API_AVAILABLE(macosx(10.14)) NotificationPlatformBridgeMacUNNotification ...@@ -60,6 +61,9 @@ class API_AVAILABLE(macosx(10.14)) NotificationPlatformBridgeMacUNNotification
// The notification center to use for local banner notifications, // The notification center to use for local banner notifications,
// this can be overridden in tests. // this can be overridden in tests.
base::scoped_nsobject<UNUserNotificationCenter> notification_center_; base::scoped_nsobject<UNUserNotificationCenter> notification_center_;
// An object that keeps temp files alive long enough for macOS to pick up.
NotificationImageRetainer image_retainer_;
}; };
#endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PLATFORM_BRIDGE_MAC_UNNOTIFICATION_H_ #endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PLATFORM_BRIDGE_MAC_UNNOTIFICATION_H_
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/notifications/notification_platform_bridge_mac_utils.h" #include "chrome/browser/notifications/notification_platform_bridge_mac_utils.h"
...@@ -87,6 +88,15 @@ void NotificationPlatformBridgeMacUNNotification::Display( ...@@ -87,6 +88,15 @@ void NotificationPlatformBridgeMacUNNotification::Display(
/*is_persistent=*/false, notification, /*is_persistent=*/false, notification,
requires_attribution))]; requires_attribution))];
if (!notification.icon().IsEmpty()) {
// TODO(crbug/1138176): Resize images by adding a transparent border so that
// its dimensions are uniform and do not get resized once sent to the
// notification center
base::FilePath path =
image_retainer_.RegisterTemporaryImage(notification.icon());
[builder setIconPath:base::SysUTF8ToNSString(path.value())];
}
[builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())]; [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())];
[builder setNotificationId:base::SysUTF8ToNSString(notification.id())]; [builder setNotificationId:base::SysUTF8ToNSString(notification.id())];
[builder setProfileId:base::SysUTF8ToNSString(GetProfileId(profile))]; [builder setProfileId:base::SysUTF8ToNSString(GetProfileId(profile))];
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
- (void)setTitle:(NSString*)title; - (void)setTitle:(NSString*)title;
- (void)setSubTitle:(NSString*)subTitle; - (void)setSubTitle:(NSString*)subTitle;
- (void)setContextMessage:(NSString*)contextMessage; - (void)setContextMessage:(NSString*)contextMessage;
- (void)setIcon:(NSImage*)icon;
- (void)setButtons:(NSString*)primaryButton - (void)setButtons:(NSString*)primaryButton
secondaryButton:(NSString*)secondaryButton; secondaryButton:(NSString*)secondaryButton;
- (void)setTag:(NSString*)tag; - (void)setTag:(NSString*)tag;
......
...@@ -44,18 +44,6 @@ ...@@ -44,18 +44,6 @@
} }
} }
- (void)setIcon:(NSImage*)icon {
if (icon) {
if ([icon conformsToProtocol:@protocol(NSSecureCoding)]) {
[_notificationData setObject:icon
forKey:notification_constants::kNotificationImage];
} else { // NSImage only conforms to NSSecureCoding from 10.10 onwards.
[_notificationData setObject:[icon TIFFRepresentation]
forKey:notification_constants::kNotificationImage];
}
}
}
- (void)setButtons:(NSString*)primaryButton - (void)setButtons:(NSString*)primaryButton
secondaryButton:(NSString*)secondaryButton { secondaryButton:(NSString*)secondaryButton {
DCHECK(primaryButton.length); DCHECK(primaryButton.length);
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
optionsLabel:(NSString*)optionsLabel optionsLabel:(NSString*)optionsLabel
settingsLabel:(NSString*)settingsLabel; settingsLabel:(NSString*)settingsLabel;
// Sets the icon that is displayed in the notification if present
- (void)setIcon:(NSImage*)icon;
// Returns a notification ready to be displayed out of the provided // Returns a notification ready to be displayed out of the provided
// |notificationData|. // |notificationData|.
......
...@@ -30,6 +30,19 @@ ...@@ -30,6 +30,19 @@
return self; return self;
} }
- (void)setIcon:(NSImage*)icon {
if (!icon)
return;
if ([icon conformsToProtocol:@protocol(NSSecureCoding)]) {
[_notificationData setObject:icon
forKey:notification_constants::kNotificationIcon];
} else { // NSImage only conforms to NSSecureCoding from 10.10 onwards.
[_notificationData setObject:[icon TIFFRepresentation]
forKey:notification_constants::kNotificationIcon];
}
}
- (NSUserNotification*)buildUserNotification { - (NSUserNotification*)buildUserNotification {
base::scoped_nsobject<NSUserNotification> toast( base::scoped_nsobject<NSUserNotification> toast(
[[NSUserNotification alloc] init]); [[NSUserNotification alloc] init]);
...@@ -44,16 +57,15 @@ ...@@ -44,16 +57,15 @@
// Icon // Icon
if ([_notificationData if ([_notificationData
objectForKey:notification_constants::kNotificationImage]) { objectForKey:notification_constants::kNotificationIcon]) {
if ([[NSImage class] conformsToProtocol:@protocol(NSSecureCoding)]) { if ([[NSImage class] conformsToProtocol:@protocol(NSSecureCoding)]) {
NSImage* image = [_notificationData NSImage* image = [_notificationData
objectForKey:notification_constants::kNotificationImage]; objectForKey:notification_constants::kNotificationIcon];
[toast setContentImage:image]; [toast setContentImage:image];
} else { // NSImage only conforms to NSSecureCoding from 10.10 onwards. } else { // NSImage only conforms to NSSecureCoding from 10.10 onwards.
base::scoped_nsobject<NSImage> image([[NSImage alloc] base::scoped_nsobject<NSImage> image([[NSImage alloc]
initWithData: initWithData:[_notificationData objectForKey:notification_constants::
[_notificationData kNotificationIcon]]);
objectForKey:notification_constants::kNotificationImage]]);
[toast setContentImage:image]; [toast setContentImage:image];
} }
} }
......
...@@ -12,7 +12,8 @@ namespace notification_constants { ...@@ -12,7 +12,8 @@ namespace notification_constants {
extern NSString* const kNotificationTitle; extern NSString* const kNotificationTitle;
extern NSString* const kNotificationSubTitle; extern NSString* const kNotificationSubTitle;
extern NSString* const kNotificationInformativeText; extern NSString* const kNotificationInformativeText;
extern NSString* const kNotificationImage; extern NSString* const kNotificationIcon;
extern NSString* const kNotificationIconPath;
extern NSString* const kNotificationButtonOne; extern NSString* const kNotificationButtonOne;
extern NSString* const kNotificationButtonTwo; extern NSString* const kNotificationButtonTwo;
extern NSString* const kNotificationTag; extern NSString* const kNotificationTag;
......
...@@ -11,7 +11,8 @@ namespace notification_constants { ...@@ -11,7 +11,8 @@ namespace notification_constants {
NSString* const kNotificationTitle = @"title"; NSString* const kNotificationTitle = @"title";
NSString* const kNotificationSubTitle = @"subtitle"; NSString* const kNotificationSubTitle = @"subtitle";
NSString* const kNotificationInformativeText = @"informativeText"; NSString* const kNotificationInformativeText = @"informativeText";
NSString* const kNotificationImage = @"icon"; NSString* const kNotificationIcon = @"icon";
NSString* const kNotificationIconPath = @"iconPath";
NSString* const kNotificationButtonOne = @"buttonOne"; NSString* const kNotificationButtonOne = @"buttonOne";
NSString* const kNotificationButtonTwo = @"buttonTwo"; NSString* const kNotificationButtonTwo = @"buttonTwo";
NSString* const kNotificationTag = @"tag"; NSString* const kNotificationTag = @"tag";
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
API_AVAILABLE(macosx(10.14)) API_AVAILABLE(macosx(10.14))
@interface UNNotificationBuilder : NotificationBuilderBase @interface UNNotificationBuilder : NotificationBuilderBase
// Sets the icon path that is used to display it in the notification if present
- (void)setIconPath:(NSString*)iconPath;
// Returns a notification ready to be displayed out of the provided // Returns a notification ready to be displayed out of the provided
// |notificationData|. // |notificationData|.
- (UNMutableNotificationContent*)buildUserNotification; - (UNMutableNotificationContent*)buildUserNotification;
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
@implementation UNNotificationBuilder @implementation UNNotificationBuilder
- (void)setIconPath:(NSString*)iconPath {
[_notificationData setObject:iconPath
forKey:notification_constants::kNotificationIconPath];
}
- (UNMutableNotificationContent*)buildUserNotification { - (UNMutableNotificationContent*)buildUserNotification {
base::scoped_nsobject<UNMutableNotificationContent> toast( base::scoped_nsobject<UNMutableNotificationContent> toast(
[[UNMutableNotificationContent alloc] init]); [[UNMutableNotificationContent alloc] init]);
...@@ -66,6 +71,30 @@ ...@@ -66,6 +71,30 @@
NSNumber* incognito = [_notificationData NSNumber* incognito = [_notificationData
objectForKey:notification_constants::kNotificationIncognito]; objectForKey:notification_constants::kNotificationIncognito];
// Icon
if ([_notificationData
objectForKey:notification_constants::kNotificationIconPath]) {
NSURL* url = [NSURL
fileURLWithPath:
[_notificationData
objectForKey:notification_constants::kNotificationIconPath]];
// When the files are saved using NotificationImageRetainer, they're saved
// without the .png extension. So |options| here is used to tell the system
// that the file is of type PNG, as NotificationImageRetainer converts files
// to PNG before writing them.
UNNotificationAttachment* attachment = [UNNotificationAttachment
attachmentWithIdentifier:notificationId
URL:url
options:@{
UNNotificationAttachmentOptionsTypeHintKey :
(NSString*)kUTTypePNG
}
error:nil];
if (attachment != nil)
[toast setAttachments:@[ attachment ]];
}
[toast setUserInfo:@{ [toast setUserInfo:@{
notification_constants::kNotificationOrigin : origin, notification_constants::kNotificationOrigin : origin,
notification_constants::kNotificationId : notificationId, notification_constants::kNotificationId : notificationId,
......
...@@ -4,12 +4,20 @@ ...@@ -4,12 +4,20 @@
#import <UserNotifications/UserNotifications.h> #import <UserNotifications/UserNotifications.h>
#include "base/files/file_util.h"
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_path_override.h"
#include "base/test/task_environment.h"
#include "chrome/browser/notifications/notification_handler.h" #include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/notifications/notification_image_retainer.h"
#include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h" #include "chrome/browser/ui/cocoa/notifications/notification_constants_mac.h"
#import "chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h" #import "chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
namespace { namespace {
...@@ -40,6 +48,7 @@ TEST(UNNotificationBuilderMacTest, TestNotificationData) { ...@@ -40,6 +48,7 @@ TEST(UNNotificationBuilderMacTest, TestNotificationData) {
EXPECT_EQ("hey there", base::SysNSStringToUTF8([content body])); EXPECT_EQ("hey there", base::SysNSStringToUTF8([content body]));
EXPECT_EQ("https://www.moe.example.com", EXPECT_EQ("https://www.moe.example.com",
base::SysNSStringToUTF8([content subtitle])); base::SysNSStringToUTF8([content subtitle]));
EXPECT_EQ(0ul, [[content attachments] count]);
} }
} }
...@@ -193,3 +202,44 @@ TEST(UNNotificationBuilderMacTest, ...@@ -193,3 +202,44 @@ TEST(UNNotificationBuilderMacTest,
boolValue]); boolValue]);
} }
} }
TEST(UNNotificationBuilderMacTest, TestIcon) {
if (@available(macOS 10.14, *)) {
base::scoped_nsobject<UNNotificationBuilder> builder =
NewTestBuilder(NotificationHandler::Type::WEB_PERSISTENT);
base::test::TaskEnvironment task_environment(
base::test::TaskEnvironment::TimeSource::MOCK_TIME);
base::ScopedPathOverride user_data_dir_override(chrome::DIR_USER_DATA);
auto image_retainer = std::make_unique<NotificationImageRetainer>(
task_environment.GetMainThreadTaskRunner(),
task_environment.GetMockTickClock());
SkBitmap icon;
icon.allocN32Pixels(64, 64);
icon.eraseARGB(255, 100, 150, 200);
gfx::Image image = gfx::Image::CreateFrom1xBitmap(icon);
base::FilePath temp_file = image_retainer->RegisterTemporaryImage(image);
ASSERT_FALSE(temp_file.empty());
ASSERT_TRUE(base::PathExists(temp_file));
[builder setIconPath:base::SysUTF8ToNSString(temp_file.value())];
UNMutableNotificationContent* content = [builder buildUserNotification];
EXPECT_EQ(1ul, [[content attachments] count]);
}
}
TEST(UNNotificationBuilderMacTest, TestIconWrongPath) {
if (@available(macOS 10.14, *)) {
base::scoped_nsobject<UNNotificationBuilder> builder =
NewTestBuilder(NotificationHandler::Type::WEB_PERSISTENT);
[builder setIconPath:@"wrong-path"];
UNMutableNotificationContent* content = [builder buildUserNotification];
EXPECT_EQ(0ul, [[content attachments] count]);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment