| 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> | 
 |    8  | 
|    7 #include "base/memory/ptr_util.h" |    9 #include "base/memory/ptr_util.h" | 
 |   10 #include "base/stl_util.h" | 
|    8 #include "base/strings/utf_string_conversions.h" |   11 #include "base/strings/utf_string_conversions.h" | 
 |   12 #include "chrome/browser/browser_process.h" | 
|    9 #include "chrome/browser/notifications/notification.h" |   13 #include "chrome/browser/notifications/notification.h" | 
|   10  |   14  | 
|   11 namespace { |   15 namespace { | 
|   12  |   16  | 
|   13 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; |   17 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; | 
|   14 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; |   18 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; | 
|   15  |   19  | 
 |   20 // Callback used by GLib when the "Notify" message completes for the | 
 |   21 // first time. | 
 |   22 void NotifyCompleteReceiver(GObject* source_object, | 
 |   23                             GAsyncResult* result, | 
 |   24                             gpointer user_data) { | 
 |   25   GDBusProxy* proxy = G_DBUS_PROXY(source_object); | 
 |   26   GVariant* value = g_dbus_proxy_call_finish(proxy, result, nullptr); | 
 |   27   if (!value) { | 
 |   28     // The message might have been cancelled, in which case | 
 |   29     // |user_data| points to a destroyed NotificationData. | 
 |   30     return; | 
 |   31   } | 
 |   32   auto* platform_bridge_linux = static_cast<NotificationPlatformBridgeLinux*>( | 
 |   33       g_browser_process->notification_platform_bridge()); | 
 |   34   platform_bridge_linux->NotifyCompleteInternal(user_data, value); | 
 |   35 } | 
 |   36  | 
|   16 }  // namespace |   37 }  // namespace | 
|   17  |   38  | 
|   18 // static |   39 // static | 
|   19 NotificationPlatformBridge* NotificationPlatformBridge::Create() { |   40 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | 
|   20   GDBusProxy* notification_proxy = g_dbus_proxy_new_for_bus_sync( |   41   GDBusProxy* notification_proxy = g_dbus_proxy_new_for_bus_sync( | 
|   21       G_BUS_TYPE_SESSION, |   42       G_BUS_TYPE_SESSION, | 
|   22       static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | |   43       static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | | 
|   23                                    G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | |   44                                    G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | | 
|   24                                    G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), |   45                                    G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), | 
|   25       nullptr, kFreedesktopNotificationsName, kFreedesktopNotificationsPath, |   46       nullptr, kFreedesktopNotificationsName, kFreedesktopNotificationsPath, | 
|   26       kFreedesktopNotificationsName, nullptr, nullptr); |   47       kFreedesktopNotificationsName, nullptr, nullptr); | 
|   27   if (!notification_proxy) |   48   if (!notification_proxy) | 
|   28     return nullptr; |   49     return nullptr; | 
|   29   return new NotificationPlatformBridgeLinux(notification_proxy); |   50   return new NotificationPlatformBridgeLinux(notification_proxy); | 
|   30 } |   51 } | 
|   31  |   52  | 
 |   53 struct NotificationPlatformBridgeLinux::NotificationData { | 
 |   54   NotificationData(const std::string& notification_id, | 
 |   55                    const std::string& profile_id, | 
 |   56                    bool is_incognito) | 
 |   57       : notification_id(notification_id), | 
 |   58         profile_id(profile_id), | 
 |   59         is_incognito(is_incognito) {} | 
 |   60  | 
 |   61   ~NotificationData() { | 
 |   62     if (cancellable) | 
 |   63       g_cancellable_cancel(cancellable); | 
 |   64   } | 
 |   65  | 
 |   66   // The ID used by the notification server.  Will be 0 until the | 
 |   67   // first "Notify" message completes. | 
 |   68   uint32_t dbus_id = 0; | 
 |   69  | 
 |   70   // Same parameters used by NotificationPlatformBridge::Display(). | 
 |   71   const std::string notification_id; | 
 |   72   const std::string profile_id; | 
 |   73   const bool is_incognito; | 
 |   74  | 
 |   75   // Used to cancel the initial "Notify" message so we don't call | 
 |   76   // NotificationPlatformBridgeLinux::NotifyCompleteInternal() with a | 
 |   77   // destroyed Notification. | 
 |   78   ScopedGObject<GCancellable> cancellable; | 
 |   79  | 
 |   80   // If not null, the data to update the notification with once | 
 |   81   // |dbus_id| becomes available. | 
 |   82   std::unique_ptr<Notification> update_data; | 
 |   83   NotificationCommon::Type update_type = NotificationCommon::TYPE_MAX; | 
 |   84  | 
 |   85   // If true, indicates the notification should be closed once | 
 |   86   // |dbus_id| becomes available. | 
 |   87   bool should_close = false; | 
 |   88 }; | 
 |   89  | 
