| // 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/network/cellular_setup_notifier.h" |
| |
| #include "ash/public/cpp/ash_pref_names.h" |
| #include "ash/public/cpp/network_config_service.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/bind.h" |
| #include "base/timer/timer.h" |
| #include "components/onc/onc_constants.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/vector_icons/vector_icons.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/public/cpp/message_center_constants.h" |
| |
| namespace ash { |
| namespace { |
| |
| const char kNotifierCellularSetup[] = "ash.cellular-setup"; |
| |
| // Delay after OOBE until notification should be shown. |
| constexpr base::TimeDelta kNotificationDelay = base::TimeDelta::FromMinutes(15); |
| |
| bool DoesCellularDeviceExist( |
| const std::vector< |
| chromeos::network_config::mojom::DeviceStatePropertiesPtr>& devices) { |
| for (const auto& device : devices) { |
| if (device->type == |
| chromeos::network_config::mojom::NetworkType::kCellular) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void OnCellularSetupNotificationClicked() { |
| Shell::Get()->system_tray_model()->client()->ShowNetworkCreate( |
| ::onc::network_type::kCellular); |
| } |
| |
| // Returns the value of kCanCellularSetupNotificationBeShown for the last active |
| // user. If the last active user's PrefService is null, returns false. |
| bool GetCanCellularSetupNotificationBeShown() { |
| PrefService* prefs = |
| Shell::Get()->session_controller()->GetLastActiveUserPrefService(); |
| if (!prefs) { |
| // Return false because we don't want to show the notification if we're |
| // unsure if it can be shown or not. |
| return false; |
| } |
| return prefs->GetBoolean(prefs::kCanCellularSetupNotificationBeShown); |
| } |
| |
| // Sets kCanCellularSetupNotificationBeShown to false for the last active user. |
| // Returns true if the flag was successfully set, and false if not. |
| bool SetCellularSetupNotificationCannotBeShown() { |
| PrefService* prefs = |
| Shell::Get()->session_controller()->GetLastActiveUserPrefService(); |
| if (!prefs) { |
| return false; |
| } |
| prefs->SetBoolean(prefs::kCanCellularSetupNotificationBeShown, false); |
| return true; |
| } |
| |
| } // namespace |
| |
| // static |
| void CellularSetupNotifier::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
| // Default value is true as we usually want to show the notification except |
| // for specific conditions (cellular-incapable device, already shown). |
| registry->RegisterBooleanPref(prefs::kCanCellularSetupNotificationBeShown, |
| true); |
| } |
| |
| // static |
| const char CellularSetupNotifier::kCellularSetupNotificationId[] = |
| "cros_cellular_setup_notifier_ids.setup_network"; |
| |
| CellularSetupNotifier::CellularSetupNotifier() |
| : timer_(std::make_unique<base::OneShotTimer>()) { |
| GetNetworkConfigService( |
| remote_cros_network_config_.BindNewPipeAndPassReceiver()); |
| remote_cros_network_config_->AddObserver( |
| cros_network_config_observer_receiver_.BindNewPipeAndPassRemote()); |
| Shell::Get()->session_controller()->AddObserver(this); |
| } |
| |
| CellularSetupNotifier::~CellularSetupNotifier() { |
| Shell::Get()->session_controller()->RemoveObserver(this); |
| } |
| |
| void CellularSetupNotifier::OnSessionStateChanged( |
| session_manager::SessionState state) { |
| if (Shell::Get()->session_controller()->GetSessionState() != |
| session_manager::SessionState::ACTIVE) { |
| timer_->Stop(); |
| return; |
| } |
| |
| if (!GetCanCellularSetupNotificationBeShown()) { |
| // The notification has already been shown or there is some condition that |
| // dictates that the notification shouldn't be shown. |
| return; |
| } |
| |
| // Wait |kNotificationDelay| after the user logs in before attempting to show |
| // a notification. This allows the user time to set up a cellular network if |
| // they desire, and it also ensures we don't spam the user with an extra |
| // notification just after they log into their device for the first time. |
| timer_->Start(FROM_HERE, kNotificationDelay, |
| base::BindOnce(&CellularSetupNotifier::OnTimerFired, |
| base::Unretained(this))); |
| } |
| |
| void CellularSetupNotifier::OnTimerFired() { |
| timer_fired_ = true; |
| MaybeShowCellularSetupNotification(); |
| } |
| |
| void CellularSetupNotifier::OnNetworkStateListChanged() { |
| MaybeShowCellularSetupNotification(); |
| } |
| |
| void CellularSetupNotifier::OnNetworkStateChanged( |
| chromeos::network_config::mojom::NetworkStatePropertiesPtr network) { |
| if (network->type != |
| chromeos::network_config::mojom::NetworkType::kCellular || |
| network->type_state->get_cellular()->activation_state != |
| chromeos::network_config::mojom::ActivationStateType::kActivated) { |
| return; |
| } |
| |
| SetCellularSetupNotificationCannotBeShown(); |
| message_center::MessageCenter* message_center = |
| message_center::MessageCenter::Get(); |
| message_center->RemoveNotification(kCellularSetupNotificationId, false); |
| } |
| |
| void CellularSetupNotifier::MaybeShowCellularSetupNotification() { |
| remote_cros_network_config_->GetDeviceStateList(base::BindOnce( |
| &CellularSetupNotifier::OnGetDeviceStateList, base::Unretained(this))); |
| } |
| |
| void CellularSetupNotifier::OnGetDeviceStateList( |
| std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr> |
| devices) { |
| if (!DoesCellularDeviceExist(devices)) { |
| // Save to prefs not to show this notification again so we don't keep |
| // starting the timer for a cellular-incapable device. |
| SetCellularSetupNotificationCannotBeShown(); |
| return; |
| } |
| remote_cros_network_config_->GetNetworkStateList( |
| chromeos::network_config::mojom::NetworkFilter::New( |
| chromeos::network_config::mojom::FilterType::kAll, |
| chromeos::network_config::mojom::NetworkType::kCellular, |
| chromeos::network_config::mojom::kNoLimit), |
| base::BindOnce(&CellularSetupNotifier::OnCellularNetworksList, |
| base::Unretained(this))); |
| } |
| |
| void CellularSetupNotifier::OnCellularNetworksList( |
| std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr> |
| networks) { |
| // Check if there are any activated pSIM or eSIM networks. The activation |
| // state property is set to activated for all eSIM services. |
| for (auto& network : networks) { |
| if (network->type_state->get_cellular()->activation_state == |
| chromeos::network_config::mojom::ActivationStateType::kActivated) { |
| // Save to prefs not to try to show this notification again so we don't |
| // keep starting the timer for a user who already has an activated |
| // cellular network. |
| SetCellularSetupNotificationCannotBeShown(); |
| message_center::MessageCenter* message_center = |
| message_center::MessageCenter::Get(); |
| message_center->RemoveNotification(kCellularSetupNotificationId, false); |
| return; |
| } |
| } |
| |
| // Do not show notification if it has already been shown, or the timer |
| // has not yet been fired. |
| if (!GetCanCellularSetupNotificationBeShown() || !timer_fired_) { |
| return; |
| } |
| |
| ShowCellularSetupNotification(); |
| } |
| |
| // Shows the Cellular Setup notification except in cases where it is unable to |
| // save that it will have shown the notification. |
| void CellularSetupNotifier::ShowCellularSetupNotification() { |
| if (!SetCellularSetupNotificationCannotBeShown()) { |
| // If we didn't successfully set the flag, don't show the notification or |
| // else we may show the notification multiple times. |
| return; |
| } |
| |
| std::unique_ptr<message_center::Notification> notification = |
| ash::CreateSystemNotification( |
| message_center::NOTIFICATION_TYPE_SIMPLE, |
| kCellularSetupNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_ASH_NETWORK_CELLULAR_SETUP_NOTIFICATION_TITLE), |
| l10n_util::GetStringUTF16( |
| IDS_ASH_NETWORK_CELLULAR_SETUP_NOTIFICATION_MESSAGE), |
| /*display_source=*/std::u16string(), GURL(), |
| message_center::NotifierId( |
| message_center::NotifierType::SYSTEM_COMPONENT, |
| kNotifierCellularSetup), |
| message_center::RichNotificationData(), |
| base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( |
| base::BindRepeating(&OnCellularSetupNotificationClicked)), |
| kAddCellularNetworkIcon, |
| message_center::SystemNotificationWarningLevel::NORMAL); |
| |
| message_center::MessageCenter* message_center = |
| message_center::MessageCenter::Get(); |
| if (message_center->FindVisibleNotificationById(kCellularSetupNotificationId)) |
| message_center->RemoveNotification(kCellularSetupNotificationId, false); |
| message_center->AddNotification(std::move(notification)); |
| } |
| |
| } // namespace ash |