screen_security_notification_controller.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright 2018 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 "ash/system/screen_security/screen_security_notification_controller.h"
  5. #include "ash/constants/notifier_catalogs.h"
  6. #include "ash/public/cpp/notification_utils.h"
  7. #include "ash/resources/vector_icons/vector_icons.h"
  8. #include "ash/shell.h"
  9. #include "ash/strings/grit/ash_strings.h"
  10. #include "ash/system/tray/system_tray_notifier.h"
  11. #include "base/bind.h"
  12. #include "base/metrics/user_metrics.h"
  13. #include "ui/base/l10n/l10n_util.h"
  14. #include "ui/message_center/message_center.h"
  15. #include "ui/message_center/public/cpp/notification.h"
  16. #include "ui/message_center/public/cpp/notification_delegate.h"
  17. using message_center::MessageCenter;
  18. using message_center::Notification;
  19. namespace ash {
  20. // It is possible that we are capturing and sharing screen at the same time, so
  21. // we cannot share the notification IDs for capturing and sharing.
  22. const char kScreenCaptureNotificationId[] = "chrome://screen/capture";
  23. const char kScreenShareNotificationId[] = "chrome://screen/share";
  24. const char kNotifierScreenCapture[] = "ash.screen-capture";
  25. const char kNotifierScreenShare[] = "ash.screen-share";
  26. ScreenSecurityNotificationController::ScreenSecurityNotificationController() {
  27. Shell::Get()->AddShellObserver(this);
  28. Shell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this);
  29. Shell::Get()->system_tray_notifier()->AddScreenShareObserver(this);
  30. }
  31. ScreenSecurityNotificationController::~ScreenSecurityNotificationController() {
  32. Shell::Get()->system_tray_notifier()->RemoveScreenShareObserver(this);
  33. Shell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this);
  34. Shell::Get()->RemoveShellObserver(this);
  35. }
  36. void ScreenSecurityNotificationController::CreateNotification(
  37. const std::u16string& message,
  38. bool is_capture) {
  39. message_center::RichNotificationData data;
  40. data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16(
  41. is_capture ? IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP
  42. : IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP)));
  43. // Only add "Change source" button when there is one session, since there
  44. // isn't a good UI to distinguish between the different sessions.
  45. if (is_capture && change_source_callback_ &&
  46. capture_stop_callbacks_.size() == 1) {
  47. data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16(
  48. IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_CHANGE_SOURCE)));
  49. }
  50. auto delegate =
  51. base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
  52. base::BindRepeating(
  53. [](base::WeakPtr<ScreenSecurityNotificationController> controller,
  54. bool is_capture, absl::optional<int> button_index) {
  55. if (!button_index)
  56. return;
  57. if (*button_index == 0) {
  58. controller->StopAllSessions(is_capture);
  59. if (is_capture) {
  60. base::RecordAction(base::UserMetricsAction(
  61. "StatusArea_ScreenCapture_Notification_Stop"));
  62. }
  63. } else if (*button_index == 1) {
  64. controller->ChangeSource();
  65. if (is_capture) {
  66. base::RecordAction(base::UserMetricsAction(
  67. "StatusArea_ScreenCapture_Change_Source"));
  68. }
  69. } else {
  70. NOTREACHED();
  71. }
  72. },
  73. weak_ptr_factory_.GetWeakPtr(), is_capture));
  74. std::unique_ptr<Notification> notification = CreateSystemNotification(
  75. message_center::NOTIFICATION_TYPE_SIMPLE,
  76. is_capture ? kScreenCaptureNotificationId : kScreenShareNotificationId,
  77. l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_TITLE),
  78. message, std::u16string() /* display_source */, GURL(),
  79. message_center::NotifierId(
  80. message_center::NotifierType::SYSTEM_COMPONENT,
  81. is_capture ? kNotifierScreenCapture : kNotifierScreenShare,
  82. NotificationCatalogName::kScreenSecurity),
  83. data, std::move(delegate), kNotificationScreenshareIcon,
  84. message_center::SystemNotificationWarningLevel::NORMAL);
  85. notification->set_pinned(true);
  86. message_center::MessageCenter::Get()->AddNotification(
  87. std::move(notification));
  88. }
  89. void ScreenSecurityNotificationController::StopAllSessions(bool is_capture) {
  90. message_center::MessageCenter::Get()->RemoveNotification(
  91. is_capture ? kScreenCaptureNotificationId : kScreenShareNotificationId,
  92. false /* by_user */);
  93. std::vector<base::OnceClosure> callbacks;
  94. std::swap(callbacks,
  95. is_capture ? capture_stop_callbacks_ : share_stop_callbacks_);
  96. for (base::OnceClosure& callback : callbacks) {
  97. if (callback)
  98. std::move(callback).Run();
  99. }
  100. change_source_callback_.Reset();
  101. }
  102. void ScreenSecurityNotificationController::ChangeSource() {
  103. if (change_source_callback_ && capture_stop_callbacks_.size() == 1)
  104. change_source_callback_.Run();
  105. }
  106. void ScreenSecurityNotificationController::OnScreenCaptureStart(
  107. const base::RepeatingClosure& stop_callback,
  108. const base::RepeatingClosure& source_callback,
  109. const std::u16string& screen_capture_status) {
  110. capture_stop_callbacks_.push_back(stop_callback);
  111. change_source_callback_ = source_callback;
  112. // We do not want to show the screen capture notification and the chromecast
  113. // casting tray notification at the same time.
  114. //
  115. // This suppression technique is currently dependent on the order
  116. // that OnScreenCaptureStart and OnCastingSessionStartedOrStopped
  117. // get invoked. OnCastingSessionStartedOrStopped currently gets
  118. // called first.
  119. if (is_casting_)
  120. return;
  121. CreateNotification(screen_capture_status, true /* is_capture */);
  122. }
  123. void ScreenSecurityNotificationController::OnScreenCaptureStop() {
  124. StopAllSessions(true /* is_capture */);
  125. }
  126. void ScreenSecurityNotificationController::OnScreenShareStart(
  127. const base::RepeatingClosure& stop_callback,
  128. const std::u16string& helper_name) {
  129. share_stop_callbacks_.emplace_back(std::move(stop_callback));
  130. std::u16string help_label_text;
  131. if (!helper_name.empty()) {
  132. help_label_text = l10n_util::GetStringFUTF16(
  133. IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED_NAME, helper_name);
  134. } else {
  135. help_label_text = l10n_util::GetStringUTF16(
  136. IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED);
  137. }
  138. CreateNotification(help_label_text, false /* is_capture */);
  139. }
  140. void ScreenSecurityNotificationController::OnScreenShareStop() {
  141. StopAllSessions(false /* is_capture */);
  142. }
  143. void ScreenSecurityNotificationController::OnCastingSessionStartedOrStopped(
  144. bool started) {
  145. is_casting_ = started;
  146. }
  147. } // namespace ash