|   32 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( |   90 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( | 
|   33     GDBusProxy* notification_proxy) |   91     GDBusProxy* notification_proxy) | 
|   34     : notification_proxy_(notification_proxy) {} |   92     : notification_proxy_(notification_proxy) {} | 
|   35  |   93  | 
|   36 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() { |   94 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() {} | 
|   37   g_object_unref(notification_proxy_); |  | 
|   38 } |  | 
|   39  |   95  | 
|   40 void NotificationPlatformBridgeLinux::Display( |   96 void NotificationPlatformBridgeLinux::Display( | 
|   41     NotificationCommon::Type notification_type, |   97     NotificationCommon::Type notification_type, | 
|   42     const std::string& notification_id, |   98     const std::string& notification_id, | 
|   43     const std::string& profile_id, |   99     const std::string& profile_id, | 
|   44     bool is_incognito, |  100     bool is_incognito, | 
|   45     const Notification& notification) { |  101     const Notification& notification) { | 
|   46   // TODO(thomasanderson): Add a complete implementation. |  102   NotificationData* data = FindNotificationData(notification_id, profile_id); | 
|   47   g_dbus_proxy_call( |  103   if (data) { | 
|   48       notification_proxy_, "Notify", |  104     // Update an existing notification. | 
|   49       g_variant_new("(susssasa{sv}i)", "", 0, "", |  105     if (data->dbus_id) { | 
|   50                     base::UTF16ToUTF8(notification.title()).c_str(), |  106       NotifyNow(data->dbus_id, notification_type, notification, nullptr, | 
|   51                     base::UTF16ToUTF8(notification.message()).c_str(), nullptr, |  107                 nullptr, nullptr); | 
|   52                     nullptr, -1), |  108     } else { | 
|   53       G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr); |  109       data->update_type = notification_type; | 
 |  110       data->update_data = base::MakeUnique<Notification>(notification); | 
 |  111     } | 
 |  112   } else { | 
 |  113     // Send the notification for the first time. | 
 |  114     data = new NotificationData(notification_id, profile_id, is_incognito); | 
 |  115     data->cancellable.reset(g_cancellable_new()); | 
 |  116     notifications_.emplace(data, base::WrapUnique(data)); | 
 |  117     NotifyNow(0, notification_type, notification, data->cancellable, | 
 |  118               NotifyCompleteReceiver, data); | 
 |  119   } | 
|   54 } |  120 } | 
|   55  |  121  | 
|   56 void NotificationPlatformBridgeLinux::Close( |  122 void NotificationPlatformBridgeLinux::Close( | 
|   57     const std::string& profile_id, |  123     const std::string& profile_id, | 
|   58     const std::string& notification_id) { |  124     const std::string& notification_id) { | 
|   59   NOTIMPLEMENTED(); |  125   NotificationData* data = FindNotificationData(notification_id, profile_id); | 
 |  126   if (!data) | 
 |  127     return; | 
 |  128   if (data->dbus_id) { | 
 |  129     CloseNow(data->dbus_id); | 
 |  130     notifications_.erase(data); | 
 |  131   } else { | 
 |  132     data->should_close = true; | 
 |  133   } | 
|   60 } |  134 } | 
|   61  |  135  | 
|   62 void NotificationPlatformBridgeLinux::GetDisplayed( |  136 void NotificationPlatformBridgeLinux::GetDisplayed( | 
|   63     const std::string& profile_id, |  137     const std::string& profile_id, | 
|   64     bool incognito, |  138     bool incognito, | 
|   65     const DisplayedNotificationsCallback& callback) const { |  139     const DisplayedNotificationsCallback& callback) const { | 
|   66   callback.Run(base::MakeUnique<std::set<std::string>>(), false); |  140   callback.Run(base::MakeUnique<std::set<std::string>>(), false); | 
|   67 } |  141 } | 
 |  142  | 
 |  143 void NotificationPlatformBridgeLinux::NotifyCompleteInternal(gpointer user_data, | 
 |  144                                                              GVariant* value) { | 
 |  145   NotificationData* data = reinterpret_cast<NotificationData*>(user_data); | 
 |  146   if (!base::ContainsKey(notifications_, data)) | 
 |  147     return; | 
 |  148   data->cancellable.reset(); | 
 |  149   if (value && g_variant_is_of_type(value, G_VARIANT_TYPE("(u)"))) | 
 |  150     g_variant_get(value, "(u)", &data->dbus_id); | 
 |  151  | 
 |  152   if (!data->dbus_id) { | 
 |  153     // There was some sort of error with creating the notification. | 
 |  154     notifications_.erase(data); | 
 |  155   } else if (data->should_close) { | 
 |  156     CloseNow(data->dbus_id); | 
 |  157     notifications_.erase(data); | 
 |  158   } else if (data->update_data) { | 
 |  159     NotifyNow(data->dbus_id, data->update_type, *data->update_data, nullptr, | 
 |  160               nullptr, nullptr); | 
 |  161     data->update_data.reset(); | 
 |  162   } | 
 |  163 } | 
 |  164  | 
 |  165 void NotificationPlatformBridgeLinux::NotifyNow( | 
 |  166     uint32_t dbus_id, | 
 |  167     NotificationCommon::Type notification_type, | 
 |  168     const Notification& notification, | 
 |  169     GCancellable* cancellable, | 
 |  170     GAsyncReadyCallback callback, | 
 |  171     gpointer user_data) { | 
 |  172   // TODO(thomasanderson): Add a complete implementation. | 
 |  173   const std::string title = base::UTF16ToUTF8(notification.title()); | 
 |  174   const std::string message = base::UTF16ToUTF8(notification.message()); | 
 |  175   GVariant* parameters = | 
 |  176       g_variant_new("(susssasa{sv}i)", "", dbus_id, "", title.c_str(), | 
 |  177                     message.c_str(), nullptr, nullptr, -1); | 
 |  178   g_dbus_proxy_call(notification_proxy_, "Notify", parameters, | 
 |  179                     G_DBUS_CALL_FLAGS_NONE, -1, cancellable, callback, | 
 |  180                     user_data); | 
 |  181 } | 
 |  182  | 
 |  183 void NotificationPlatformBridgeLinux::CloseNow(uint32_t dbus_id) { | 
 |  184   g_dbus_proxy_call(notification_proxy_, "CloseNotification", | 
 |  185                     g_variant_new("(u)", dbus_id), G_DBUS_CALL_FLAGS_NONE, -1, | 
 |  186                     nullptr, nullptr, nullptr); | 
 |  187 } | 
 |  188  | 
 |  189 NotificationPlatformBridgeLinux::NotificationData* | 
 |  190 NotificationPlatformBridgeLinux::FindNotificationData( | 
 |  191     const std::string& notification_id, | 
 |  192     const std::string& profile_id) { | 
 |  193   for (const auto& pair : notifications_) { | 
 |  194     NotificationData* data = pair.first; | 
 |  195     if (data->notification_id == notification_id && | 
 |  196         data->profile_id == profile_id) { | 
 |  197       return data; | 
 |  198     } | 
 |  199   } | 
 |  200  | 
 |  201   return nullptr; | 
 |  202 } | 
| OLD | NEW |