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

Unified Diff: chrome/browser/notifications/notification_platform_bridge_linux.cc

Issue 2872053002: Linux native notifications: Support image notifications (Closed)
Patch Set: Rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/notifications/notification_platform_bridge_linux.cc
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index 602b7b3047963c747b8d7246f67cdb8750e763af..f821eaa8d3b8264da3dbdd4de7ce8e5ba1c06506 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -36,6 +36,7 @@
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
+#include "skia/ext/image_operations.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image_skia.h"
@@ -71,6 +72,10 @@ const char kCapabilitySound[] = "sound";
const char kDefaultButtonId[] = "default";
const char kSettingsButtonId[] = "settings";
+// Max image size; specified in the FDO notification specification.
+const int kMaxImageWidth = 200;
+const int kMaxImageHeight = 100;
+
// The values in this enumeration correspond to those of the
// Linux.NotificationPlatformBridge.InitializationStatus histogram, so
// the ordering should not be changed. New error codes should be
@@ -84,6 +89,10 @@ enum class ConnectionInitializationStatusCode {
NUM_ITEMS
};
+int ClampInt(int value, int low, int hi) {
+ return std::max(std::min(value, hi), low);
+}
+
base::string16 CreateNotificationTitle(const Notification& notification) {
base::string16 title;
if (notification.type() == message_center::NOTIFICATION_TYPE_PROGRESS) {
@@ -121,6 +130,28 @@ int NotificationPriorityToFdoUrgency(int priority) {
}
}
+// Constrain |image|'s size to |kMaxImageWidth|x|kMaxImageHeight|. If
+// the image does not need to be resized, or the image is empty,
+// returns |image| directly.
+gfx::Image ResizeImageToFdoMaxSize(const gfx::Image& image) {
+ if (image.IsEmpty())
+ return image;
+ int width = image.Width();
+ int height = image.Height();
+ if (width <= kMaxImageWidth && height <= kMaxImageHeight) {
+ return image;
+ }
+ const SkBitmap* image_bitmap = image.ToSkBitmap();
+ double scale = std::min(static_cast<double>(kMaxImageWidth) / width,
+ static_cast<double>(kMaxImageHeight) / height);
+ width = ClampInt(scale * width, 1, kMaxImageWidth);
+ height = ClampInt(scale * height, 1, kMaxImageHeight);
+ return gfx::Image(
+ gfx::ImageSkia::CreateFrom1xBitmap(skia::ImageOperations::Resize(
+ *image_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, width,
+ height)));
+}
+
// Runs once the profile has been loaded in order to perform a given
// |operation| on a notification.
void ProfileLoadedCallback(NotificationCommon::Operation operation,
@@ -235,7 +266,9 @@ class NotificationPlatformBridgeLinuxImpl
// non-thread-safe reference counts) to the task runner thread.
auto notification_copy = base::MakeUnique<Notification>(notification);
notification_copy->set_icon(DeepCopyImage(notification_copy->icon()));
- notification_copy->set_image(gfx::Image());
+ notification_copy->set_image(body_images_supported_
+ ? DeepCopyImage(notification_copy->image())
+ : gfx::Image());
notification_copy->set_small_image(gfx::Image());
for (size_t i = 0; i < notification_copy->buttons().size(); i++)
notification_copy->SetButtonIcon(i, gfx::Image());
@@ -337,6 +370,11 @@ class NotificationPlatformBridgeLinuxImpl
CleanUp();
}
+ void SetBodyImagesSupported(bool body_images_supported) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ body_images_supported_ = body_images_supported;
+ }
+
void PostTaskToUiThread(base::OnceClosure closure) const {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
bool success = content::BrowserThread::PostTask(
@@ -386,6 +424,9 @@ class NotificationPlatformBridgeLinuxImpl
capabilities_.insert(capability);
}
RecordMetricsForCapabilities();
+ PostTaskToUiThread(base::BindOnce(
+ &NotificationPlatformBridgeLinuxImpl::SetBodyImagesSupported, this,
+ base::ContainsKey(capabilities_, kCapabilityBodyImages)));
dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName,
kMethodGetServerInformation);
@@ -475,11 +516,39 @@ class NotificationPlatformBridgeLinuxImpl
std::string body;
if (base::ContainsKey(capabilities_, kCapabilityBody)) {
body = base::UTF16ToUTF8(notification->message());
- if (base::ContainsKey(capabilities_, kCapabilityBodyMarkup)) {
+ const bool body_markup =
+ base::ContainsKey(capabilities_, kCapabilityBodyMarkup);
+ if (body_markup) {
base::ReplaceSubstringsAfterOffset(&body, 0, "&", "&amp;");
base::ReplaceSubstringsAfterOffset(&body, 0, "<", "&lt;");
base::ReplaceSubstringsAfterOffset(&body, 0, ">", "&gt;");
}
+ if (notification->type() == message_center::NOTIFICATION_TYPE_MULTIPLE) {
+ for (const auto& item : notification->items()) {
+ if (!body.empty())
+ body += "\n";
+ const std::string title = base::UTF16ToUTF8(item.title);
+ const std::string message = base::UTF16ToUTF8(item.message);
+ // TODO(peter): Figure out the right way to internationalize
+ // this for RTL languages.
+ if (body_markup)
+ body += "<b>" + title + "</b> " + message;
+ else
+ body += title + " - " + message;
+ }
+ } else if (notification->type() ==
+ message_center::NOTIFICATION_TYPE_IMAGE &&
+ base::ContainsKey(capabilities_, "body-images")) {
+ std::unique_ptr<ResourceFile> image_file = WriteDataToTmpFile(
+ ResizeImageToFdoMaxSize(notification->image()).As1xPNGBytes());
+ if (image_file) {
+ if (!body.empty())
+ body += "\n";
+ body +=
+ "<img src=\"" + image_file->file_path().value() + "\" alt=\"\"/>";
Peter Beverloo 2017/05/15 16:16:00 Let's use an std::stringstream for building |body|
Tom (Use chromium acct) 2017/05/15 19:18:39 Done.
+ data->resource_files.push_back(std::move(image_file));
+ }
+ }
}
writer.AppendString(body);
@@ -549,7 +618,9 @@ class NotificationPlatformBridgeLinuxImpl
writer.CloseContainer(&hints_writer);
const int32_t kExpireTimeoutDefault = -1;
- writer.AppendInt32(kExpireTimeoutDefault);
+ const int32_t kExpireTimeoutNever = 0;
+ writer.AppendInt32(notification->never_timeout() ? kExpireTimeoutNever
Peter Beverloo 2017/05/15 16:16:00 As a general comment, some of your CLs are a bit t
Tom (Use chromium acct) 2017/05/15 19:18:39 Done. Sorry, the dependent patch set somehow got
+ : kExpireTimeoutDefault);
std::unique_ptr<dbus::Response> response =
notification_proxy_->CallMethodAndBlock(
@@ -765,6 +836,12 @@ class NotificationPlatformBridgeLinuxImpl
base::Optional<bool> connected_;
std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_;
+ // Notification servers very rarely have the 'body-images'
+ // capability, so try to avoid an image copy if possible. It is
+ // intialized to true so that the UI thread will conservatively copy
+ // the image before the GetCapabilities message completes.
+ bool body_images_supported_ = true;
Peter Beverloo 2017/05/15 16:16:00 Technically we should never call Display() before
Tom (Use chromium acct) 2017/05/15 19:18:39 In the case of unit testing, calls to Display() ar
Lei Zhang 2017/05/15 21:48:40 Is it a lot of work to change the unit tests to no
Tom (Use chromium acct) 2017/05/16 00:22:00 Nope, just a one line change in CreatePlatformBrid
+
//////////////////////////////////////////////////////////////////////////////
// Members used only on the task runner thread.

Powered by Google App Engine
This is Rietveld 408576698