| // Copyright 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/pcie_peripheral/pcie_peripheral_notification_controller.h" |
| |
| #include <string> |
| |
| #include "ash/public/cpp/ash_pref_names.h" |
| #include "ash/public/cpp/new_window_delegate.h" |
| #include "ash/public/cpp/notification_utils.h" |
| #include "ash/public/cpp/system_tray_client.h" |
| #include "ash/resources/vector_icons/vector_icons.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/system/model/system_tray_model.h" |
| #include "base/optional.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| #include "ui/message_center/public/cpp/notification_types.h" |
| #include "url/gurl.h" |
| |
| namespace ash { |
| |
| namespace { |
| const char kNotifierPciePeripheral[] = "ash.pcie_peripheral"; |
| const char kLearnMoreHelpUrl[] = |
| "https://www.support.google.com/chromebook?p=connect_thblt_usb4_accy"; |
| const int kNotificationsClicksThreshold = 3; |
| |
| const char kPciePeripheralLimitedPerformanceNotificationId[] = |
| "cros_pcie_peripheral_limited_performance_notification_id"; |
| const char kPciePeripheralLimitedPerformanceGuestModeNotificationId[] = |
| "cros_pcie_peripheral_limited_performance_guest_mode_notification_id"; |
| const char kPciePeripheralGuestModeNotSupportedNotificationId[] = |
| "cros_pcie_peripheral_guest_mode_not_supported_notifcation_id"; |
| const char kPciePeripheralDeviceBlockedNotificationId[] = |
| "cros_pcie_peripheral_device_blocked_notifcation_id"; |
| |
| // Represents the buttons in the notification. |
| enum ButtonIndex { kSettings, kLearnMore }; |
| |
| int GetNotificationClickPrefCount() { |
| PrefService* prefs = |
| Shell::Get()->session_controller()->GetActivePrefService(); |
| |
| return prefs->GetInteger(prefs::kPciePeripheralDisplayNotificationRemaining); |
| } |
| |
| void UpdateNotificationPrefCount(bool clicked_settings) { |
| int current_pref_val = GetNotificationClickPrefCount(); |
| |
| // We're already not showing any new notifications, don't update. |
| if (current_pref_val == 0) |
| return; |
| |
| PrefService* prefs = |
| Shell::Get()->session_controller()->GetActivePrefService(); |
| |
| // If the user has reached the settings page through the notification, do |
| // not show any more new notifications. |
| if (clicked_settings) { |
| prefs->SetInteger(prefs::kPciePeripheralDisplayNotificationRemaining, 0); |
| return; |
| } |
| |
| // Otherwise, decrement the pref count. |
| prefs->SetInteger(prefs::kPciePeripheralDisplayNotificationRemaining, |
| current_pref_val - 1); |
| } |
| |
| void ShowPrivacyAndSecuritySettings() { |
| Shell::Get()->system_tray_model()->client()->ShowPrivacyAndSecuritySettings(); |
| } |
| |
| void RemoveNotification(const std::string& notification_id) { |
| message_center::MessageCenter::Get()->RemoveNotification(notification_id, |
| /*from_user=*/true); |
| } |
| |
| void OnPeripheralLimitedNotificationClicked(base::Optional<int> button_index) { |
| // Clicked on body. |
| if (!button_index) { |
| ShowPrivacyAndSecuritySettings(); |
| UpdateNotificationPrefCount(/*clicked_settings=*/true); |
| RemoveNotification(kPciePeripheralLimitedPerformanceNotificationId); |
| return; |
| } |
| |
| switch (*button_index) { |
| case ButtonIndex::kSettings: |
| ShowPrivacyAndSecuritySettings(); |
| UpdateNotificationPrefCount(/*clicked_settings=*/true); |
| break; |
| case ButtonIndex::kLearnMore: |
| NewWindowDelegate::GetInstance()->NewTabWithUrl( |
| GURL(kLearnMoreHelpUrl), /*from_user_interaction=*/true); |
| break; |
| } |
| RemoveNotification(kPciePeripheralLimitedPerformanceNotificationId); |
| } |
| |
| void OnGuestNotificationClicked(bool is_thunderbolt_only) { |
| NewWindowDelegate::GetInstance()->NewTabWithUrl( |
| GURL(kLearnMoreHelpUrl), /*from_user_interaction=*/true); |
| |
| if (is_thunderbolt_only) { |
| RemoveNotification(kPciePeripheralGuestModeNotSupportedNotificationId); |
| return; |
| } |
| |
| RemoveNotification(kPciePeripheralLimitedPerformanceGuestModeNotificationId); |
| } |
| |
| void OnPeripheralBlockedNotificationClicked() { |
| NewWindowDelegate::GetInstance()->NewTabWithUrl( |
| GURL(kLearnMoreHelpUrl), /*from_user_interaction=*/true); |
| RemoveNotification(kPciePeripheralDeviceBlockedNotificationId); |
| } |
| |
| // We only display notifications for active user sessions (signed-in/guest with |
| // desktop ready). Also do not show notifications in signin or lock screen. |
| bool ShouldDisplayNotification() { |
| return Shell::Get()->session_controller()->GetSessionState() == |
| session_manager::SessionState::ACTIVE && |
| !Shell::Get()->session_controller()->IsUserSessionBlocked(); |
| } |
| |
| } // namespace |
| |
| PciePeripheralNotificationController::PciePeripheralNotificationController( |
| message_center::MessageCenter* message_center) |
| : message_center_(message_center) { |
| DCHECK(message_center_); |
| } |
| |
| PciePeripheralNotificationController::~PciePeripheralNotificationController() { |
| if (ash::PciePeripheralManager::IsInitialized()) |
| ash::PciePeripheralManager::Get()->RemoveObserver(this); |
| } |
| |
| void PciePeripheralNotificationController:: |
| OnPciePeripheralManagerInitialized() { |
| DCHECK(ash::PciePeripheralManager::IsInitialized()); |
| |
| ash::PciePeripheralManager::Get()->AddObserver(this); |
| } |
| |
| void PciePeripheralNotificationController::NotifyLimitedPerformance() { |
| // Don't show the notification if the user has already clicked on the |
| // notification three times. |
| if (!ShouldDisplayNotification() || GetNotificationClickPrefCount() == 0) |
| return; |
| |
| message_center::RichNotificationData optional; |
| optional.buttons.push_back( |
| message_center::ButtonInfo(l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_SETTINGS_BUTTON_TEXT))); |
| optional.buttons.push_back( |
| message_center::ButtonInfo(l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_LEARN_MORE_BUTTON_TEXT))); |
| |
| std::unique_ptr<message_center::Notification> notification = |
| CreateSystemNotification( |
| message_center::NOTIFICATION_TYPE_SIMPLE, |
| kPciePeripheralLimitedPerformanceNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_PERFORMANCE_LIMITED_TITLE), |
| l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_PERFORMANCE_LIMITED_BODY), |
| /*display_source=*/std::u16string(), GURL(), |
| message_center::NotifierId( |
| message_center::NotifierType::SYSTEM_COMPONENT, |
| kNotifierPciePeripheral), |
| optional, |
| base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( |
| base::BindRepeating(&OnPeripheralLimitedNotificationClicked)), |
| kSettingsIcon, |
| message_center::SystemNotificationWarningLevel::WARNING); |
| |
| message_center_->AddNotification(std::move(notification)); |
| UpdateNotificationPrefCount(/*clicked_settings=*/false); |
| } |
| |
| void PciePeripheralNotificationController::NotifyGuestModeNotification( |
| bool is_thunderbolt_only) { |
| if (!ShouldDisplayNotification()) |
| return; |
| |
| std::unique_ptr<message_center::Notification> notification = CreateSystemNotification( |
| message_center::NOTIFICATION_TYPE_SIMPLE, |
| is_thunderbolt_only |
| ? kPciePeripheralGuestModeNotSupportedNotificationId |
| : kPciePeripheralLimitedPerformanceGuestModeNotificationId, |
| /*title=*/std::u16string(), |
| is_thunderbolt_only |
| ? l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_GUEST_MODE_NOT_SUPPORTED) |
| : l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_PERFORMANCE_LIMITED_GUEST_MODE), |
| /*display_source=*/std::u16string(), GURL(), |
| message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT, |
| kNotifierPciePeripheral), |
| message_center::RichNotificationData(), |
| base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( |
| base::BindRepeating(&OnGuestNotificationClicked, |
| is_thunderbolt_only)), |
| kSettingsIcon, |
| is_thunderbolt_only |
| ? message_center::SystemNotificationWarningLevel::CRITICAL_WARNING |
| : message_center::SystemNotificationWarningLevel::WARNING); |
| |
| message_center_->AddNotification(std::move(notification)); |
| } |
| |
| void PciePeripheralNotificationController:: |
| NotifyPeripheralBlockedNotification() { |
| std::unique_ptr<message_center::Notification> notification = |
| CreateSystemNotification( |
| message_center::NOTIFICATION_TYPE_SIMPLE, |
| kPciePeripheralDeviceBlockedNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE), |
| l10n_util::GetStringUTF16( |
| IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY), |
| /*display_source=*/std::u16string(), GURL(), |
| message_center::NotifierId( |
| message_center::NotifierType::SYSTEM_COMPONENT, |
| kNotifierPciePeripheral), |
| message_center::RichNotificationData(), |
| base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( |
| base::BindRepeating(&OnPeripheralBlockedNotificationClicked)), |
| kSettingsIcon, |
| message_center::SystemNotificationWarningLevel::CRITICAL_WARNING); |
| |
| message_center_->AddNotification(std::move(notification)); |
| } |
| |
| void PciePeripheralNotificationController:: |
| OnLimitedPerformancePeripheralReceived() { |
| NotifyLimitedPerformance(); |
| } |
| |
| void PciePeripheralNotificationController::OnGuestModeNotificationReceived( |
| bool is_thunderbolt_only) { |
| NotifyGuestModeNotification(is_thunderbolt_only); |
| } |
| |
| void PciePeripheralNotificationController::OnPeripheralBlockedReceived() { |
| NotifyPeripheralBlockedNotification(); |
| } |
| |
| // static |
| void PciePeripheralNotificationController::RegisterProfilePrefs( |
| PrefRegistrySimple* registry) { |
| // By default, we let the user click on the notifications three times before |
| // hiding future notifications. |
| registry->RegisterIntegerPref( |
| prefs::kPciePeripheralDisplayNotificationRemaining, |
| kNotificationsClicksThreshold); |
| } |
| } // namespace ash |