| OLD | NEW |
| 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 23 matching lines...) Expand all Loading... |
| 34 #include "content/public/browser/browser_thread.h" | 34 #include "content/public/browser/browser_thread.h" |
| 35 #include "content/public/browser/notification_service.h" | 35 #include "content/public/browser/notification_service.h" |
| 36 #include "dbus/bus.h" | 36 #include "dbus/bus.h" |
| 37 #include "dbus/message.h" | 37 #include "dbus/message.h" |
| 38 #include "dbus/object_proxy.h" | 38 #include "dbus/object_proxy.h" |
| 39 #include "ui/base/l10n/l10n_util.h" | 39 #include "ui/base/l10n/l10n_util.h" |
| 40 #include "ui/gfx/image/image_skia.h" | 40 #include "ui/gfx/image/image_skia.h" |
| 41 | 41 |
| 42 namespace { | 42 namespace { |
| 43 | 43 |
| 44 // DBus name / path. |
| 44 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; | 45 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; |
| 45 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; | 46 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; |
| 46 | 47 |
| 48 // DBus methods. |
| 49 const char kMethodCloseNotification[] = "CloseNotification"; |
| 50 const char kMethodGetCapabilities[] = "GetCapabilities"; |
| 51 const char kMethodNotify[] = "Notify"; |
| 52 const char kMethodGetServerInformation[] = "GetServerInformation"; |
| 53 |
| 54 // DBus signals. |
| 55 const char kSignalActionInvoked[] = "ActionInvoked"; |
| 56 const char kSignalNotificationClosed[] = "NotificationClosed"; |
| 57 |
| 58 // Capabilities. |
| 59 const char kCapabilityActionIcons[] = "action-icons"; |
| 60 const char kCapabilityActions[] = "actions"; |
| 61 const char kCapabilityBody[] = "body"; |
| 62 const char kCapabilityBodyHyperlinks[] = "body-hyperlinks"; |
| 63 const char kCapabilityBodyImages[] = "body-images"; |
| 64 const char kCapabilityBodyMarkup[] = "body-markup"; |
| 65 const char kCapabilityIconMulti[] = "icon-multi"; |
| 66 const char kCapabilityIconStatic[] = "icon-static"; |
| 67 const char kCapabilityPersistence[] = "persistence"; |
| 68 const char kCapabilitySound[] = "sound"; |
| 69 |
| 70 // Button IDs. |
| 47 const char kDefaultButtonId[] = "default"; | 71 const char kDefaultButtonId[] = "default"; |
| 48 const char kSettingsButtonId[] = "settings"; | 72 const char kSettingsButtonId[] = "settings"; |
| 49 | 73 |
| 50 // The values in this enumeration correspond to those of the | 74 // The values in this enumeration correspond to those of the |
| 51 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so | 75 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so |
| 52 // the ordering should not be changed. New error codes should be | 76 // the ordering should not be changed. New error codes should be |
| 53 // added at the end, before NUM_ITEMS. | 77 // added at the end, before NUM_ITEMS. |
| 54 enum class ConnectionInitializationStatusCode { | 78 enum class ConnectionInitializationStatusCode { |
| 55 SUCCESS = 0, | 79 SUCCESS = 0, |
| 56 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1, | 80 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1, |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 bus_->GetObjectProxy(kFreedesktopNotificationsName, | 367 bus_->GetObjectProxy(kFreedesktopNotificationsName, |
| 344 dbus::ObjectPath(kFreedesktopNotificationsPath)); | 368 dbus::ObjectPath(kFreedesktopNotificationsPath)); |
| 345 if (!notification_proxy_) { | 369 if (!notification_proxy_) { |
| 346 OnConnectionInitializationFinishedOnTaskRunner( | 370 OnConnectionInitializationFinishedOnTaskRunner( |
| 347 ConnectionInitializationStatusCode:: | 371 ConnectionInitializationStatusCode:: |
| 348 NATIVE_NOTIFICATIONS_NOT_SUPPORTED); | 372 NATIVE_NOTIFICATIONS_NOT_SUPPORTED); |
| 349 return; | 373 return; |
| 350 } | 374 } |
| 351 | 375 |
| 352 dbus::MethodCall get_capabilities_call(kFreedesktopNotificationsName, | 376 dbus::MethodCall get_capabilities_call(kFreedesktopNotificationsName, |
| 353 "GetCapabilities"); | 377 kMethodGetCapabilities); |
| 354 std::unique_ptr<dbus::Response> capabilities_response = | 378 std::unique_ptr<dbus::Response> capabilities_response = |
| 355 notification_proxy_->CallMethodAndBlock( | 379 notification_proxy_->CallMethodAndBlock( |
| 356 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 380 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 357 if (capabilities_response) { | 381 if (capabilities_response) { |
| 358 dbus::MessageReader reader(capabilities_response.get()); | 382 dbus::MessageReader reader(capabilities_response.get()); |
| 359 std::vector<std::string> capabilities; | 383 std::vector<std::string> capabilities; |
| 360 reader.PopArrayOfStrings(&capabilities); | 384 reader.PopArrayOfStrings(&capabilities); |
| 361 for (const std::string& capability : capabilities) | 385 for (const std::string& capability : capabilities) |
| 362 capabilities_.insert(capability); | 386 capabilities_.insert(capability); |
| 363 } | 387 } |
| 364 RecordMetricsForCapabilities(); | 388 RecordMetricsForCapabilities(); |
| 365 | 389 |
| 366 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName, | 390 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName, |
| 367 "GetServerInformation"); | 391 kMethodGetServerInformation); |
| 368 std::unique_ptr<dbus::Response> server_information_response = | 392 std::unique_ptr<dbus::Response> server_information_response = |
| 369 notification_proxy_->CallMethodAndBlock( | 393 notification_proxy_->CallMethodAndBlock( |
| 370 &get_server_information_call, | 394 &get_server_information_call, |
| 371 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 395 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 372 if (server_information_response) { | 396 if (server_information_response) { |
| 373 dbus::MessageReader reader(server_information_response.get()); | 397 dbus::MessageReader reader(server_information_response.get()); |
| 374 std::string spec_version; | 398 std::string spec_version; |
| 375 reader.PopString(&spec_version); // name | 399 reader.PopString(&spec_version); // name |
| 376 reader.PopString(&spec_version); // vendor | 400 reader.PopString(&spec_version); // vendor |
| 377 reader.PopString(&spec_version); // version | 401 reader.PopString(&spec_version); // version |
| 378 reader.PopString(&spec_version); // spec_version | 402 reader.PopString(&spec_version); // spec_version |
| 379 spec_version_ = base::Version(spec_version); | 403 spec_version_ = base::Version(spec_version); |
| 380 } | 404 } |
| 381 // The minimum supported spec version is 1.1, because this was the | 405 // The minimum supported spec version is 1.1, because this was the |
| 382 // version that added image hints. | 406 // version that added image hints. |
| 383 if (!spec_version_.IsValid() || | 407 if (!spec_version_.IsValid() || |
| 384 spec_version_ < base::Version(std::vector<uint32_t>{1, 1})) { | 408 spec_version_ < base::Version(std::vector<uint32_t>{1, 1})) { |
| 385 OnConnectionInitializationFinishedOnTaskRunner( | 409 OnConnectionInitializationFinishedOnTaskRunner( |
| 386 ConnectionInitializationStatusCode::INCOMPATIBLE_SPEC_VERSION); | 410 ConnectionInitializationStatusCode::INCOMPATIBLE_SPEC_VERSION); |
| 387 return; | 411 return; |
| 388 } | 412 } |
| 389 | 413 |
| 390 connected_signals_barrier_ = base::BarrierClosure( | 414 connected_signals_barrier_ = base::BarrierClosure( |
| 391 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: | 415 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: |
| 392 OnConnectionInitializationFinishedOnTaskRunner, | 416 OnConnectionInitializationFinishedOnTaskRunner, |
| 393 this, ConnectionInitializationStatusCode::SUCCESS)); | 417 this, ConnectionInitializationStatusCode::SUCCESS)); |
| 394 notification_proxy_->ConnectToSignal( | 418 notification_proxy_->ConnectToSignal( |
| 395 kFreedesktopNotificationsName, "ActionInvoked", | 419 kFreedesktopNotificationsName, kSignalActionInvoked, |
| 396 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), | 420 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), |
| 397 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 421 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 398 this)); | 422 this)); |
| 399 notification_proxy_->ConnectToSignal( | 423 notification_proxy_->ConnectToSignal( |
| 400 kFreedesktopNotificationsName, "NotificationClosed", | 424 kFreedesktopNotificationsName, kSignalNotificationClosed, |
| 401 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, | 425 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, |
| 402 this), | 426 this), |
| 403 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 427 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 404 this)); | 428 this)); |
| 405 } | 429 } |
| 406 | 430 |
| 407 void CleanUpOnTaskRunner() { | 431 void CleanUpOnTaskRunner() { |
| 408 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 432 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 409 if (bus_) | 433 if (bus_) |
| 410 bus_->ShutdownAndBlock(); | 434 bus_->ShutdownAndBlock(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 427 data->notification_type = notification_type; | 451 data->notification_type = notification_type; |
| 428 data->resource_files.clear(); | 452 data->resource_files.clear(); |
| 429 } else { | 453 } else { |
| 430 // Send the notification for the first time. | 454 // Send the notification for the first time. |
| 431 data = | 455 data = |
| 432 new NotificationData(notification_type, notification_id, profile_id, | 456 new NotificationData(notification_type, notification_id, profile_id, |
| 433 is_incognito, notification->origin_url()); | 457 is_incognito, notification->origin_url()); |
| 434 notifications_.emplace(data, base::WrapUnique(data)); | 458 notifications_.emplace(data, base::WrapUnique(data)); |
| 435 } | 459 } |
| 436 | 460 |
| 437 dbus::MethodCall method_call(kFreedesktopNotificationsName, "Notify"); | 461 dbus::MethodCall method_call(kFreedesktopNotificationsName, kMethodNotify); |
| 438 dbus::MessageWriter writer(&method_call); | 462 dbus::MessageWriter writer(&method_call); |
| 439 | 463 |
| 440 // app_name passed implicitly via desktop-entry. | 464 // app_name passed implicitly via desktop-entry. |
| 441 writer.AppendString(""); | 465 writer.AppendString(""); |
| 442 | 466 |
| 443 writer.AppendUint32(data->dbus_id); | 467 writer.AppendUint32(data->dbus_id); |
| 444 | 468 |
| 445 // app_icon passed implicitly via desktop-entry. | 469 // app_icon passed implicitly via desktop-entry. |
| 446 writer.AppendString(""); | 470 writer.AppendString(""); |
| 447 | 471 |
| 448 writer.AppendString( | 472 writer.AppendString( |
| 449 base::UTF16ToUTF8(CreateNotificationTitle(*notification))); | 473 base::UTF16ToUTF8(CreateNotificationTitle(*notification))); |
| 450 | 474 |
| 451 std::string body; | 475 std::string body; |
| 452 if (base::ContainsKey(capabilities_, "body")) { | 476 if (base::ContainsKey(capabilities_, kCapabilityBody)) { |
| 453 body = base::UTF16ToUTF8(notification->message()); | 477 body = base::UTF16ToUTF8(notification->message()); |
| 454 if (base::ContainsKey(capabilities_, "body-markup")) { | 478 if (base::ContainsKey(capabilities_, kCapabilityBodyMarkup)) { |
| 455 base::ReplaceSubstringsAfterOffset(&body, 0, "&", "&"); | 479 base::ReplaceSubstringsAfterOffset(&body, 0, "&", "&"); |
| 456 base::ReplaceSubstringsAfterOffset(&body, 0, "<", "<"); | 480 base::ReplaceSubstringsAfterOffset(&body, 0, "<", "<"); |
| 457 base::ReplaceSubstringsAfterOffset(&body, 0, ">", ">"); | 481 base::ReplaceSubstringsAfterOffset(&body, 0, ">", ">"); |
| 458 } | 482 } |
| 459 } | 483 } |
| 460 writer.AppendString(body); | 484 writer.AppendString(body); |
| 461 | 485 |
| 462 // Even-indexed elements in this vector are action IDs passed back to | 486 // Even-indexed elements in this vector are action IDs passed back to |
| 463 // us in OnActionInvoked(). Odd-indexed ones contain the button text. | 487 // us in OnActionInvoked(). Odd-indexed ones contain the button text. |
| 464 std::vector<std::string> actions; | 488 std::vector<std::string> actions; |
| 465 if (base::ContainsKey(capabilities_, "actions")) { | 489 if (base::ContainsKey(capabilities_, kCapabilityActions)) { |
| 466 data->action_start = data->action_end; | 490 data->action_start = data->action_end; |
| 467 for (const auto& button_info : notification->buttons()) { | 491 for (const auto& button_info : notification->buttons()) { |
| 468 // FDO notification buttons can contain either an icon or a label, | 492 // FDO notification buttons can contain either an icon or a label, |
| 469 // but not both, and the type of all buttons must be the same (all | 493 // but not both, and the type of all buttons must be the same (all |
| 470 // labels or all icons), so always use labels. | 494 // labels or all icons), so always use labels. |
| 471 const std::string id = base::SizeTToString(data->action_end++); | 495 const std::string id = base::SizeTToString(data->action_end++); |
| 472 const std::string label = base::UTF16ToUTF8(button_info.title); | 496 const std::string label = base::UTF16ToUTF8(button_info.title); |
| 473 actions.push_back(id); | 497 actions.push_back(id); |
| 474 actions.push_back(label); | 498 actions.push_back(label); |
| 475 } | 499 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 // Makes the "CloseNotification" call to D-Bus. | 567 // Makes the "CloseNotification" call to D-Bus. |
| 544 void CloseOnTaskRunner(const std::string& profile_id, | 568 void CloseOnTaskRunner(const std::string& profile_id, |
| 545 const std::string& notification_id) { | 569 const std::string& notification_id) { |
| 546 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 570 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 547 std::vector<NotificationData*> to_erase; | 571 std::vector<NotificationData*> to_erase; |
| 548 for (const auto& pair : notifications_) { | 572 for (const auto& pair : notifications_) { |
| 549 NotificationData* data = pair.first; | 573 NotificationData* data = pair.first; |
| 550 if (data->notification_id == notification_id && | 574 if (data->notification_id == notification_id && |
| 551 data->profile_id == profile_id) { | 575 data->profile_id == profile_id) { |
| 552 dbus::MethodCall method_call(kFreedesktopNotificationsName, | 576 dbus::MethodCall method_call(kFreedesktopNotificationsName, |
| 553 "CloseNotification"); | 577 kMethodCloseNotification); |
| 554 dbus::MessageWriter writer(&method_call); | 578 dbus::MessageWriter writer(&method_call); |
| 555 writer.AppendUint32(data->dbus_id); | 579 writer.AppendUint32(data->dbus_id); |
| 556 notification_proxy_->CallMethodAndBlock( | 580 notification_proxy_->CallMethodAndBlock( |
| 557 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 581 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 558 to_erase.push_back(data); | 582 to_erase.push_back(data); |
| 559 } | 583 } |
| 560 } | 584 } |
| 561 for (NotificationData* data : to_erase) | 585 for (NotificationData* data : to_erase) |
| 562 notifications_.erase(data); | 586 notifications_.erase(data); |
| 563 } | 587 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 OnConnectionInitializationFinishedOnTaskRunner( | 717 OnConnectionInitializationFinishedOnTaskRunner( |
| 694 ConnectionInitializationStatusCode::COULD_NOT_CONNECT_TO_SIGNALS); | 718 ConnectionInitializationStatusCode::COULD_NOT_CONNECT_TO_SIGNALS); |
| 695 return; | 719 return; |
| 696 } | 720 } |
| 697 connected_signals_barrier_.Run(); | 721 connected_signals_barrier_.Run(); |
| 698 } | 722 } |
| 699 | 723 |
| 700 void RecordMetricsForCapabilities() { | 724 void RecordMetricsForCapabilities() { |
| 701 // Histogram macros must be called with the same name for each | 725 // Histogram macros must be called with the same name for each |
| 702 // callsite, so we can't roll the below into a nice loop. | 726 // callsite, so we can't roll the below into a nice loop. |
| 703 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.ActionIcons", | 727 UMA_HISTOGRAM_BOOLEAN( |
| 704 base::ContainsKey(capabilities_, "action-icons")); | 728 "Notifications.Freedesktop.Capabilities.ActionIcons", |
| 729 base::ContainsKey(capabilities_, kCapabilityActionIcons)); |
| 705 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Actions", | 730 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Actions", |
| 706 base::ContainsKey(capabilities_, "actions")); | 731 base::ContainsKey(capabilities_, kCapabilityActions)); |
| 707 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Body", | 732 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Body", |
| 708 base::ContainsKey(capabilities_, "body")); | 733 base::ContainsKey(capabilities_, kCapabilityBody)); |
| 709 UMA_HISTOGRAM_BOOLEAN( | 734 UMA_HISTOGRAM_BOOLEAN( |
| 710 "Notifications.Freedesktop.Capabilities.BodyHyperlinks", | 735 "Notifications.Freedesktop.Capabilities.BodyHyperlinks", |
| 711 base::ContainsKey(capabilities_, "body-hyperlinks")); | 736 base::ContainsKey(capabilities_, kCapabilityBodyHyperlinks)); |
| 712 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.BodyImages", | 737 UMA_HISTOGRAM_BOOLEAN( |
| 713 base::ContainsKey(capabilities_, "body-images")); | 738 "Notifications.Freedesktop.Capabilities.BodyImages", |
| 714 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.BodyMarkup", | 739 base::ContainsKey(capabilities_, kCapabilityBodyImages)); |
| 715 base::ContainsKey(capabilities_, "body-markup")); | 740 UMA_HISTOGRAM_BOOLEAN( |
| 716 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.IconMulti", | 741 "Notifications.Freedesktop.Capabilities.BodyMarkup", |
| 717 base::ContainsKey(capabilities_, "icon-multi")); | 742 base::ContainsKey(capabilities_, kCapabilityBodyMarkup)); |
| 718 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.IconStatic", | 743 UMA_HISTOGRAM_BOOLEAN( |
| 719 base::ContainsKey(capabilities_, "icon-static")); | 744 "Notifications.Freedesktop.Capabilities.IconMulti", |
| 720 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Persistence", | 745 base::ContainsKey(capabilities_, kCapabilityIconMulti)); |
| 721 base::ContainsKey(capabilities_, "persistence")); | 746 UMA_HISTOGRAM_BOOLEAN( |
| 747 "Notifications.Freedesktop.Capabilities.IconStatic", |
| 748 base::ContainsKey(capabilities_, kCapabilityIconStatic)); |
| 749 UMA_HISTOGRAM_BOOLEAN( |
| 750 "Notifications.Freedesktop.Capabilities.Persistence", |
| 751 base::ContainsKey(capabilities_, kCapabilityPersistence)); |
| 722 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Sound", | 752 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Sound", |
| 723 base::ContainsKey(capabilities_, "sound")); | 753 base::ContainsKey(capabilities_, kCapabilitySound)); |
| 724 } | 754 } |
| 725 | 755 |
| 726 ////////////////////////////////////////////////////////////////////////////// | 756 ////////////////////////////////////////////////////////////////////////////// |
| 727 // Members used only on the UI thread. | 757 // Members used only on the UI thread. |
| 728 | 758 |
| 729 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 759 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 730 | 760 |
| 731 content::NotificationRegistrar registrar_; | 761 content::NotificationRegistrar registrar_; |
| 732 | 762 |
| 733 // State necessary for OnConnectionInitializationFinished() and | 763 // State necessary for OnConnectionInitializationFinished() and |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 } | 824 } |
| 795 | 825 |
| 796 void NotificationPlatformBridgeLinux::SetReadyCallback( | 826 void NotificationPlatformBridgeLinux::SetReadyCallback( |
| 797 NotificationBridgeReadyCallback callback) { | 827 NotificationBridgeReadyCallback callback) { |
| 798 impl_->SetReadyCallback(std::move(callback)); | 828 impl_->SetReadyCallback(std::move(callback)); |
| 799 } | 829 } |
| 800 | 830 |
| 801 void NotificationPlatformBridgeLinux::CleanUp() { | 831 void NotificationPlatformBridgeLinux::CleanUp() { |
| 802 impl_->CleanUp(); | 832 impl_->CleanUp(); |
| 803 } | 833 } |
| OLD | NEW |