issue_manager.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/media_router/browser/issue_manager.h"
  5. #include <algorithm>
  6. #include "base/bind.h"
  7. #include "base/observer_list.h"
  8. #include "base/time/time.h"
  9. #include "content/public/browser/browser_task_traits.h"
  10. #include "content/public/browser/browser_thread.h"
  11. namespace media_router {
  12. namespace {
  13. // The number of minutes a NOTIFICATION Issue stays in the IssueManager
  14. // before it is auto-dismissed.
  15. constexpr int kNotificationAutoDismissMins = 1;
  16. // The number of minutes a WARNING Issue stays in the IssueManager before it
  17. // is auto-dismissed.
  18. constexpr int kWarningAutoDismissMins = 5;
  19. } // namespace
  20. // static
  21. base::TimeDelta IssueManager::GetAutoDismissTimeout(
  22. const IssueInfo& issue_info) {
  23. if (issue_info.is_blocking)
  24. return base::TimeDelta();
  25. switch (issue_info.severity) {
  26. case IssueInfo::Severity::NOTIFICATION:
  27. return base::Minutes(kNotificationAutoDismissMins);
  28. case IssueInfo::Severity::WARNING:
  29. return base::Minutes(kWarningAutoDismissMins);
  30. case IssueInfo::Severity::FATAL:
  31. NOTREACHED() << "FATAL issues should be blocking";
  32. return base::TimeDelta();
  33. }
  34. NOTREACHED();
  35. return base::TimeDelta();
  36. }
  37. IssueManager::IssueManager()
  38. : top_issue_(nullptr), task_runner_(content::GetUIThreadTaskRunner({})) {}
  39. IssueManager::~IssueManager() {
  40. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  41. }
  42. void IssueManager::AddIssue(const IssueInfo& issue_info) {
  43. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  44. auto& issues_map =
  45. issue_info.is_blocking ? blocking_issues_ : non_blocking_issues_;
  46. for (const auto& key_value_pair : issues_map) {
  47. const auto& issue = key_value_pair.second->issue;
  48. if (issue.info() == issue_info)
  49. return;
  50. }
  51. Issue issue(issue_info);
  52. std::unique_ptr<base::CancelableOnceClosure> cancelable_dismiss_cb;
  53. base::TimeDelta timeout = GetAutoDismissTimeout(issue_info);
  54. if (!timeout.is_zero()) {
  55. cancelable_dismiss_cb =
  56. std::make_unique<base::CancelableOnceClosure>(base::BindOnce(
  57. &IssueManager::ClearIssue, base::Unretained(this), issue.id()));
  58. task_runner_->PostDelayedTask(FROM_HERE, cancelable_dismiss_cb->callback(),
  59. timeout);
  60. }
  61. issues_map.emplace(issue.id(), std::make_unique<IssueManager::Entry>(
  62. issue, std::move(cancelable_dismiss_cb)));
  63. MaybeUpdateTopIssue();
  64. }
  65. void IssueManager::ClearIssue(const Issue::Id& issue_id) {
  66. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  67. if (non_blocking_issues_.erase(issue_id) || blocking_issues_.erase(issue_id))
  68. MaybeUpdateTopIssue();
  69. }
  70. void IssueManager::ClearNonBlockingIssues() {
  71. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  72. if (non_blocking_issues_.empty())
  73. return;
  74. non_blocking_issues_.clear();
  75. MaybeUpdateTopIssue();
  76. }
  77. void IssueManager::RegisterObserver(IssuesObserver* observer) {
  78. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  79. DCHECK(observer);
  80. DCHECK(!issues_observers_.HasObserver(observer));
  81. issues_observers_.AddObserver(observer);
  82. if (top_issue_)
  83. observer->OnIssue(*top_issue_);
  84. }
  85. void IssueManager::UnregisterObserver(IssuesObserver* observer) {
  86. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  87. issues_observers_.RemoveObserver(observer);
  88. }
  89. IssueManager::Entry::Entry(
  90. const Issue& issue,
  91. std::unique_ptr<base::CancelableOnceClosure> cancelable_dismiss_callback)
  92. : issue(issue),
  93. cancelable_dismiss_callback(std::move(cancelable_dismiss_callback)) {}
  94. IssueManager::Entry::~Entry() = default;
  95. void IssueManager::MaybeUpdateTopIssue() {
  96. const Issue* new_top_issue = nullptr;
  97. // Select the first blocking issue in the list of issues.
  98. // If there are none, simply select the first issue in the list.
  99. if (!blocking_issues_.empty()) {
  100. new_top_issue = &blocking_issues_.begin()->second->issue;
  101. } else if (!non_blocking_issues_.empty()) {
  102. new_top_issue = &non_blocking_issues_.begin()->second->issue;
  103. }
  104. // If we've found a new top issue, then report it via the observer.
  105. if (new_top_issue != top_issue_) {
  106. top_issue_ = new_top_issue;
  107. for (auto& observer : issues_observers_) {
  108. if (top_issue_)
  109. observer.OnIssue(*top_issue_);
  110. else
  111. observer.OnIssuesCleared();
  112. }
  113. }
  114. }
  115. } // namespace media_router