| 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 | 8 |
| 9 #include "base/barrier_closure.h" | 9 #include "base/barrier_closure.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 } | 81 } |
| 82 | 82 |
| 83 void ForwardNotificationOperationOnUiThread( | 83 void ForwardNotificationOperationOnUiThread( |
| 84 NotificationCommon::Operation operation, | 84 NotificationCommon::Operation operation, |
| 85 NotificationCommon::Type notification_type, | 85 NotificationCommon::Type notification_type, |
| 86 const std::string& origin, | 86 const std::string& origin, |
| 87 const std::string& notification_id, | 87 const std::string& notification_id, |
| 88 int action_index, | 88 int action_index, |
| 89 const std::string& profile_id, | 89 const std::string& profile_id, |
| 90 bool is_incognito) { | 90 bool is_incognito) { |
| 91 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 92 ProfileManager* profile_manager = g_browser_process->profile_manager(); | 91 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 93 | 92 |
| 94 profile_manager->LoadProfile( | 93 profile_manager->LoadProfile( |
| 95 profile_id, is_incognito, | 94 profile_id, is_incognito, |
| 96 base::Bind(&ProfileLoadedCallback, operation, notification_type, origin, | 95 base::Bind(&ProfileLoadedCallback, operation, notification_type, origin, |
| 97 notification_id, action_index, base::NullableString16())); | 96 notification_id, action_index, base::NullableString16())); |
| 98 } | 97 } |
| 99 | 98 |
| 100 // Writes |data| to a new temporary file and returns its path. | 99 // Writes |data| to a new temporary file and returns its path. |
| 101 // Returns base::FilePath() on failure. | 100 // Returns base::FilePath() on failure. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 120 // static | 119 // static |
| 121 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | 120 NotificationPlatformBridge* NotificationPlatformBridge::Create() { |
| 122 return new NotificationPlatformBridgeLinux(); | 121 return new NotificationPlatformBridgeLinux(); |
| 123 } | 122 } |
| 124 | 123 |
| 125 class NotificationPlatformBridgeLinuxImpl | 124 class NotificationPlatformBridgeLinuxImpl |
| 126 : public NotificationPlatformBridge, | 125 : public NotificationPlatformBridge, |
| 127 public content::NotificationObserver, | 126 public content::NotificationObserver, |
| 128 public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { | 127 public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { |
| 129 public: | 128 public: |
| 130 NotificationPlatformBridgeLinuxImpl() | 129 NotificationPlatformBridgeLinuxImpl( |
| 131 : task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( | 130 scoped_refptr<base::SequencedTaskRunner> notification_task_runner, |
| 132 base::TaskTraits().MayBlock().WithPriority( | 131 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
| 133 base::TaskPriority::USER_BLOCKING))) { | 132 scoped_refptr<dbus::Bus> bus) |
| 133 : notification_task_runner_(notification_task_runner), |
| 134 ui_task_runner_(ui_task_runner), |
| 135 bus_(bus) { |
| 136 if (!notification_task_runner_) { |
| 137 notification_task_runner_ = base::CreateSingleThreadTaskRunnerWithTraits( |
| 138 base::TaskTraits().MayBlock().WithPriority( |
| 139 base::TaskPriority::USER_BLOCKING)); |
| 140 } |
| 141 DCHECK(ui_task_runner_); |
| 134 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, | 142 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
| 135 content::NotificationService::AllSources()); | 143 content::NotificationService::AllSources()); |
| 144 } |
| 145 |
| 146 // Init() cannot be called from within the constructor because of a |
| 147 // race condition. The reference count for |this| starts out as 0. |
| 148 // Posting the Init task would increment the count to 1. If the |
| 149 // task finishes before the constructor returns, the count will go |
| 150 // to 0 and the object would be prematurely destructed. |
| 151 void InitAfterConstructor() { |
| 136 PostTaskToTaskRunnerThread( | 152 PostTaskToTaskRunnerThread( |
| 137 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); | 153 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); |
| 138 } | 154 } |
| 139 | 155 |
| 140 void Display(NotificationCommon::Type notification_type, | 156 void Display(NotificationCommon::Type notification_type, |
| 141 const std::string& notification_id, | 157 const std::string& notification_id, |
| 142 const std::string& profile_id, | 158 const std::string& profile_id, |
| 143 bool is_incognito, | 159 bool is_incognito, |
| 144 const Notification& notification) override { | 160 const Notification& notification) override { |
| 145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 161 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 146 // Notifications contain gfx::Image's which have reference counts | 162 // Notifications contain gfx::Image's which have reference counts |
| 147 // that are not thread safe. Because of this, we duplicate the | 163 // that are not thread safe. Because of this, we duplicate the |
| 148 // notification and its images. Wrap the notification in a | 164 // notification and its images. Wrap the notification in a |
| 149 // unique_ptr to transfer ownership of the notification (and the | 165 // unique_ptr to transfer ownership of the notification (and the |
| 150 // non-thread-safe reference counts) to the task runner thread. | 166 // non-thread-safe reference counts) to the task runner thread. |
| 151 auto notification_copy = base::MakeUnique<Notification>(notification); | 167 auto notification_copy = base::MakeUnique<Notification>(notification); |
| 152 notification_copy->set_icon(DeepCopyImage(notification_copy->icon())); | 168 notification_copy->set_icon(DeepCopyImage(notification_copy->icon())); |
| 153 notification_copy->set_image(gfx::Image()); | 169 notification_copy->set_image(gfx::Image()); |
| 154 notification_copy->set_small_image(gfx::Image()); | 170 notification_copy->set_small_image(gfx::Image()); |
| 155 for (size_t i = 0; i < notification_copy->buttons().size(); i++) | 171 for (size_t i = 0; i < notification_copy->buttons().size(); i++) |
| 156 notification_copy->SetButtonIcon(i, gfx::Image()); | 172 notification_copy->SetButtonIcon(i, gfx::Image()); |
| 157 | 173 |
| 158 PostTaskToTaskRunnerThread(base::BindOnce( | 174 PostTaskToTaskRunnerThread(base::BindOnce( |
| 159 &NotificationPlatformBridgeLinuxImpl::DisplayOnTaskRunner, this, | 175 &NotificationPlatformBridgeLinuxImpl::DisplayOnTaskRunner, this, |
| 160 notification_type, notification_id, profile_id, is_incognito, | 176 notification_type, notification_id, profile_id, is_incognito, |
| 161 base::Passed(¬ification_copy))); | 177 base::Passed(¬ification_copy))); |
| 162 } | 178 } |
| 163 | 179 |
| 164 void Close(const std::string& profile_id, | 180 void Close(const std::string& profile_id, |
| 165 const std::string& notification_id) override { | 181 const std::string& notification_id) override { |
| 166 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 182 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 167 PostTaskToTaskRunnerThread( | 183 PostTaskToTaskRunnerThread( |
| 168 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::CloseOnTaskRunner, | 184 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::CloseOnTaskRunner, |
| 169 this, profile_id, notification_id)); | 185 this, profile_id, notification_id)); |
| 170 } | 186 } |
| 171 | 187 |
| 172 void GetDisplayed( | 188 void GetDisplayed( |
| 173 const std::string& profile_id, | 189 const std::string& profile_id, |
| 174 bool incognito, | 190 bool incognito, |
| 175 const GetDisplayedNotificationsCallback& callback) const override { | 191 const GetDisplayedNotificationsCallback& callback) const override { |
| 176 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 192 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 177 PostTaskToTaskRunnerThread(base::BindOnce( | 193 PostTaskToTaskRunnerThread(base::BindOnce( |
| 178 &NotificationPlatformBridgeLinuxImpl::GetDisplayedOnTaskRunner, this, | 194 &NotificationPlatformBridgeLinuxImpl::GetDisplayedOnTaskRunner, this, |
| 179 profile_id, incognito, callback)); | 195 profile_id, incognito, callback)); |
| 180 } | 196 } |
| 181 | 197 |
| 182 void SetReadyCallback(NotificationBridgeReadyCallback callback) override { | 198 void SetReadyCallback(NotificationBridgeReadyCallback callback) override { |
| 183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 199 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 184 if (connected_.has_value()) { | 200 if (connected_.has_value()) { |
| 185 std::move(callback).Run(connected_.value()); | 201 std::move(callback).Run(connected_.value()); |
| 186 } else { | 202 } else { |
| 187 on_connected_callbacks_.push_back(std::move(callback)); | 203 on_connected_callbacks_.push_back(std::move(callback)); |
| 188 } | 204 } |
| 189 } | 205 } |
| 190 | 206 |
| 207 void CleanUp() { |
| 208 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 209 if (cleanup_posted_) |
| 210 return; |
| 211 PostTaskToTaskRunnerThread(base::BindOnce( |
| 212 &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); |
| 213 cleanup_posted_ = true; |
| 214 } |
| 215 |
| 191 private: | 216 private: |
| 192 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; | 217 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; |
| 193 | 218 |
| 194 struct ResourceFile { | 219 struct ResourceFile { |
| 195 explicit ResourceFile(const base::FilePath& file_path) | 220 explicit ResourceFile(const base::FilePath& file_path) |
| 196 : file_path(file_path) {} | 221 : file_path(file_path) {} |
| 197 ~ResourceFile() { base::DeleteFile(file_path, false); } | 222 ~ResourceFile() { base::DeleteFile(file_path, false); } |
| 198 const base::FilePath file_path; | 223 const base::FilePath file_path; |
| 199 }; | 224 }; |
| 200 | 225 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 231 size_t action_start = 0; | 256 size_t action_start = 0; |
| 232 size_t action_end = 0; | 257 size_t action_end = 0; |
| 233 | 258 |
| 234 // Temporary resource files associated with the notification that | 259 // Temporary resource files associated with the notification that |
| 235 // should be cleaned up when the notification is closed or on | 260 // should be cleaned up when the notification is closed or on |
| 236 // shutdown. | 261 // shutdown. |
| 237 std::vector<std::unique_ptr<ResourceFile>> resource_files; | 262 std::vector<std::unique_ptr<ResourceFile>> resource_files; |
| 238 }; | 263 }; |
| 239 | 264 |
| 240 ~NotificationPlatformBridgeLinuxImpl() override { | 265 ~NotificationPlatformBridgeLinuxImpl() override { |
| 266 DCHECK(cleanup_posted_); |
| 241 DCHECK(!bus_); | 267 DCHECK(!bus_); |
| 268 DCHECK(!notification_proxy_); |
| 242 DCHECK(notifications_.empty()); | 269 DCHECK(notifications_.empty()); |
| 243 } | 270 } |
| 244 | 271 |
| 245 void Observe(int type, | 272 void Observe(int type, |
| 246 const content::NotificationSource& source, | 273 const content::NotificationSource& source, |
| 247 const content::NotificationDetails& details) override { | 274 const content::NotificationDetails& details) override { |
| 248 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 275 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 249 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); | 276 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); |
| 250 // The browser process is about to exit. Post the CleanUp() task | 277 // The browser process is about to exit. Post the CleanUp() task |
| 251 // while we still can. | 278 // while we still can. |
| 252 CleanUp(); | 279 CleanUp(); |
| 253 } | 280 } |
| 254 | 281 |
| 255 void PostTaskToUiThread(base::OnceClosure closure) const { | 282 void PostTaskToUiThread(base::OnceClosure closure) const { |
| 256 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 283 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 257 bool success = content::BrowserThread::PostTask( | 284 DCHECK(ui_task_runner_); |
| 258 content::BrowserThread::UI, FROM_HERE, std::move(closure)); | 285 bool success = ui_task_runner_->PostTask(FROM_HERE, std::move(closure)); |
| 259 DCHECK(success); | 286 DCHECK(success); |
| 260 } | 287 } |
| 261 | 288 |
| 262 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { | 289 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { |
| 263 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 290 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 264 DCHECK(task_runner_); | 291 DCHECK(notification_task_runner_); |
| 265 bool success = task_runner_->PostTask(FROM_HERE, std::move(closure)); | 292 bool success = |
| 293 notification_task_runner_->PostTask(FROM_HERE, std::move(closure)); |
| 266 DCHECK(success); | 294 DCHECK(success); |
| 267 } | 295 } |
| 268 | 296 |
| 269 // Sets up the D-Bus connection. | 297 // Sets up the D-Bus connection. |
| 270 void Init() { | 298 void Init() { |
| 271 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 299 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 272 dbus::Bus::Options bus_options; | 300 if (!bus_) { |
| 273 bus_options.bus_type = dbus::Bus::SESSION; | 301 dbus::Bus::Options bus_options; |
| 274 bus_options.connection_type = dbus::Bus::PRIVATE; | 302 bus_options.bus_type = dbus::Bus::SESSION; |
| 275 bus_options.dbus_task_runner = task_runner_; | 303 bus_options.connection_type = dbus::Bus::PRIVATE; |
| 276 bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); | 304 bus_options.dbus_task_runner = notification_task_runner_; |
| 305 bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); |
| 306 } |
| 277 | 307 |
| 278 notification_proxy_ = | 308 notification_proxy_ = |
| 279 bus_->GetObjectProxy(kFreedesktopNotificationsName, | 309 bus_->GetObjectProxy(kFreedesktopNotificationsName, |
| 280 dbus::ObjectPath(kFreedesktopNotificationsPath)); | 310 dbus::ObjectPath(kFreedesktopNotificationsPath)); |
| 281 if (!notification_proxy_) { | 311 if (!notification_proxy_) { |
| 282 OnConnectionInitializationFinishedOnTaskRunner(false); | 312 OnConnectionInitializationFinishedOnTaskRunner(false); |
| 283 return; | 313 return; |
| 284 } | 314 } |
| 285 | 315 |
| 286 connected_signals_barrier_ = base::BarrierClosure( | 316 connected_signals_barrier_ = base::BarrierClosure( |
| 287 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: | 317 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: |
| 288 OnConnectionInitializationFinishedOnTaskRunner, | 318 OnConnectionInitializationFinishedOnTaskRunner, |
| 289 this, true)); | 319 this, true)); |
| 290 notification_proxy_->ConnectToSignal( | 320 notification_proxy_->ConnectToSignal( |
| 291 kFreedesktopNotificationsName, "ActionInvoked", | 321 kFreedesktopNotificationsName, "ActionInvoked", |
| 292 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), | 322 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), |
| 293 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 323 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 294 this)); | 324 this)); |
| 295 notification_proxy_->ConnectToSignal( | 325 notification_proxy_->ConnectToSignal( |
| 296 kFreedesktopNotificationsName, "NotificationClosed", | 326 kFreedesktopNotificationsName, "NotificationClosed", |
| 297 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, | 327 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, |
| 298 this), | 328 this), |
| 299 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 329 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
| 300 this)); | 330 this)); |
| 301 } | 331 } |
| 302 | 332 |
| 303 void CleanUp() { | |
| 304 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 305 if (cleanup_posted_) | |
| 306 return; | |
| 307 PostTaskToTaskRunnerThread(base::BindOnce( | |
| 308 &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); | |
| 309 cleanup_posted_ = true; | |
| 310 } | |
| 311 | |
| 312 void CleanUpOnTaskRunner() { | 333 void CleanUpOnTaskRunner() { |
| 313 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 334 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 314 bus_->ShutdownAndBlock(); | 335 bus_->ShutdownAndBlock(); |
| 315 bus_ = nullptr; | 336 bus_ = nullptr; |
| 316 notification_proxy_ = nullptr; | 337 notification_proxy_ = nullptr; |
| 317 notifications_.clear(); | 338 notifications_.clear(); |
| 318 } | 339 } |
| 319 | 340 |
| 320 // Makes the "Notify" call to D-Bus. | 341 // Makes the "Notify" call to D-Bus. |
| 321 void DisplayOnTaskRunner(NotificationCommon::Type notification_type, | 342 void DisplayOnTaskRunner(NotificationCommon::Type notification_type, |
| 322 const std::string& notification_id, | 343 const std::string& notification_id, |
| 323 const std::string& profile_id, | 344 const std::string& profile_id, |
| 324 bool is_incognito, | 345 bool is_incognito, |
| 325 std::unique_ptr<Notification> notification) { | 346 std::unique_ptr<Notification> notification) { |
| 326 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 347 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 327 NotificationData* data = | 348 NotificationData* data = |
| 328 FindNotificationData(notification_id, profile_id, is_incognito); | 349 FindNotificationData(notification_id, profile_id, is_incognito); |
| 329 if (data) { | 350 if (data) { |
| 330 // Update an existing notification. | 351 // Update an existing notification. |
| 331 data->notification_type = notification_type; | 352 data->notification_type = notification_type; |
| 332 data->resource_files.clear(); | 353 data->resource_files.clear(); |
| 333 } else { | 354 } else { |
| 334 // Send the notification for the first time. | 355 // Send the notification for the first time. |
| 335 data = | 356 data = |
| 336 new NotificationData(notification_type, notification_id, profile_id, | 357 new NotificationData(notification_type, notification_id, profile_id, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 } | 445 } |
| 425 if (!data->dbus_id) { | 446 if (!data->dbus_id) { |
| 426 // There was some sort of error with creating the notification. | 447 // There was some sort of error with creating the notification. |
| 427 notifications_.erase(data); | 448 notifications_.erase(data); |
| 428 } | 449 } |
| 429 } | 450 } |
| 430 | 451 |
| 431 // Makes the "CloseNotification" call to D-Bus. | 452 // Makes the "CloseNotification" call to D-Bus. |
| 432 void CloseOnTaskRunner(const std::string& profile_id, | 453 void CloseOnTaskRunner(const std::string& profile_id, |
| 433 const std::string& notification_id) { | 454 const std::string& notification_id) { |
| 434 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 455 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 435 std::vector<NotificationData*> to_erase; | 456 std::vector<NotificationData*> to_erase; |
| 436 for (const auto& pair : notifications_) { | 457 for (const auto& pair : notifications_) { |
| 437 NotificationData* data = pair.first; | 458 NotificationData* data = pair.first; |
| 438 if (data->notification_id == notification_id && | 459 if (data->notification_id == notification_id && |
| 439 data->profile_id == profile_id) { | 460 data->profile_id == profile_id) { |
| 440 dbus::MethodCall method_call(kFreedesktopNotificationsName, | 461 dbus::MethodCall method_call(kFreedesktopNotificationsName, |
| 441 "CloseNotification"); | 462 "CloseNotification"); |
| 442 dbus::MessageWriter writer(&method_call); | 463 dbus::MessageWriter writer(&method_call); |
| 443 writer.AppendUint32(data->dbus_id); | 464 writer.AppendUint32(data->dbus_id); |
| 444 notification_proxy_->CallMethodAndBlock( | 465 notification_proxy_->CallMethodAndBlock( |
| 445 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); | 466 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
| 446 } | 467 } |
| 447 } | 468 } |
| 448 for (NotificationData* data : to_erase) | 469 for (NotificationData* data : to_erase) |
| 449 notifications_.erase(data); | 470 notifications_.erase(data); |
| 450 } | 471 } |
| 451 | 472 |
| 452 void GetDisplayedOnTaskRunner( | 473 void GetDisplayedOnTaskRunner( |
| 453 const std::string& profile_id, | 474 const std::string& profile_id, |
| 454 bool incognito, | 475 bool incognito, |
| 455 const GetDisplayedNotificationsCallback& callback) const { | 476 const GetDisplayedNotificationsCallback& callback) const { |
| 456 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 477 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 457 // TODO(thomasanderson): Implement. | 478 // TODO(thomasanderson): Implement. |
| 458 PostTaskToUiThread(base::BindOnce( | 479 PostTaskToUiThread(base::BindOnce( |
| 459 callback, base::Passed(base::MakeUnique<std::set<std::string>>()), | 480 callback, base::Passed(base::MakeUnique<std::set<std::string>>()), |
| 460 false)); | 481 false)); |
| 461 } | 482 } |
| 462 | 483 |
| 463 NotificationData* FindNotificationData(const std::string& notification_id, | 484 NotificationData* FindNotificationData(const std::string& notification_id, |
| 464 const std::string& profile_id, | 485 const std::string& profile_id, |
| 465 bool is_incognito) { | 486 bool is_incognito) { |
| 466 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 487 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 467 for (const auto& pair : notifications_) { | 488 for (const auto& pair : notifications_) { |
| 468 NotificationData* data = pair.first; | 489 NotificationData* data = pair.first; |
| 469 if (data->notification_id == notification_id && | 490 if (data->notification_id == notification_id && |
| 470 data->profile_id == profile_id && | 491 data->profile_id == profile_id && |
| 471 data->is_incognito == is_incognito) { | 492 data->is_incognito == is_incognito) { |
| 472 return data; | 493 return data; |
| 473 } | 494 } |
| 474 } | 495 } |
| 475 | 496 |
| 476 return nullptr; | 497 return nullptr; |
| 477 } | 498 } |
| 478 | 499 |
| 479 NotificationData* FindNotificationData(uint32_t dbus_id) { | 500 NotificationData* FindNotificationData(uint32_t dbus_id) { |
| 480 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 501 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 481 for (const auto& pair : notifications_) { | 502 for (const auto& pair : notifications_) { |
| 482 NotificationData* data = pair.first; | 503 NotificationData* data = pair.first; |
| 483 if (data->dbus_id == dbus_id) | 504 if (data->dbus_id == dbus_id) |
| 484 return data; | 505 return data; |
| 485 } | 506 } |
| 486 | 507 |
| 487 return nullptr; | 508 return nullptr; |
| 488 } | 509 } |
| 489 | 510 |
| 490 void ForwardNotificationOperation(NotificationData* data, | 511 void ForwardNotificationOperation(NotificationData* data, |
| 491 NotificationCommon::Operation operation, | 512 NotificationCommon::Operation operation, |
| 492 int action_index) { | 513 int action_index) { |
| 493 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 514 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 494 PostTaskToUiThread(base::BindOnce( | 515 PostTaskToUiThread(base::BindOnce( |
| 495 ForwardNotificationOperationOnUiThread, operation, | 516 ForwardNotificationOperationOnUiThread, operation, |
| 496 data->notification_type, data->origin_url.spec(), data->notification_id, | 517 data->notification_type, data->origin_url.spec(), data->notification_id, |
| 497 action_index, data->profile_id, data->is_incognito)); | 518 action_index, data->profile_id, data->is_incognito)); |
| 498 } | 519 } |
| 499 | 520 |
| 500 void OnActionInvoked(dbus::Signal* signal) { | 521 void OnActionInvoked(dbus::Signal* signal) { |
| 501 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 522 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 502 dbus::MessageReader reader(signal); | 523 dbus::MessageReader reader(signal); |
| 503 uint32_t dbus_id; | 524 uint32_t dbus_id; |
| 504 if (!reader.PopUint32(&dbus_id)) | 525 if (!reader.PopUint32(&dbus_id)) |
| 505 return; | 526 return; |
| 506 std::string action; | 527 std::string action; |
| 507 if (!reader.PopString(&action)) | 528 if (!reader.PopString(&action)) |
| 508 return; | 529 return; |
| 509 | 530 |
| 510 NotificationData* data = FindNotificationData(dbus_id); | 531 NotificationData* data = FindNotificationData(dbus_id); |
| 511 if (!data) | 532 if (!data) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 522 size_t n_buttons = data->action_end - data->action_start; | 543 size_t n_buttons = data->action_end - data->action_start; |
| 523 size_t id_zero_based = id - data->action_start; | 544 size_t id_zero_based = id - data->action_start; |
| 524 if (id_zero_based >= n_buttons) | 545 if (id_zero_based >= n_buttons) |
| 525 return; | 546 return; |
| 526 ForwardNotificationOperation(data, NotificationCommon::CLICK, | 547 ForwardNotificationOperation(data, NotificationCommon::CLICK, |
| 527 id_zero_based); | 548 id_zero_based); |
| 528 } | 549 } |
| 529 } | 550 } |
| 530 | 551 |
| 531 void OnNotificationClosed(dbus::Signal* signal) { | 552 void OnNotificationClosed(dbus::Signal* signal) { |
| 532 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 553 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 533 dbus::MessageReader reader(signal); | 554 dbus::MessageReader reader(signal); |
| 534 uint32_t dbus_id; | 555 uint32_t dbus_id; |
| 535 if (!reader.PopUint32(&dbus_id)) | 556 if (!reader.PopUint32(&dbus_id)) |
| 536 return; | 557 return; |
| 537 | 558 |
| 538 NotificationData* data = FindNotificationData(dbus_id); | 559 NotificationData* data = FindNotificationData(dbus_id); |
| 539 if (!data) | 560 if (!data) |
| 540 return; | 561 return; |
| 541 | 562 |
| 542 ForwardNotificationOperation(data, NotificationCommon::CLOSE, -1); | 563 ForwardNotificationOperation(data, NotificationCommon::CLOSE, -1); |
| 543 notifications_.erase(data); | 564 notifications_.erase(data); |
| 544 } | 565 } |
| 545 | 566 |
| 546 // Called once the connection has been set up (or not). |success| | 567 // Called once the connection has been set up (or not). |success| |
| 547 // indicates the connection is ready to use. | 568 // indicates the connection is ready to use. |
| 548 void OnConnectionInitializationFinishedOnUiThread(bool success) { | 569 void OnConnectionInitializationFinishedOnUiThread(bool success) { |
| 549 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 570 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
| 550 connected_ = success; | 571 connected_ = success; |
| 551 for (auto& callback : on_connected_callbacks_) | 572 for (auto& callback : on_connected_callbacks_) |
| 552 std::move(callback).Run(success); | 573 std::move(callback).Run(success); |
| 553 on_connected_callbacks_.clear(); | 574 on_connected_callbacks_.clear(); |
| 554 if (!success) | 575 if (!success) |
| 555 CleanUp(); | 576 CleanUp(); |
| 556 } | 577 } |
| 557 | 578 |
| 558 void OnConnectionInitializationFinishedOnTaskRunner(bool success) { | 579 void OnConnectionInitializationFinishedOnTaskRunner(bool success) { |
| 559 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 580 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 560 PostTaskToUiThread( | 581 PostTaskToUiThread( |
| 561 base::BindOnce(&NotificationPlatformBridgeLinuxImpl:: | 582 base::BindOnce(&NotificationPlatformBridgeLinuxImpl:: |
| 562 OnConnectionInitializationFinishedOnUiThread, | 583 OnConnectionInitializationFinishedOnUiThread, |
| 563 this, success)); | 584 this, success)); |
| 564 } | 585 } |
| 565 | 586 |
| 566 void OnSignalConnected(const std::string& interface_name, | 587 void OnSignalConnected(const std::string& interface_name, |
| 567 const std::string& signal_name, | 588 const std::string& signal_name, |
| 568 bool success) { | 589 bool success) { |
| 569 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 590 DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
| 570 if (!success) { | 591 if (!success) { |
| 571 OnConnectionInitializationFinishedOnTaskRunner(false); | 592 OnConnectionInitializationFinishedOnTaskRunner(false); |
| 572 return; | 593 return; |
| 573 } | 594 } |
| 574 connected_signals_barrier_.Run(); | 595 connected_signals_barrier_.Run(); |
| 575 } | 596 } |
| 576 | 597 |
| 577 ////////////////////////////////////////////////////////////////////////////// | 598 ////////////////////////////////////////////////////////////////////////////// |
| 578 // Members used only on the UI thread. | 599 // Members used only on the UI thread. |
| 579 | 600 |
| 580 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 601 scoped_refptr<base::SequencedTaskRunner> notification_task_runner_; |
| 581 | 602 |
| 582 content::NotificationRegistrar registrar_; | 603 content::NotificationRegistrar registrar_; |
| 583 | 604 |
| 584 // State necessary for OnConnectionInitializationFinished() and | 605 // State necessary for OnConnectionInitializationFinished() and |
| 585 // SetReadyCallback(). | 606 // SetReadyCallback(). |
| 586 base::Optional<bool> connected_; | 607 base::Optional<bool> connected_; |
| 587 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; | 608 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; |
| 588 | 609 |
| 589 bool cleanup_posted_ = false; | 610 bool cleanup_posted_ = false; |
| 590 | 611 |
| 591 ////////////////////////////////////////////////////////////////////////////// | 612 ////////////////////////////////////////////////////////////////////////////// |
| 592 // Members used only on the task runner thread. | 613 // Members used only on the task runner thread. |
| 593 | 614 |
| 615 scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; |
| 616 |
| 594 scoped_refptr<dbus::Bus> bus_; | 617 scoped_refptr<dbus::Bus> bus_; |
| 595 | 618 |
| 596 dbus::ObjectProxy* notification_proxy_ = nullptr; | 619 dbus::ObjectProxy* notification_proxy_ = nullptr; |
| 597 | 620 |
| 598 base::Closure connected_signals_barrier_; | 621 base::Closure connected_signals_barrier_; |
| 599 | 622 |
| 600 // A std::set<std::unique_ptr<T>> doesn't work well because | 623 // A std::set<std::unique_ptr<T>> doesn't work well because |
| 601 // eg. std::set::erase(T) would require a std::unique_ptr<T> | 624 // eg. std::set::erase(T) would require a std::unique_ptr<T> |
| 602 // argument, so the data would get double-destructed. | 625 // argument, so the data would get double-destructed. |
| 603 template <typename T> | 626 template <typename T> |
| 604 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; | 627 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; |
| 605 | 628 |
| 606 UnorderedUniqueSet<NotificationData> notifications_; | 629 UnorderedUniqueSet<NotificationData> notifications_; |
| 607 | 630 |
| 608 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); | 631 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); |
| 609 }; | 632 }; |
| 610 | 633 |
| 611 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() | 634 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() |
| 612 : impl_(new NotificationPlatformBridgeLinuxImpl()) {} | 635 : NotificationPlatformBridgeLinux( |
| 636 nullptr, |
| 637 content::BrowserThread::GetTaskRunnerForThread( |
| 638 content::BrowserThread::UI), |
| 639 nullptr) { |
| 640 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 641 } |
| 642 |
| 643 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( |
| 644 scoped_refptr<base::SequencedTaskRunner> notification_task_runner, |
| 645 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
| 646 scoped_refptr<dbus::Bus> bus) |
| 647 : impl_(new NotificationPlatformBridgeLinuxImpl(notification_task_runner, |
| 648 ui_task_runner, |
| 649 bus)) { |
| 650 impl_->InitAfterConstructor(); |
| 651 } |
| 613 | 652 |
| 614 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; | 653 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; |
| 615 | 654 |
| 616 void NotificationPlatformBridgeLinux::Display( | 655 void NotificationPlatformBridgeLinux::Display( |
| 617 NotificationCommon::Type notification_type, | 656 NotificationCommon::Type notification_type, |
| 618 const std::string& notification_id, | 657 const std::string& notification_id, |
| 619 const std::string& profile_id, | 658 const std::string& profile_id, |
| 620 bool is_incognito, | 659 bool is_incognito, |
| 621 const Notification& notification) { | 660 const Notification& notification) { |
| 622 impl_->Display(notification_type, notification_id, profile_id, is_incognito, | 661 impl_->Display(notification_type, notification_id, profile_id, is_incognito, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 633 const std::string& profile_id, | 672 const std::string& profile_id, |
| 634 bool incognito, | 673 bool incognito, |
| 635 const GetDisplayedNotificationsCallback& callback) const { | 674 const GetDisplayedNotificationsCallback& callback) const { |
| 636 impl_->GetDisplayed(profile_id, incognito, callback); | 675 impl_->GetDisplayed(profile_id, incognito, callback); |
| 637 } | 676 } |
| 638 | 677 |
| 639 void NotificationPlatformBridgeLinux::SetReadyCallback( | 678 void NotificationPlatformBridgeLinux::SetReadyCallback( |
| 640 NotificationBridgeReadyCallback callback) { | 679 NotificationBridgeReadyCallback callback) { |
| 641 impl_->SetReadyCallback(std::move(callback)); | 680 impl_->SetReadyCallback(std::move(callback)); |
| 642 } | 681 } |
| 682 |
| 683 void NotificationPlatformBridgeLinux::CleanUp() { |
| 684 impl_->CleanUp(); |
| 685 } |
| OLD | NEW |