Chromium Code Reviews| 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 20 matching lines...) Expand all Loading... | |
| 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 "ui/gfx/image/image_skia.h" | 37 #include "ui/gfx/image/image_skia.h" |
| 38 | 38 |
| 39 namespace { | 39 namespace { |
| 40 | 40 |
| 41 // DBus names, paths, methods, and signals. | |
|
Tom Anderson
2017/05/10 06:11:48
nit: give the methods and signals their own sectio
Lei Zhang
2017/05/10 21:11:56
Done.
| |
| 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"; |
| 44 const char kMethodCloseNotification[] = "CloseNotification"; | |
| 45 const char kMethodGetCapabilities[] = "GetCapabilities"; | |
| 46 const char kMethodNotify[] = "Notify"; | |
| 47 const char kMethodGetServerInformation[] = "GetServerInformation"; | |
| 48 const char kSignalActionInvoked[] = "ActionInvoked"; | |
| 49 const char kSignalNotificationClosed[] = "NotificationClosed"; | |
| 43 | 50 |
| 51 // Capabilities | |
| 52 const char kCapabilityActionIcons[] = "action-icons"; | |
| 53 const char kCapabilityActions[] = "actions"; | |
| 54 const char kCapabilityBody[] = "body"; | |
| 55 const char kCapabilityBodyHyperlinks[] = "body-hyperlinks"; | |
| 56 const char kCapabilityBodyImages[] = "body-images"; | |
| 57 const char kCapabilityBodyMarkup[] = "body-markup"; | |
| 58 const char kCapabilityIconMulti[] = "icon-multi"; | |
| 59 const char kCapabilityIconStatic[] = "icon-static"; | |
| 60 const char kCapabilityPersistence[] = "persistence"; | |
| 61 const char kCapabilitySound[] = "sound"; | |
| 62 | |
| 63 // Button IDs. | |
| 44 const char kDefaultButtonId[] = "default"; | 64 const char kDefaultButtonId[] = "default"; |
| 45 const char kSettingsButtonId[] = "settings"; | 65 const char kSettingsButtonId[] = "settings"; |
| 46 | 66 |
| 47 // The values in this enumeration correspond to those of the | 67 // The values in this enumeration correspond to those of the |
| 48 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so | 68 // Linux.NotificationPlatformBridge.InitializationStatus histogram, so |
| 49 // the ordering should not be changed. New error codes should be | 69 // the ordering should not be changed. New error codes should be |
| 50 // added at the end, before NUM_ITEMS. | 70 // added at the end, before NUM_ITEMS. |
| 51 enum class ConnectionInitializationStatusCode { | 71 enum class ConnectionInitializationStatusCode { |
| 52 SUCCESS = 0, | 72 SUCCESS = 0, |
| 53 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1, | 73 NATIVE_NOTIFICATIONS_NOT_SUPPORTED = 1, |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 bus_->GetObjectProxy(kFreedesktopNotificationsName, | 350 bus_->GetObjectProxy(kFreedesktopNotificationsName, |
| 331 dbus::ObjectPath(kFreedesktopNotificationsPath)); | 351 dbus::ObjectPath(kFreedesktopNotificationsPath)); |
| 332 if (!notification_proxy_) { | 352 if (!notification_proxy_) { |
| 333 OnConnectionInitializationFinishedOnTaskRunner( | 353 OnConnectionInitializationFinishedOnTaskRunner( |
| 334 ConnectionInitializationStatusCode:: | 354 ConnectionInitializationStatusCode:: |
| 335 NATIVE_NOTIFICATIONS_NOT_SUPPORTED); | 355 NATIVE_NOTIFICATIONS_NOT_SUPPORTED); |
| 336 return; | 356 return; |
| 337 } | 357 } |
| 338 | 358 |
| 339 dbus::MethodCall get_capabilities_call(kFreedesktopNotificationsName, | 359 dbus::MethodCall get_capabilities_call(kFreedesktopNotificationsName, |
| 340 "GetCapabilities"); | 360 kMethodGetCapabilities); |
| 341 std::unique_ptr<dbus::Response> capabilities_response = | 361 std::unique_ptr<dbus::Response> capabilities_response = |
| 342 notification_proxy_->CallMethodAndBlock( | 362 notification_proxy_->CallMethodAndBlock( |
| 343 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 363 &get_capabilities_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 344 if (capabilities_response) { | 364 if (capabilities_response) { |
| 345 dbus::MessageReader reader(capabilities_response.get()); | 365 dbus::MessageReader reader(capabilities_response.get()); |
| 346 std::vector<std::string> capabilities; | 366 std::vector<std::string> capabilities; |
| 347 reader.PopArrayOfStrings(&capabilities); | 367 reader.PopArrayOfStrings(&capabilities); |
| 348 for (const std::string& capability : capabilities) | 368 for (const std::string& capability : capabilities) |
| 349 capabilities_.insert(capability); | 369 capabilities_.insert(capability); |
| 350 } | 370 } |
| 351 RecordMetricsForCapabilities(); | 371 RecordMetricsForCapabilities(); |
| 352 | 372 |
| 353 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName, | 373 dbus::MethodCall get_server_information_call(kFreedesktopNotificationsName, |
| 354 "GetServerInformation"); | 374 kMethodGetServerInformation); |
| 355 std::unique_ptr<dbus::Response> server_information_response = | 375 std::unique_ptr<dbus::Response> server_information_response = |
| 356 notification_proxy_->CallMethodAndBlock( | 376 notification_proxy_->CallMethodAndBlock( |
| 357 &get_server_information_call, | 377 &get_server_information_call, |
| 358 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 378 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 359 if (server_information_response) { | 379 if (server_information_response) { |
| 360 dbus::MessageReader reader(server_information_response.get()); | 380 dbus::MessageReader reader(server_information_response.get()); |
| 361 std::string spec_version; | 381 std::string spec_version; |
| 362 reader.PopString(&spec_version); // name | 382 reader.PopString(&spec_version); // name |
| 363 reader.PopString(&spec_version); // vendor | 383 reader.PopString(&spec_version); // vendor |
| 364 reader.PopString(&spec_version); // version | 384 reader.PopString(&spec_version); // version |
| 365 reader.PopString(&spec_version); // spec_version | 385 reader.PopString(&spec_version); // spec_version |
| 366 spec_version_ = base::Version(spec_version); | 386 spec_version_ = base::Version(spec_version); |
| 367 } | 387 } |
| 368 // The minimum supported spec version is 1.1, because this was the | 388 // The minimum supported spec version is 1.1, because this was the |
| 369 // version that added image hints. | 389 // version that added image hints. |
| 370 if (!spec_version_.IsValid() || | 390 if (!spec_version_.IsValid() || |
| 371 spec_version_ < base::Version(std::vector<uint32_t>{1, 1})) { | 391 spec_version_ < base::Version(std::vector<uint32_t>{1, 1})) { |
| 372 OnConnectionInitializationFinishedOnTaskRunner( | 392 OnConnectionInitializationFinishedOnTaskRunner( |
| 373 ConnectionInitializationStatusCode::INCOMPATIBLE_SPEC_VERSION); | 393 ConnectionInitializationStatusCode::INCOMPATIBLE_SPEC_VERSION); |
| 374 return; | 394 return; |
| 375 } | 395 } |
| 376 | 396 |
| 377 connected_signals_barrier_ = base::BarrierClosure( | 397 connected_signals_barrier_ = base::BarrierClosure( |
| 378 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: | 398 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: |
| 379 OnConnectionInitializationFinishedOnTaskRunner, | 399 OnConnectionInitializationFinishedOnTaskRunner, |
| 380 this, ConnectionInitializationStatusCode::SUCCESS)); | 400 this, ConnectionInitializationStatusCode::SUCCESS)); |
| 381 notification_proxy_->ConnectToSignal( | 401 notification_proxy_->ConnectToSignal( |
| 382 kFreedesktopNotificationsName, "ActionInvoked", | 402 kFreedesktopNotificationsName, kSignalActionInvoked, |
| 383 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), | 403 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), |
| 384 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 404 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 385 this)); | 405 this)); |
| 386 notification_proxy_->ConnectToSignal( | 406 notification_proxy_->ConnectToSignal( |
| 387 kFreedesktopNotificationsName, "NotificationClosed", | 407 kFreedesktopNotificationsName, kSignalNotificationClosed, |
| 388 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, | 408 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, |
| 389 this), | 409 this), |
| 390 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 410 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 391 this)); | 411 this)); |
| 392 } | 412 } |
| 393 | 413 |
| 394 void CleanUpOnTaskRunner() { | 414 void CleanUpOnTaskRunner() { |
| 395 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 415 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 396 if (bus_) | 416 if (bus_) |
| 397 bus_->ShutdownAndBlock(); | 417 bus_->ShutdownAndBlock(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 414 data->notification_type = notification_type; | 434 data->notification_type = notification_type; |
| 415 data->resource_files.clear(); | 435 data->resource_files.clear(); |
| 416 } else { | 436 } else { |
| 417 // Send the notification for the first time. | 437 // Send the notification for the first time. |
| 418 data = | 438 data = |
| 419 new NotificationData(notification_type, notification_id, profile_id, | 439 new NotificationData(notification_type, notification_id, profile_id, |
| 420 is_incognito, notification->origin_url()); | 440 is_incognito, notification->origin_url()); |
| 421 notifications_.emplace(data, base::WrapUnique(data)); | 441 notifications_.emplace(data, base::WrapUnique(data)); |
| 422 } | 442 } |
| 423 | 443 |
| 424 dbus::MethodCall method_call(kFreedesktopNotificationsName, "Notify"); | 444 dbus::MethodCall method_call(kFreedesktopNotificationsName, kMethodNotify); |
| 425 dbus::MessageWriter writer(&method_call); | 445 dbus::MessageWriter writer(&method_call); |
| 426 | 446 |
| 427 // app_name passed implicitly via desktop-entry. | 447 // app_name passed implicitly via desktop-entry. |
| 428 writer.AppendString(""); | 448 writer.AppendString(""); |
| 429 | 449 |
| 430 writer.AppendUint32(data->dbus_id); | 450 writer.AppendUint32(data->dbus_id); |
| 431 | 451 |
| 432 // app_icon passed implicitly via desktop-entry. | 452 // app_icon passed implicitly via desktop-entry. |
| 433 writer.AppendString(""); | 453 writer.AppendString(""); |
| 434 | 454 |
| 435 writer.AppendString(base::UTF16ToUTF8(notification->title())); | 455 writer.AppendString(base::UTF16ToUTF8(notification->title())); |
| 436 | 456 |
| 437 std::string body; | 457 std::string body; |
| 438 if (base::ContainsKey(capabilities_, "body")) { | 458 if (base::ContainsKey(capabilities_, kCapabilityBody)) { |
| 439 body = base::UTF16ToUTF8(notification->message()); | 459 body = base::UTF16ToUTF8(notification->message()); |
| 440 if (base::ContainsKey(capabilities_, "body-markup")) { | 460 if (base::ContainsKey(capabilities_, kCapabilityBodyMarkup)) { |
| 441 base::ReplaceSubstringsAfterOffset(&body, 0, "&", "&"); | 461 base::ReplaceSubstringsAfterOffset(&body, 0, "&", "&"); |
| 442 base::ReplaceSubstringsAfterOffset(&body, 0, "<", "<"); | 462 base::ReplaceSubstringsAfterOffset(&body, 0, "<", "<"); |
| 443 base::ReplaceSubstringsAfterOffset(&body, 0, ">", ">"); | 463 base::ReplaceSubstringsAfterOffset(&body, 0, ">", ">"); |
| 444 } | 464 } |
| 445 } | 465 } |
| 446 writer.AppendString(body); | 466 writer.AppendString(body); |
| 447 | 467 |
| 448 // Even-indexed elements in this vector are action IDs passed back to | 468 // Even-indexed elements in this vector are action IDs passed back to |
| 449 // us in OnActionInvoked(). Odd-indexed ones contain the button text. | 469 // us in OnActionInvoked(). Odd-indexed ones contain the button text. |
| 450 std::vector<std::string> actions; | 470 std::vector<std::string> actions; |
| 451 if (base::ContainsKey(capabilities_, "actions")) { | 471 if (base::ContainsKey(capabilities_, kCapabilityActions)) { |
| 452 data->action_start = data->action_end; | 472 data->action_start = data->action_end; |
| 453 for (const auto& button_info : notification->buttons()) { | 473 for (const auto& button_info : notification->buttons()) { |
| 454 // FDO notification buttons can contain either an icon or a label, | 474 // FDO notification buttons can contain either an icon or a label, |
| 455 // but not both, and the type of all buttons must be the same (all | 475 // but not both, and the type of all buttons must be the same (all |
| 456 // labels or all icons), so always use labels. | 476 // labels or all icons), so always use labels. |
| 457 const std::string id = base::SizeTToString(data->action_end++); | 477 const std::string id = base::SizeTToString(data->action_end++); |
| 458 const std::string label = base::UTF16ToUTF8(button_info.title); | 478 const std::string label = base::UTF16ToUTF8(button_info.title); |
| 459 actions.push_back(id); | 479 actions.push_back(id); |
| 460 actions.push_back(label); | 480 actions.push_back(label); |
| 461 } | 481 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 // Makes the "CloseNotification" call to D-Bus. | 549 // Makes the "CloseNotification" call to D-Bus. |
| 530 void CloseOnTaskRunner(const std::string& profile_id, | 550 void CloseOnTaskRunner(const std::string& profile_id, |
| 531 const std::string& notification_id) { | 551 const std::string& notification_id) { |
| 532 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 552 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 533 std::vector<NotificationData*> to_erase; | 553 std::vector<NotificationData*> to_erase; |
| 534 for (const auto& pair : notifications_) { | 554 for (const auto& pair : notifications_) { |
| 535 NotificationData* data = pair.first; | 555 NotificationData* data = pair.first; |
| 536 if (data->notification_id == notification_id && | 556 if (data->notification_id == notification_id && |
| 537 data->profile_id == profile_id) { | 557 data->profile_id == profile_id) { |
| 538 dbus::MethodCall method_call(kFreedesktopNotificationsName, | 558 dbus::MethodCall method_call(kFreedesktopNotificationsName, |
| 539 "CloseNotification"); | 559 kMethodCloseNotification); |
| 540 dbus::MessageWriter writer(&method_call); | 560 dbus::MessageWriter writer(&method_call); |
| 541 writer.AppendUint32(data->dbus_id); | 561 writer.AppendUint32(data->dbus_id); |
| 542 notification_proxy_->CallMethodAndBlock( | 562 notification_proxy_->CallMethodAndBlock( |
| 543 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 563 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 544 to_erase.push_back(data); | 564 to_erase.push_back(data); |
| 545 } | 565 } |
| 546 } | 566 } |
| 547 for (NotificationData* data : to_erase) | 567 for (NotificationData* data : to_erase) |
| 548 notifications_.erase(data); | 568 notifications_.erase(data); |
| 549 } | 569 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 679 OnConnectionInitializationFinishedOnTaskRunner( | 699 OnConnectionInitializationFinishedOnTaskRunner( |
| 680 ConnectionInitializationStatusCode::COULD_NOT_CONNECT_TO_SIGNALS); | 700 ConnectionInitializationStatusCode::COULD_NOT_CONNECT_TO_SIGNALS); |
| 681 return; | 701 return; |
| 682 } | 702 } |
| 683 connected_signals_barrier_.Run(); | 703 connected_signals_barrier_.Run(); |
| 684 } | 704 } |
| 685 | 705 |
| 686 void RecordMetricsForCapabilities() { | 706 void RecordMetricsForCapabilities() { |
| 687 // Histogram macros must be called with the same name for each | 707 // Histogram macros must be called with the same name for each |
| 688 // callsite, so we can't roll the below into a nice loop. | 708 // callsite, so we can't roll the below into a nice loop. |
| 689 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.ActionIcons", | 709 UMA_HISTOGRAM_BOOLEAN( |
| 690 base::ContainsKey(capabilities_, "action-icons")); | 710 "Notifications.Freedesktop.Capabilities.ActionIcons", |
| 711 base::ContainsKey(capabilities_, kCapabilityActionIcons)); | |
| 691 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Actions", | 712 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Actions", |
| 692 base::ContainsKey(capabilities_, "actions")); | 713 base::ContainsKey(capabilities_, kCapabilityActions)); |
| 693 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Body", | 714 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Body", |
| 694 base::ContainsKey(capabilities_, "body")); | 715 base::ContainsKey(capabilities_, kCapabilityBody)); |
| 695 UMA_HISTOGRAM_BOOLEAN( | 716 UMA_HISTOGRAM_BOOLEAN( |
| 696 "Notifications.Freedesktop.Capabilities.BodyHyperlinks", | 717 "Notifications.Freedesktop.Capabilities.BodyHyperlinks", |
| 697 base::ContainsKey(capabilities_, "body-hyperlinks")); | 718 base::ContainsKey(capabilities_, kCapabilityBodyHyperlinks)); |
| 698 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.BodyImages", | 719 UMA_HISTOGRAM_BOOLEAN( |
| 699 base::ContainsKey(capabilities_, "body-images")); | 720 "Notifications.Freedesktop.Capabilities.BodyImages", |
| 700 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.BodyMarkup", | 721 base::ContainsKey(capabilities_, kCapabilityBodyImages)); |
| 701 base::ContainsKey(capabilities_, "body-markup")); | 722 UMA_HISTOGRAM_BOOLEAN( |
| 702 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.IconMulti", | 723 "Notifications.Freedesktop.Capabilities.BodyMarkup", |
| 703 base::ContainsKey(capabilities_, "icon-multi")); | 724 base::ContainsKey(capabilities_, kCapabilityBodyMarkup)); |
| 704 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.IconStatic", | 725 UMA_HISTOGRAM_BOOLEAN( |
| 705 base::ContainsKey(capabilities_, "icon-static")); | 726 "Notifications.Freedesktop.Capabilities.IconMulti", |
| 706 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Persistence", | 727 base::ContainsKey(capabilities_, kCapabilityIconMulti)); |
| 707 base::ContainsKey(capabilities_, "persistence")); | 728 UMA_HISTOGRAM_BOOLEAN( |
| 729 "Notifications.Freedesktop.Capabilities.IconStatic", | |
| 730 base::ContainsKey(capabilities_, kCapabilityIconStatic)); | |
| 731 UMA_HISTOGRAM_BOOLEAN( | |
| 732 "Notifications.Freedesktop.Capabilities.Persistence", | |
| 733 base::ContainsKey(capabilities_, kCapabilityPersistence)); | |
| 708 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Sound", | 734 UMA_HISTOGRAM_BOOLEAN("Notifications.Freedesktop.Capabilities.Sound", |
| 709 base::ContainsKey(capabilities_, "sound")); | 735 base::ContainsKey(capabilities_, kCapabilitySound)); |
| 710 } | 736 } |
| 711 | 737 |
| 712 ////////////////////////////////////////////////////////////////////////////// | 738 ////////////////////////////////////////////////////////////////////////////// |
| 713 // Members used only on the UI thread. | 739 // Members used only on the UI thread. |
| 714 | 740 |
| 715 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 741 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 716 | 742 |
| 717 content::NotificationRegistrar registrar_; | 743 content::NotificationRegistrar registrar_; |
| 718 | 744 |
| 719 // State necessary for OnConnectionInitializationFinished() and | 745 // State necessary for OnConnectionInitializationFinished() and |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 } | 806 } |
| 781 | 807 |
| 782 void NotificationPlatformBridgeLinux::SetReadyCallback( | 808 void NotificationPlatformBridgeLinux::SetReadyCallback( |
| 783 NotificationBridgeReadyCallback callback) { | 809 NotificationBridgeReadyCallback callback) { |
| 784 impl_->SetReadyCallback(std::move(callback)); | 810 impl_->SetReadyCallback(std::move(callback)); |
| 785 } | 811 } |
| 786 | 812 |
| 787 void NotificationPlatformBridgeLinux::CleanUp() { | 813 void NotificationPlatformBridgeLinux::CleanUp() { |
| 788 impl_->CleanUp(); | 814 impl_->CleanUp(); |
| 789 } | 815 } |
| OLD | NEW |