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

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

Issue 2805543005: Linux native notifications: Handle clicks and closes (Closed)
Patch Set: Address peter@'s comments Created 3 years, 8 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
« no previous file with comments | « chrome/browser/notifications/notification_platform_bridge_linux.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 f19184ac8c78ff35c57e1baf256a8a3c2d51b8a0..4eb07fdd2f154f463ebcd9a51f144cae81008876 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -8,15 +8,26 @@
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
+#include "base/strings/nullable_string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/notifications/native_notification_display_service.h"
#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/browser/profiles/profile_manager.h"
namespace {
const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications";
const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications";
+void AddActionToNotification(GVariantBuilder* actions_builder,
+ const char* action_id,
+ const char* button_label) {
+ g_variant_builder_add(actions_builder, "s", action_id);
+ g_variant_builder_add(actions_builder, "s", button_label);
+}
+
// Callback used by GLib when the "Notify" message completes for the
// first time.
void NotifyCompleteReceiver(GObject* source_object,
@@ -34,6 +45,26 @@ void NotifyCompleteReceiver(GObject* source_object,
platform_bridge_linux->NotifyCompleteInternal(user_data, value);
}
+// Runs once the profile has been loaded in order to perform a given
+// |operation| on a notification.
+void ProfileLoadedCallback(NotificationCommon::Operation operation,
+ NotificationCommon::Type notification_type,
+ const std::string& origin,
+ const std::string& notification_id,
+ int action_index,
+ const base::NullableString16& reply,
+ Profile* profile) {
+ if (!profile)
+ return;
+
+ NotificationDisplayService* display_service =
+ NotificationDisplayServiceFactory::GetForProfile(profile);
+
+ static_cast<NativeNotificationDisplayService*>(display_service)
+ ->ProcessNotificationOperation(operation, notification_type, origin,
+ notification_id, action_index, reply);
+}
+
} // namespace
// static
@@ -41,7 +72,6 @@ NotificationPlatformBridge* NotificationPlatformBridge::Create() {
GDBusProxy* notification_proxy = g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION,
static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
- G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
nullptr, kFreedesktopNotificationsName, kFreedesktopNotificationsPath,
kFreedesktopNotificationsName, nullptr, nullptr);
@@ -51,12 +81,16 @@ NotificationPlatformBridge* NotificationPlatformBridge::Create() {
}
struct NotificationPlatformBridgeLinux::NotificationData {
- NotificationData(const std::string& notification_id,
+ NotificationData(NotificationCommon::Type notification_type,
+ const std::string& notification_id,
const std::string& profile_id,
- bool is_incognito)
- : notification_id(notification_id),
+ bool is_incognito,
+ const GURL& origin_url)
+ : notification_type(notification_type),
+ notification_id(notification_id),
profile_id(profile_id),
- is_incognito(is_incognito) {}
+ is_incognito(is_incognito),
+ origin_url(origin_url) {}
~NotificationData() {
if (cancellable)
@@ -68,10 +102,16 @@ struct NotificationPlatformBridgeLinux::NotificationData {
uint32_t dbus_id = 0;
// Same parameters used by NotificationPlatformBridge::Display().
+ const NotificationCommon::Type notification_type;
const std::string notification_id;
const std::string profile_id;
const bool is_incognito;
+ // A copy of the origin_url from the underlying
+ // message_center::Notification. Used to pass back to
+ // NativeNotificationDisplayService.
+ const GURL origin_url;
+
// Used to cancel the initial "Notify" message so we don't call
// NotificationPlatformBridgeLinux::NotifyCompleteInternal() with a
// destroyed Notification.
@@ -80,7 +120,6 @@ struct NotificationPlatformBridgeLinux::NotificationData {
// If not null, the data to update the notification with once
// |dbus_id| becomes available.
std::unique_ptr<Notification> update_data;
- NotificationCommon::Type update_type = NotificationCommon::TYPE_MAX;
// If true, indicates the notification should be closed once
// |dbus_id| becomes available.
@@ -89,9 +128,15 @@ struct NotificationPlatformBridgeLinux::NotificationData {
NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux(
GDBusProxy* notification_proxy)
- : notification_proxy_(notification_proxy) {}
+ : notification_proxy_(notification_proxy) {
+ proxy_signal_handler_ = g_signal_connect(
+ notification_proxy_, "g-signal", G_CALLBACK(GSignalReceiverThunk), this);
+}
-NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() {}
+NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() {
+ if (proxy_signal_handler_)
+ g_signal_handler_disconnect(notification_proxy_, proxy_signal_handler_);
+}
void NotificationPlatformBridgeLinux::Display(
NotificationCommon::Type notification_type,
@@ -99,19 +144,21 @@ void NotificationPlatformBridgeLinux::Display(
const std::string& profile_id,
bool is_incognito,
const Notification& notification) {
- NotificationData* data = FindNotificationData(notification_id, profile_id);
+ NotificationData* data =
+ FindNotificationData(notification_id, profile_id, is_incognito);
if (data) {
// Update an existing notification.
+ DCHECK_EQ(data->notification_type, notification_type);
if (data->dbus_id) {
NotifyNow(data->dbus_id, notification_type, notification, nullptr,
nullptr, nullptr);
} else {
- data->update_type = notification_type;
data->update_data = base::MakeUnique<Notification>(notification);
}
} else {
// Send the notification for the first time.
- data = new NotificationData(notification_id, profile_id, is_incognito);
+ data = new NotificationData(notification_type, notification_id, profile_id,
+ is_incognito, notification.origin_url());
data->cancellable.reset(g_cancellable_new());
notifications_.emplace(data, base::WrapUnique(data));
NotifyNow(0, notification_type, notification, data->cancellable,
@@ -122,15 +169,21 @@ void NotificationPlatformBridgeLinux::Display(
void NotificationPlatformBridgeLinux::Close(
const std::string& profile_id,
const std::string& notification_id) {
- NotificationData* data = FindNotificationData(notification_id, profile_id);
- if (!data)
- return;
- if (data->dbus_id) {
- CloseNow(data->dbus_id);
- notifications_.erase(data);
- } else {
- data->should_close = true;
+ std::vector<NotificationData*> to_erase;
+ for (const auto& pair : notifications_) {
+ NotificationData* data = pair.first;
+ if (data->notification_id == notification_id &&
+ data->profile_id == profile_id) {
+ if (data->dbus_id) {
+ CloseNow(data->dbus_id);
+ to_erase.push_back(data);
+ } else {
+ data->should_close = true;
+ }
+ }
}
Peter Beverloo 2017/04/07 20:41:37 Filed crbug.com/709608 and will fix + cleanup.
+ for (NotificationData* data : to_erase)
+ notifications_.erase(data);
}
void NotificationPlatformBridgeLinux::GetDisplayed(
@@ -156,8 +209,8 @@ void NotificationPlatformBridgeLinux::NotifyCompleteInternal(gpointer user_data,
CloseNow(data->dbus_id);
notifications_.erase(data);
} else if (data->update_data) {
- NotifyNow(data->dbus_id, data->update_type, *data->update_data, nullptr,
- nullptr, nullptr);
+ NotifyNow(data->dbus_id, data->notification_type, *data->update_data,
+ nullptr, nullptr, nullptr);
data->update_data.reset();
}
}
@@ -170,11 +223,25 @@ void NotificationPlatformBridgeLinux::NotifyNow(
GAsyncReadyCallback callback,
gpointer user_data) {
// TODO(thomasanderson): Add a complete implementation.
+
+ GVariantBuilder actions_builder;
+ // Even-indexed elements in this array are action IDs passed back to
+ // us in GSignalReceiver. Odd-indexed ones contain the button text.
+ g_variant_builder_init(&actions_builder, G_VARIANT_TYPE("as"));
+ if (notification.clickable()) {
+ // Special case: the pair ("default", "") will not add a button,
+ // but instead makes the entire notification clickable.
+ AddActionToNotification(&actions_builder, "default", "");
+ }
+ // Always add a settings button.
+ AddActionToNotification(&actions_builder, "settings", "Settings");
+
const std::string title = base::UTF16ToUTF8(notification.title());
const std::string message = base::UTF16ToUTF8(notification.message());
+
GVariant* parameters =
g_variant_new("(susssasa{sv}i)", "", dbus_id, "", title.c_str(),
- message.c_str(), nullptr, nullptr, -1);
+ message.c_str(), &actions_builder, nullptr, -1);
g_dbus_proxy_call(notification_proxy_, "Notify", parameters,
G_DBUS_CALL_FLAGS_NONE, -1, cancellable, callback,
user_data);
@@ -189,14 +256,76 @@ void NotificationPlatformBridgeLinux::CloseNow(uint32_t dbus_id) {
NotificationPlatformBridgeLinux::NotificationData*
NotificationPlatformBridgeLinux::FindNotificationData(
const std::string& notification_id,
- const std::string& profile_id) {
+ const std::string& profile_id,
+ bool is_incognito) {
for (const auto& pair : notifications_) {
NotificationData* data = pair.first;
if (data->notification_id == notification_id &&
- data->profile_id == profile_id) {
+ data->profile_id == profile_id && data->is_incognito == is_incognito) {
return data;
}
}
return nullptr;
}
+
+NotificationPlatformBridgeLinux::NotificationData*
+NotificationPlatformBridgeLinux::FindNotificationData(uint32_t dbus_id) {
+ for (const auto& pair : notifications_) {
+ NotificationData* data = pair.first;
+ if (data->dbus_id == dbus_id)
+ return data;
+ }
+
+ return nullptr;
+}
+
+void NotificationPlatformBridgeLinux::ForwardNotificationOperation(
+ uint32_t dbus_id,
+ NotificationCommon::Operation operation,
+ int action_index) {
+ NotificationData* data = FindNotificationData(dbus_id);
+ if (!data) {
+ // This notification either belongs to a different app or we
+ // already removed the NotificationData after sending a
+ // "CloseNotification" message.
+ return;
+ }
+
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ DCHECK(profile_manager);
+
+ profile_manager->LoadProfile(
+ data->profile_id, data->is_incognito,
+ base::Bind(&ProfileLoadedCallback, operation, data->notification_type,
+ data->origin_url.spec(), data->notification_id, action_index,
+ base::NullableString16()));
+}
+
+void NotificationPlatformBridgeLinux::GSignalReceiver(GDBusProxy* proxy,
+ const char* sender_name,
+ const char* sender_signal,
+ GVariant* parameters) {
+ uint32_t dbus_id = 0;
+ if (strcmp("NotificationClosed", sender_signal) == 0 &&
+ g_variant_is_of_type(parameters, G_VARIANT_TYPE("(uu)"))) {
+ uint32_t reason;
+ g_variant_get(parameters, "(uu)", &dbus_id, &reason);
+ ForwardNotificationOperation(dbus_id, NotificationCommon::CLOSE, -1);
+ // std::unordered_map::erase(nullptr) is safe here.
+ notifications_.erase(FindNotificationData(dbus_id));
+ } else if (strcmp("ActionInvoked", sender_signal) == 0 &&
+ g_variant_is_of_type(parameters, G_VARIANT_TYPE("(us)"))) {
+ const gchar* action = nullptr;
+ g_variant_get(parameters, "(u&s)", &dbus_id, &action);
+ DCHECK(action);
+
+ if (strcmp(action, "default") == 0) {
+ ForwardNotificationOperation(dbus_id, NotificationCommon::CLICK, 0);
+ } else if (strcmp(action, "settings") == 0) {
+ ForwardNotificationOperation(dbus_id, NotificationCommon::SETTINGS, -1);
+ } else {
+ NOTIMPLEMENTED() << "No custom buttons just yet!";
+ }
+ }
+}
« no previous file with comments | « chrome/browser/notifications/notification_platform_bridge_linux.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698