Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/extensions/api/notifications/notifications_api.h" | 5 #include "chrome/browser/extensions/api/notifications/notifications_api.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/feature_list.h" | 12 #include "base/feature_list.h" |
| 13 #include "base/guid.h" | 13 #include "base/guid.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
| 17 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 21 #include "build/build_config.h" | 21 #include "build/build_config.h" |
| 22 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper.h" |
| 23 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper_factory.h" | |
| 23 #include "chrome/browser/notifications/notification.h" | 24 #include "chrome/browser/notifications/notification.h" |
| 24 #include "chrome/browser/notifications/notification_ui_manager.h" | |
| 25 #include "chrome/browser/notifications/notifier_state_tracker.h" | 25 #include "chrome/browser/notifications/notifier_state_tracker.h" |
| 26 #include "chrome/browser/notifications/notifier_state_tracker_factory.h" | 26 #include "chrome/browser/notifications/notifier_state_tracker_factory.h" |
| 27 #include "chrome/browser/profiles/profile.h" | 27 #include "chrome/browser/profiles/profile.h" |
| 28 #include "chrome/common/extensions/api/notifications/notification_style.h" | 28 #include "chrome/common/extensions/api/notifications/notification_style.h" |
| 29 #include "components/keyed_service/content/browser_context_keyed_service_shutdow n_notifier_factory.h" | 29 #include "components/keyed_service/content/browser_context_keyed_service_shutdow n_notifier_factory.h" |
| 30 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h" | 30 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h" |
| 31 #include "content/public/browser/render_process_host.h" | 31 #include "content/public/browser/render_process_host.h" |
| 32 #include "content/public/browser/render_view_host.h" | 32 #include "content/public/browser/render_view_host.h" |
| 33 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
| 34 #include "extensions/browser/app_window/app_window.h" | 34 #include "extensions/browser/app_window/app_window.h" |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 }; | 205 }; |
| 206 | 206 |
| 207 class NotificationsApiDelegate : public NotificationDelegate { | 207 class NotificationsApiDelegate : public NotificationDelegate { |
| 208 public: | 208 public: |
| 209 NotificationsApiDelegate(ChromeAsyncExtensionFunction* api_function, | 209 NotificationsApiDelegate(ChromeAsyncExtensionFunction* api_function, |
| 210 Profile* profile, | 210 Profile* profile, |
| 211 const std::string& extension_id, | 211 const std::string& extension_id, |
| 212 const std::string& id) | 212 const std::string& id) |
| 213 : api_function_(api_function), | 213 : api_function_(api_function), |
| 214 event_router_(EventRouter::Get(profile)), | 214 event_router_(EventRouter::Get(profile)), |
| 215 profile_(profile), | |
| 215 extension_id_(extension_id), | 216 extension_id_(extension_id), |
| 216 id_(id), | 217 id_(id), |
| 217 scoped_id_(CreateScopedIdentifier(extension_id, id)) { | 218 scoped_id_(CreateScopedIdentifier(extension_id, id)) { |
| 218 DCHECK(api_function_); | 219 DCHECK(api_function_); |
| 219 shutdown_notifier_subscription_ = | 220 shutdown_notifier_subscription_ = |
| 220 ShutdownNotifierFactory::GetInstance()->Get(profile)->Subscribe( | 221 ShutdownNotifierFactory::GetInstance()->Get(profile)->Subscribe( |
| 221 base::Bind(&NotificationsApiDelegate::Shutdown, | 222 base::Bind(&NotificationsApiDelegate::Shutdown, |
| 222 base::Unretained(this))); | 223 base::Unretained(this))); |
| 223 } | 224 } |
| 224 | 225 |
| 225 void Close(bool by_user) override { | 226 void Close(bool by_user) override { |
| 226 EventRouter::UserGestureState gesture = | 227 EventRouter::UserGestureState gesture = |
| 227 by_user ? EventRouter::USER_GESTURE_ENABLED | 228 by_user ? EventRouter::USER_GESTURE_ENABLED |
| 228 : EventRouter::USER_GESTURE_NOT_ENABLED; | 229 : EventRouter::USER_GESTURE_NOT_ENABLED; |
| 229 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs()); | 230 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs()); |
| 230 args->AppendBoolean(by_user); | 231 args->AppendBoolean(by_user); |
| 231 SendEvent(events::NOTIFICATIONS_ON_CLOSED, | 232 SendEvent(events::NOTIFICATIONS_ON_CLOSED, |
| 232 notifications::OnClosed::kEventName, gesture, std::move(args)); | 233 notifications::OnClosed::kEventName, gesture, std::move(args)); |
| 234 | |
| 235 DCHECK(profile_); | |
| 236 ExtensionNotificationDisplayHelperFactory::GetForProfile(profile_) | |
| 237 ->EraseDataForNotificationId(scoped_id_); | |
| 233 } | 238 } |
| 234 | 239 |
| 235 void Click() override { | 240 void Click() override { |
| 236 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs()); | 241 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs()); |
| 237 SendEvent(events::NOTIFICATIONS_ON_CLICKED, | 242 SendEvent(events::NOTIFICATIONS_ON_CLICKED, |
| 238 notifications::OnClicked::kEventName, | 243 notifications::OnClicked::kEventName, |
| 239 EventRouter::USER_GESTURE_ENABLED, std::move(args)); | 244 EventRouter::USER_GESTURE_ENABLED, std::move(args)); |
| 240 } | 245 } |
| 241 | 246 |
| 242 bool HasClickedListener() override { | 247 bool HasClickedListener() override { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 if (!event_router_) | 300 if (!event_router_) |
| 296 return; | 301 return; |
| 297 | 302 |
| 298 std::unique_ptr<Event> event( | 303 std::unique_ptr<Event> event( |
| 299 new Event(histogram_value, name, std::move(args))); | 304 new Event(histogram_value, name, std::move(args))); |
| 300 event->user_gesture = user_gesture; | 305 event->user_gesture = user_gesture; |
| 301 event_router_->DispatchEventToExtension(extension_id_, std::move(event)); | 306 event_router_->DispatchEventToExtension(extension_id_, std::move(event)); |
| 302 } | 307 } |
| 303 | 308 |
| 304 void Shutdown() { | 309 void Shutdown() { |
| 310 // Make a copy of |profile_| so that the member can be nulled out. | |
| 311 Profile* profile = profile_; | |
| 312 | |
| 313 shutdown_notifier_subscription_.reset(); | |
| 305 event_router_ = nullptr; | 314 event_router_ = nullptr; |
| 306 shutdown_notifier_subscription_.reset(); | 315 profile_ = nullptr; |
| 316 | |
| 317 // The following call will result in deleting |this|. Do not access members | |
| 318 // after this, as you will be accessing invalid memory. | |
| 319 ExtensionNotificationDisplayHelperFactory::GetForProfile(profile)->Close( | |
|
Miguel Garcia
2017/02/21 10:56:43
Wouldn't it be safer to post it as a task then?
Peter Beverloo
2017/02/21 17:23:50
The issue there is that Shutdown() will be called
| |
| 320 scoped_id_); | |
| 307 } | 321 } |
| 308 | 322 |
| 309 std::unique_ptr<base::ListValue> CreateBaseEventArgs() { | 323 std::unique_ptr<base::ListValue> CreateBaseEventArgs() { |
| 310 std::unique_ptr<base::ListValue> args(new base::ListValue()); | 324 std::unique_ptr<base::ListValue> args(new base::ListValue()); |
| 311 args->AppendString(id_); | 325 args->AppendString(id_); |
| 312 return args; | 326 return args; |
| 313 } | 327 } |
| 314 | 328 |
| 315 scoped_refptr<ChromeAsyncExtensionFunction> api_function_; | 329 scoped_refptr<ChromeAsyncExtensionFunction> api_function_; |
| 316 | 330 |
| 317 // Since this class is refcounted it may outlive the profile. We listen for | 331 // Since this class is refcounted it may outlive the profile. We listen for |
| 318 // profile-keyed service shutdown events and reset to nullptr at that time, | 332 // profile-keyed service shutdown events and reset to nullptr at that time, |
| 319 // so make sure to check for a valid pointer before use. | 333 // so make sure to check for a valid pointer before use. |
| 320 EventRouter* event_router_; | 334 EventRouter* event_router_; |
| 335 Profile* profile_; | |
| 321 | 336 |
| 322 const std::string extension_id_; | 337 const std::string extension_id_; |
| 323 const std::string id_; | 338 const std::string id_; |
| 324 const std::string scoped_id_; | 339 const std::string scoped_id_; |
| 325 | 340 |
| 326 std::unique_ptr<KeyedServiceShutdownNotifier::Subscription> | 341 std::unique_ptr<KeyedServiceShutdownNotifier::Subscription> |
| 327 shutdown_notifier_subscription_; | 342 shutdown_notifier_subscription_; |
| 328 | 343 |
| 329 DISALLOW_COPY_AND_ASSIGN(NotificationsApiDelegate); | 344 DISALLOW_COPY_AND_ASSIGN(NotificationsApiDelegate); |
| 330 }; | 345 }; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 489 type, title, message, icon, | 504 type, title, message, icon, |
| 490 message_center::NotifierId(message_center::NotifierId::APPLICATION, | 505 message_center::NotifierId(message_center::NotifierId::APPLICATION, |
| 491 extension_->id()), | 506 extension_->id()), |
| 492 base::UTF8ToUTF16(extension_->name()), extension_->url(), | 507 base::UTF8ToUTF16(extension_->name()), extension_->url(), |
| 493 api_delegate->id(), optional_fields, api_delegate); | 508 api_delegate->id(), optional_fields, api_delegate); |
| 494 | 509 |
| 495 // Apply the "requireInteraction" flag. The value defaults to false. | 510 // Apply the "requireInteraction" flag. The value defaults to false. |
| 496 notification.set_never_timeout(options->require_interaction && | 511 notification.set_never_timeout(options->require_interaction && |
| 497 *options->require_interaction); | 512 *options->require_interaction); |
| 498 | 513 |
| 499 g_browser_process->notification_ui_manager()->Add(notification, GetProfile()); | 514 GetDisplayHelper()->Display(notification); |
| 500 return true; | 515 return true; |
| 501 } | 516 } |
| 502 | 517 |
| 503 bool NotificationsApiFunction::UpdateNotification( | 518 bool NotificationsApiFunction::UpdateNotification( |
| 504 const std::string& id, | 519 const std::string& id, |
| 505 api::notifications::NotificationOptions* options, | 520 api::notifications::NotificationOptions* options, |
| 506 Notification* notification) { | 521 Notification* notification) { |
| 507 #if !defined(OS_CHROMEOS) | 522 #if !defined(OS_CHROMEOS) |
| 508 if (options->priority && | 523 if (options->priority && |
| 509 *options->priority < message_center::DEFAULT_PRIORITY) { | 524 *options->priority < message_center::DEFAULT_PRIORITY) { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 623 base::UTF8ToUTF16(api_item.title), | 638 base::UTF8ToUTF16(api_item.title), |
| 624 base::UTF8ToUTF16(api_item.message))); | 639 base::UTF8ToUTF16(api_item.message))); |
| 625 } | 640 } |
| 626 notification->set_items(items); | 641 notification->set_items(items); |
| 627 } | 642 } |
| 628 | 643 |
| 629 // Then override if it's already set. | 644 // Then override if it's already set. |
| 630 if (options->is_clickable.get()) | 645 if (options->is_clickable.get()) |
| 631 notification->set_clickable(*options->is_clickable); | 646 notification->set_clickable(*options->is_clickable); |
| 632 | 647 |
| 633 g_browser_process->notification_ui_manager()->Update(*notification, | 648 // It's safe to follow the regular path for adding a new notification as it's |
| 634 GetProfile()); | 649 // already been verified that there is a notification that can be updated. |
| 650 GetDisplayHelper()->Display(*notification); | |
| 651 | |
| 635 return true; | 652 return true; |
| 636 } | 653 } |
| 637 | 654 |
| 638 bool NotificationsApiFunction::AreExtensionNotificationsAllowed() const { | 655 bool NotificationsApiFunction::AreExtensionNotificationsAllowed() const { |
| 639 NotifierStateTracker* notifier_state_tracker = | 656 NotifierStateTracker* notifier_state_tracker = |
| 640 NotifierStateTrackerFactory::GetForProfile(GetProfile()); | 657 NotifierStateTrackerFactory::GetForProfile(GetProfile()); |
| 641 | 658 |
| 642 return notifier_state_tracker->IsNotifierEnabled( | 659 return notifier_state_tracker->IsNotifierEnabled( |
| 643 message_center::NotifierId(message_center::NotifierId::APPLICATION, | 660 message_center::NotifierId(message_center::NotifierId::APPLICATION, |
| 644 extension_->id())); | 661 extension_->id())); |
| 645 } | 662 } |
| 646 | 663 |
| 647 bool NotificationsApiFunction::IsNotificationsApiEnabled() const { | 664 bool NotificationsApiFunction::IsNotificationsApiEnabled() const { |
| 648 return CanRunWhileDisabled() || AreExtensionNotificationsAllowed(); | 665 return CanRunWhileDisabled() || AreExtensionNotificationsAllowed(); |
| 649 } | 666 } |
| 650 | 667 |
| 651 bool NotificationsApiFunction::CanRunWhileDisabled() const { | 668 bool NotificationsApiFunction::CanRunWhileDisabled() const { |
| 652 return false; | 669 return false; |
| 653 } | 670 } |
| 654 | 671 |
| 672 ExtensionNotificationDisplayHelper* NotificationsApiFunction::GetDisplayHelper() | |
| 673 const { | |
| 674 return ExtensionNotificationDisplayHelperFactory::GetForProfile(GetProfile()); | |
| 675 } | |
| 676 | |
| 655 bool NotificationsApiFunction::RunAsync() { | 677 bool NotificationsApiFunction::RunAsync() { |
| 656 if (IsNotificationsApiAvailable() && IsNotificationsApiEnabled()) { | 678 if (IsNotificationsApiAvailable() && IsNotificationsApiEnabled()) { |
| 657 return RunNotificationsApi(); | 679 return RunNotificationsApi(); |
| 658 } else { | 680 } else { |
| 659 SendResponse(false); | 681 SendResponse(false); |
| 660 return true; | 682 return true; |
| 661 } | 683 } |
| 662 } | 684 } |
| 663 | 685 |
| 664 message_center::NotificationType | 686 message_center::NotificationType |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 721 NotificationsUpdateFunction::~NotificationsUpdateFunction() { | 743 NotificationsUpdateFunction::~NotificationsUpdateFunction() { |
| 722 } | 744 } |
| 723 | 745 |
| 724 bool NotificationsUpdateFunction::RunNotificationsApi() { | 746 bool NotificationsUpdateFunction::RunNotificationsApi() { |
| 725 params_ = api::notifications::Update::Params::Create(*args_); | 747 params_ = api::notifications::Update::Params::Create(*args_); |
| 726 EXTENSION_FUNCTION_VALIDATE(params_.get()); | 748 EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| 727 | 749 |
| 728 // We are in update. If the ID doesn't exist, succeed but call the callback | 750 // We are in update. If the ID doesn't exist, succeed but call the callback |
| 729 // with "false". | 751 // with "false". |
| 730 const Notification* matched_notification = | 752 const Notification* matched_notification = |
| 731 g_browser_process->notification_ui_manager()->FindById( | 753 GetDisplayHelper()->GetByNotificationId( |
| 732 CreateScopedIdentifier(extension_->id(), params_->notification_id), | 754 CreateScopedIdentifier(extension_->id(), params_->notification_id)); |
| 733 NotificationUIManager::GetProfileID(GetProfile())); | 755 |
| 734 if (!matched_notification) { | 756 if (!matched_notification) { |
| 735 SetResult(base::MakeUnique<base::FundamentalValue>(false)); | 757 SetResult(base::MakeUnique<base::FundamentalValue>(false)); |
| 736 SendResponse(true); | 758 SendResponse(true); |
| 737 return true; | 759 return true; |
| 738 } | 760 } |
| 739 | 761 |
| 740 // Copy the existing notification to get a writable version of it. | 762 // Copy the existing notification to get a writable version of it. |
| 741 Notification notification = *matched_notification; | 763 Notification notification = *matched_notification; |
| 742 | 764 |
| 743 // If we have trouble updating the notification (could be improper use of API | 765 // If we have trouble updating the notification (could be improper use of API |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 760 NotificationsClearFunction::NotificationsClearFunction() { | 782 NotificationsClearFunction::NotificationsClearFunction() { |
| 761 } | 783 } |
| 762 | 784 |
| 763 NotificationsClearFunction::~NotificationsClearFunction() { | 785 NotificationsClearFunction::~NotificationsClearFunction() { |
| 764 } | 786 } |
| 765 | 787 |
| 766 bool NotificationsClearFunction::RunNotificationsApi() { | 788 bool NotificationsClearFunction::RunNotificationsApi() { |
| 767 params_ = api::notifications::Clear::Params::Create(*args_); | 789 params_ = api::notifications::Clear::Params::Create(*args_); |
| 768 EXTENSION_FUNCTION_VALIDATE(params_.get()); | 790 EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| 769 | 791 |
| 770 bool cancel_result = g_browser_process->notification_ui_manager()->CancelById( | 792 bool cancel_result = GetDisplayHelper()->Close( |
| 771 CreateScopedIdentifier(extension_->id(), params_->notification_id), | 793 CreateScopedIdentifier(extension_->id(), params_->notification_id)); |
| 772 NotificationUIManager::GetProfileID(GetProfile())); | |
| 773 | 794 |
| 774 SetResult(base::MakeUnique<base::FundamentalValue>(cancel_result)); | 795 SetResult(base::MakeUnique<base::FundamentalValue>(cancel_result)); |
| 775 SendResponse(true); | 796 SendResponse(true); |
| 776 | 797 |
| 777 return true; | 798 return true; |
| 778 } | 799 } |
| 779 | 800 |
| 780 NotificationsGetAllFunction::NotificationsGetAllFunction() {} | 801 NotificationsGetAllFunction::NotificationsGetAllFunction() {} |
| 781 | 802 |
| 782 NotificationsGetAllFunction::~NotificationsGetAllFunction() {} | 803 NotificationsGetAllFunction::~NotificationsGetAllFunction() {} |
| 783 | 804 |
| 784 bool NotificationsGetAllFunction::RunNotificationsApi() { | 805 bool NotificationsGetAllFunction::RunNotificationsApi() { |
| 785 NotificationUIManager* notification_ui_manager = | |
| 786 g_browser_process->notification_ui_manager(); | |
| 787 std::set<std::string> notification_ids = | 806 std::set<std::string> notification_ids = |
| 788 notification_ui_manager->GetAllIdsByProfileAndSourceOrigin( | 807 GetDisplayHelper()->GetNotificationIdsForExtension(extension_->url()); |
| 789 NotificationUIManager::GetProfileID(GetProfile()), extension_->url()); | |
| 790 | 808 |
| 791 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 809 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 792 | 810 |
| 793 for (std::set<std::string>::iterator iter = notification_ids.begin(); | 811 for (std::set<std::string>::iterator iter = notification_ids.begin(); |
| 794 iter != notification_ids.end(); iter++) { | 812 iter != notification_ids.end(); iter++) { |
| 795 result->SetBooleanWithoutPathExpansion( | 813 result->SetBooleanWithoutPathExpansion( |
| 796 StripScopeFromIdentifier(extension_->id(), *iter), true); | 814 StripScopeFromIdentifier(extension_->id(), *iter), true); |
| 797 } | 815 } |
| 798 | 816 |
| 799 SetResult(std::move(result)); | 817 SetResult(std::move(result)); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 819 : api::notifications::PERMISSION_LEVEL_DENIED; | 837 : api::notifications::PERMISSION_LEVEL_DENIED; |
| 820 | 838 |
| 821 SetResult(base::MakeUnique<base::StringValue>( | 839 SetResult(base::MakeUnique<base::StringValue>( |
| 822 api::notifications::ToString(result))); | 840 api::notifications::ToString(result))); |
| 823 SendResponse(true); | 841 SendResponse(true); |
| 824 | 842 |
| 825 return true; | 843 return true; |
| 826 } | 844 } |
| 827 | 845 |
| 828 } // namespace extensions | 846 } // namespace extensions |
| OLD | NEW |