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

Side by Side Diff: chrome/browser/notifications/notification_platform_bridge_linux.cc

Issue 2872053002: Linux native notifications: Support image notifications (Closed)
Patch Set: 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" 5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <set> 9 #include <set>
10 #include <unordered_map> 10 #include <unordered_map>
(...skipping 16 matching lines...) Expand all
27 #include "chrome/browser/notifications/native_notification_display_service.h" 27 #include "chrome/browser/notifications/native_notification_display_service.h"
28 #include "chrome/browser/notifications/notification.h" 28 #include "chrome/browser/notifications/notification.h"
29 #include "chrome/browser/notifications/notification_display_service_factory.h" 29 #include "chrome/browser/notifications/notification_display_service_factory.h"
30 #include "chrome/browser/profiles/profile_manager.h" 30 #include "chrome/browser/profiles/profile_manager.h"
31 #include "chrome/browser/shell_integration_linux.h" 31 #include "chrome/browser/shell_integration_linux.h"
32 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/notification_service.h"
34 #include "dbus/bus.h" 34 #include "dbus/bus.h"
35 #include "dbus/message.h" 35 #include "dbus/message.h"
36 #include "dbus/object_proxy.h" 36 #include "dbus/object_proxy.h"
37 #include "skia/ext/image_operations.h"
37 #include "ui/gfx/image/image_skia.h" 38 #include "ui/gfx/image/image_skia.h"
38 39
39 namespace { 40 namespace {
40 41
41 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; 42 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications";
42 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; 43 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications";
43 44
44 const char kDefaultButtonId[] = "default"; 45 const char kDefaultButtonId[] = "default";
45 const char kSettingsButtonId[] = "settings"; 46 const char kSettingsButtonId[] = "settings";
46 47
48 // Specified in FDO notification specification.
49 const int kMaxImageWidth = 200;
50 const int kMaxImageHeight = 100;
Peter Beverloo 2017/05/10 12:54:40 This is tiny! Developers have to provide images wi
Tom (Use chromium acct) 2017/05/11 00:07:04 Yeah, but the only notification server that actual
51
47 // The values in this enumeration correspond to those of the 52 // The values in this enumeration correspond to those of the
48 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so 53 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so
49 // the ordering should not be changed. New error codes should be 54 // the ordering should not be changed. New error codes should be
50 // added at the end, before NUM_ITEMS. 55 // added at the end, before NUM_ITEMS.
51 enum class ConnectionInitializationStatusCode { 56 enum class ConnectionInitializationStatusCode {
52 SUCCESS = 0, 57 SUCCESS = 0,
53 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1, 58 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1,
54 MISSING_REQUIRED_CAPABILITIES = 2, 59 MISSING_REQUIRED_CAPABILITIES = 2,
55 COULD_NOT_CONNECT_TO_SIGNALS = 3, 60 COULD_NOT_CONNECT_TO_SIGNALS = 3,
56 INCOMPATIBLE_SPEC_VERSION = 4, 61 INCOMPATIBLE_SPEC_VERSION = 4,
57 NUM_ITEMS 62 NUM_ITEMS
58 }; 63 };
59 64
65 int ClampInt(int v, int lo, int hi) {
66 if (v < lo)
67 return lo;
68 if (v > hi)
69 return hi;
70 return v;
71 }
72
60 gfx::Image DeepCopyImage(const gfx::Image& image) { 73 gfx::Image DeepCopyImage(const gfx::Image& image) {
61 if (image.IsEmpty()) 74 if (image.IsEmpty())
62 return gfx::Image(); 75 return gfx::Image();
63 std::unique_ptr<gfx::ImageSkia> image_skia(image.CopyImageSkia()); 76 std::unique_ptr<gfx::ImageSkia> image_skia(image.CopyImageSkia());
64 return gfx::Image(*image_skia); 77 return gfx::Image(*image_skia);
65 } 78 }
66 79
67 int NotificationPriorityToFdoUrgency(int priority) { 80 int NotificationPriorityToFdoUrgency(int priority) {
68 enum FdoUrgency { 81 enum FdoUrgency {
69 LOW = 0, 82 LOW = 0,
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 bool is_incognito, 204 bool is_incognito,
192 const Notification& notification) override { 205 const Notification& notification) override {
193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 206 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
194 // Notifications contain gfx::Image's which have reference counts 207 // Notifications contain gfx::Image's which have reference counts
195 // that are not thread safe. Because of this, we duplicate the 208 // that are not thread safe. Because of this, we duplicate the
196 // notification and its images. Wrap the notification in a 209 // notification and its images. Wrap the notification in a
197 // unique_ptr to transfer ownership of the notification (and the 210 // unique_ptr to transfer ownership of the notification (and the
198 // non-thread-safe reference counts) to the task runner thread. 211 // non-thread-safe reference counts) to the task runner thread.
199 auto notification_copy = base::MakeUnique<Notification>(notification); 212 auto notification_copy = base::MakeUnique<Notification>(notification);
200 notification_copy->set_icon(DeepCopyImage(notification_copy->icon())); 213 notification_copy->set_icon(DeepCopyImage(notification_copy->icon()));
201 notification_copy->set_image(gfx::Image()); 214 if (body_images_supported_ != BODY_IMAGES_NOT_SUPPORTED &&
215 !notification_copy->image().IsEmpty()) {
216 int width = notification_copy->image().Width();
217 int height = notification_copy->image().Height();
218 if (width <= kMaxImageWidth && height <= kMaxImageHeight) {
219 notification_copy->set_image(DeepCopyImage(notification_copy->image()));
220 } else {
221 const SkBitmap* image_bitmap = notification_copy->image().ToSkBitmap();
222 double scale = std::min(static_cast<double>(kMaxImageWidth) / width,
223 static_cast<double>(kMaxImageHeight) / height);
224 width = ClampInt(scale * width, 1, kMaxImageWidth);
225 height = ClampInt(scale * height, 1, kMaxImageHeight);
226 notification_copy->set_image(gfx::Image(
227 gfx::ImageSkia::CreateFrom1xBitmap(skia::ImageOperations::Resize(
228 *image_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, width,
229 height))));
Peter Beverloo 2017/05/10 12:54:40 Since these images potentially can be huge, we sho
Tom (Use chromium acct) 2017/05/11 00:07:04 Done.
230 }
231 }
202 notification_copy->set_small_image(gfx::Image()); 232 notification_copy->set_small_image(gfx::Image());
203 for (size_t i = 0; i < notification_copy->buttons().size(); i++) 233 for (size_t i = 0; i < notification_copy->buttons().size(); i++)
204 notification_copy->SetButtonIcon(i, gfx::Image()); 234 notification_copy->SetButtonIcon(i, gfx::Image());
205 235
206 PostTaskToTaskRunnerThread(base::BindOnce( 236 PostTaskToTaskRunnerThread(base::BindOnce(
207 &NotificationPlatformBridgeLinuxImpl::DisplayOnTaskRunner, this, 237 &NotificationPlatformBridgeLinuxImpl::DisplayOnTaskRunner, this,
208 notification_type, notification_id, profile_id, is_incognito, 238 notification_type, notification_id, profile_id, is_incognito,
209 base::Passed(&notification_copy))); 239 base::Passed(&notification_copy)));
210 } 240 }
211 241
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 notification_proxy_->CallMethodAndBlock( 372 notification_proxy_->CallMethodAndBlock(
343 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); 373 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
344 if (capabilities_response) { 374 if (capabilities_response) {
345 dbus::MessageReader reader(capabilities_response.get()); 375 dbus::MessageReader reader(capabilities_response.get());
346 std::vector<std::string> capabilities; 376 std::vector<std::string> capabilities;
347 reader.PopArrayOfStrings(&capabilities); 377 reader.PopArrayOfStrings(&capabilities);
348 for (const std::string& capability : capabilities) 378 for (const std::string& capability : capabilities)
349 capabilities_.insert(capability); 379 capabilities_.insert(capability);
350 } 380 }
351 RecordMetricsForCapabilities(); 381 RecordMetricsForCapabilities();
382 body_images_supported_ = base::ContainsKey(capabilities_, "body-images")
383 ? BODY_IMAGES_SUPPORTED
384 : BODY_IMAGES_NOT_SUPPORTED;
352 385
353 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName, 386 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName,
354 "GetServerInformation"); 387 "GetServerInformation");
355 std::unique_ptr<dbus::Response> server_information_response = 388 std::unique_ptr<dbus::Response> server_information_response =
356 notification_proxy_->CallMethodAndBlock( 389 notification_proxy_->CallMethodAndBlock(
357 &get_server_information_call, 390 &get_server_information_call,
358 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); 391 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
359 if (server_information_response) { 392 if (server_information_response) {
360 dbus::MessageReader reader(server_information_response.get()); 393 dbus::MessageReader reader(server_information_response.get());
361 std::string spec_version; 394 std::string spec_version;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 for (const auto& item : notification->items()) { 483 for (const auto& item : notification->items()) {
451 if (!body.empty()) 484 if (!body.empty())
452 body += "\n"; 485 body += "\n";
453 const std::string title = base::UTF16ToUTF8(item.title); 486 const std::string title = base::UTF16ToUTF8(item.title);
454 const std::string message = base::UTF16ToUTF8(item.message); 487 const std::string message = base::UTF16ToUTF8(item.message);
455 if (body_markup) 488 if (body_markup)
456 body += "<b>" + title + "</b> " + message; 489 body += "<b>" + title + "</b> " + message;
457 else 490 else
458 body += title + " - " + message; 491 body += title + " - " + message;
459 } 492 }
493 } else if (notification->type() ==
494 message_center::NOTIFICATION_TYPE_IMAGE) {
495 std::unique_ptr<ResourceFile> image_file =
496 WriteDataToTmpFile(notification->image().As1xPNGBytes());
497 if (image_file) {
498 if (!body.empty())
499 body += "\n";
500 body +=
501 "<img src=\"" + image_file->file_path().value() + "\" alt=\"\"/>";
Peter Beverloo 2017/05/10 12:54:40 Is a data: URL an option here? If the toast requir
Tom (Use chromium acct) 2017/05/11 00:07:04 No, the spec says "Images referenced must always b
502 data->resource_files.push_back(std::move(image_file));
503 }
460 } 504 }
461 } 505 }
462 writer.AppendString(body); 506 writer.AppendString(body);
463 507
464 // Even-indexed elements in this vector are action IDs passed back to 508 // Even-indexed elements in this vector are action IDs passed back to
465 // us in OnActionInvoked(). Odd-indexed ones contain the button text. 509 // us in OnActionInvoked(). Odd-indexed ones contain the button text.
466 std::vector<std::string> actions; 510 std::vector<std::string> actions;
467 if (base::ContainsKey(capabilities_, "actions")) { 511 if (base::ContainsKey(capabilities_, "actions")) {
468 data->action_start = data->action_end; 512 data->action_start = data->action_end;
469 for (const auto& button_info : notification->buttons()) { 513 for (const auto& button_info : notification->buttons()) {
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 base::Closure connected_signals_barrier_; 805 base::Closure connected_signals_barrier_;
762 806
763 // A std::set<std::unique_ptr<T>> doesn't work well because 807 // A std::set<std::unique_ptr<T>> doesn't work well because
764 // eg. std::set::erase(T) would require a std::unique_ptr<T> 808 // eg. std::set::erase(T) would require a std::unique_ptr<T>
765 // argument, so the data would get double-destructed. 809 // argument, so the data would get double-destructed.
766 template <typename T> 810 template <typename T>
767 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; 811 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>;
768 812
769 UnorderedUniqueSet<NotificationData> notifications_; 813 UnorderedUniqueSet<NotificationData> notifications_;
770 814
815 //////////////////////////////////////////////////////////////////////////////
816 // Members used on both the UI thread and the task runner thread.
817
818 // Notification servers very rarely have the 'body-images'
819 // capability, so try to avoid an image copy/resize if possible.
820 // Reads and writes to |body_images_supported_| should be atomic, so
821 // no locking is necessary.
822 enum {
823 BODY_IMAGES_UNKNOWN,
824 BODY_IMAGES_SUPPORTED,
825 BODY_IMAGES_NOT_SUPPORTED,
826 } body_images_supported_ = BODY_IMAGES_UNKNOWN;
Peter Beverloo 2017/05/10 12:54:40 It looks like you're considering base::Optional<bo
Tom (Use chromium acct) 2017/05/11 00:07:04 Done.
827
771 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); 828 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl);
772 }; 829 };
773 830
774 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() 831 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux()
775 : NotificationPlatformBridgeLinux(nullptr) {} 832 : NotificationPlatformBridgeLinux(nullptr) {}
776 833
777 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( 834 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux(
778 scoped_refptr<dbus::Bus> bus) 835 scoped_refptr<dbus::Bus> bus)
779 : impl_(new NotificationPlatformBridgeLinuxImpl(bus)) { 836 : impl_(new NotificationPlatformBridgeLinuxImpl(bus)) {
780 impl_->Init(); 837 impl_->Init();
(...skipping 25 matching lines...) Expand all
806 } 863 }
807 864
808 void NotificationPlatformBridgeLinux::SetReadyCallback( 865 void NotificationPlatformBridgeLinux::SetReadyCallback(
809 NotificationBridgeReadyCallback callback) { 866 NotificationBridgeReadyCallback callback) {
810 impl_->SetReadyCallback(std::move(callback)); 867 impl_->SetReadyCallback(std::move(callback));
811 } 868 }
812 869
813 void NotificationPlatformBridgeLinux::CleanUp() { 870 void NotificationPlatformBridgeLinux::CleanUp() {
814 impl_->CleanUp(); 871 impl_->CleanUp();
815 } 872 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698