| // Copyright 2017 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 "chrome/browser/chromeos/net/tether_notification_presenter.h" |
| |
| #include "base/bind.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/proximity_auth/logging/logging.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/color_palette.h" |
| #include "ui/gfx/image/image.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/notification_types.h" |
| #include "ui/message_center/notifier_settings.h" |
| |
| namespace chromeos { |
| |
| namespace tether { |
| |
| namespace { |
| |
| // Mean value of NetworkStat's signal_strength() range. |
| const int kMediumSignalStrength = 50; |
| |
| // Dimensions of Tether notification icon in pixels. |
| constexpr gfx::Size kTetherSignalIconSize(40, 40); |
| |
| const char kTetherSettingsSubpage[] = "networks?type=Tether"; |
| |
| class SettingsUiDelegateImpl |
| : public TetherNotificationPresenter::SettingsUiDelegate { |
| public: |
| SettingsUiDelegateImpl() {} |
| ~SettingsUiDelegateImpl() override {} |
| |
| void ShowSettingsSubPageForProfile(Profile* profile, |
| const std::string& sub_page) override { |
| chrome::ShowSettingsSubPageForProfile(profile, sub_page); |
| } |
| }; |
| |
| // Gets the normalized signal strength that can range from 0 to 4. This return |
| // value is then used to get an appropriate image to display on the |
| // notification. Defaults to full signal strength (4) if |signal_strength| |
| // is out of bounds. |
| int GetNormalizedSignalStrength(int signal_strength) { |
| int normalized_signal_strength = signal_strength / 25; |
| return std::min(std::max(normalized_signal_strength, 0), 4); |
| } |
| |
| } // namespace |
| |
| // static |
| constexpr const char TetherNotificationPresenter::kTetherNotifierId[] = |
| "cros_tether_notification_ids.notifier_id"; |
| |
| // static |
| constexpr const char TetherNotificationPresenter::kActiveHostNotificationId[] = |
| "cros_tether_notification_ids.active_host"; |
| |
| // static |
| constexpr const char |
| TetherNotificationPresenter::kPotentialHotspotNotificationId[] = |
| "cros_tether_notification_ids.potential_hotspot"; |
| |
| // static |
| constexpr const char |
| TetherNotificationPresenter::kSetupRequiredNotificationId[] = |
| "cros_tether_notification_ids.setup_required"; |
| |
| // static |
| constexpr const char |
| TetherNotificationPresenter::kEnableBluetoothNotificationId[] = |
| "cros_tether_notification_ids.enable_bluetooth"; |
| |
| // static |
| constexpr const char* const |
| TetherNotificationPresenter::kIdsWhichOpenTetherSettingsOnClick[] = { |
| TetherNotificationPresenter::kTetherNotifierId, |
| TetherNotificationPresenter::kActiveHostNotificationId, |
| TetherNotificationPresenter::kPotentialHotspotNotificationId, |
| TetherNotificationPresenter::kSetupRequiredNotificationId}; |
| |
| // static |
| std::unique_ptr<message_center::Notification> |
| TetherNotificationPresenter::CreateNotificationWithMediumSignalStrengthIcon( |
| const std::string& id, |
| const base::string16& title, |
| const base::string16& message) { |
| return CreateNotification(id, title, message, |
| message_center::RichNotificationData(), |
| kMediumSignalStrength); |
| } |
| |
| // static |
| std::unique_ptr<message_center::Notification> |
| TetherNotificationPresenter::CreateNotification( |
| const std::string& id, |
| const base::string16& title, |
| const base::string16& message, |
| const message_center::RichNotificationData rich_notification_data, |
| int signal_strength) { |
| auto source = base::MakeUnique<ash::network_icon::SignalStrengthImageSource>( |
| ash::network_icon::BARS, gfx::kGoogleBlue500, kTetherSignalIconSize, |
| GetNormalizedSignalStrength(signal_strength)); |
| return base::MakeUnique<message_center::Notification>( |
| message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title, |
| message, |
| gfx::Image(gfx::ImageSkia(std::move(source), kTetherSignalIconSize)), |
| base::string16() /* display_source */, GURL() /* origin_url */, |
| message_center::NotifierId( |
| message_center::NotifierId::NotifierType::SYSTEM_COMPONENT, |
| kTetherNotifierId), |
| rich_notification_data, nullptr); |
| } |
| |
| TetherNotificationPresenter::TetherNotificationPresenter( |
| Profile* profile, |
| message_center::MessageCenter* message_center, |
| NetworkConnect* network_connect) |
| : profile_(profile), |
| message_center_(message_center), |
| network_connect_(network_connect), |
| settings_ui_delegate_(base::WrapUnique(new SettingsUiDelegateImpl())), |
| weak_ptr_factory_(this) { |
| message_center_->AddObserver(this); |
| } |
| |
| TetherNotificationPresenter::~TetherNotificationPresenter() { |
| message_center_->RemoveObserver(this); |
| } |
| |
| void TetherNotificationPresenter::NotifyPotentialHotspotNearby( |
| const cryptauth::RemoteDevice& remote_device, |
| int signal_strength) { |
| PA_LOG(INFO) << "Displaying \"potential hotspot nearby\" notification for " |
| << "device with name \"" << remote_device.name << "\". " |
| << "Notification ID = " << kPotentialHotspotNotificationId; |
| |
| hotspot_nearby_device_ = remote_device; |
| |
| message_center::RichNotificationData rich_notification_data; |
| rich_notification_data.buttons.push_back( |
| message_center::ButtonInfo(l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_ONE_DEVICE_CONNECT))); |
| ShowNotification(CreateNotification( |
| kPotentialHotspotNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_ONE_DEVICE_TITLE), |
| l10n_util::GetStringFUTF16( |
| IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_ONE_DEVICE_MESSAGE, |
| base::ASCIIToUTF16(hotspot_nearby_device_.name)), |
| rich_notification_data, signal_strength)); |
| } |
| |
| void TetherNotificationPresenter::NotifyMultiplePotentialHotspotsNearby() { |
| PA_LOG(INFO) << "Displaying \"potential hotspot nearby\" notification for " |
| << "multiple devices. Notification ID = " |
| << kPotentialHotspotNotificationId; |
| |
| ShowNotification(CreateNotificationWithMediumSignalStrengthIcon( |
| kPotentialHotspotNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_MULTIPLE_DEVICES_TITLE), |
| l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_WIFI_AVAILABLE_MULTIPLE_DEVICES_MESSAGE))); |
| } |
| |
| void TetherNotificationPresenter::RemovePotentialHotspotNotification() { |
| RemoveNotificationIfVisible(kPotentialHotspotNotificationId); |
| } |
| |
| void TetherNotificationPresenter::NotifySetupRequired( |
| const std::string& device_name) { |
| PA_LOG(INFO) << "Displaying \"setup required\" notification. Notification " |
| << "ID = " << kSetupRequiredNotificationId; |
| |
| ShowNotification(CreateNotificationWithMediumSignalStrengthIcon( |
| kSetupRequiredNotificationId, |
| l10n_util::GetStringFUTF16(IDS_TETHER_NOTIFICATION_SETUP_REQUIRED_TITLE, |
| base::ASCIIToUTF16(device_name)), |
| l10n_util::GetStringFUTF16(IDS_TETHER_NOTIFICATION_SETUP_REQUIRED_MESSAGE, |
| base::ASCIIToUTF16(device_name)))); |
| } |
| |
| void TetherNotificationPresenter::RemoveSetupRequiredNotification() { |
| RemoveNotificationIfVisible(kSetupRequiredNotificationId); |
| } |
| |
| void TetherNotificationPresenter::NotifyConnectionToHostFailed() { |
| PA_LOG(INFO) << "Displaying \"connection attempt failed\" notification. " |
| << "Notification ID = " << kActiveHostNotificationId; |
| |
| ShowNotification(CreateNotificationWithMediumSignalStrengthIcon( |
| kActiveHostNotificationId, |
| l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_CONNECTION_FAILED_TITLE), |
| l10n_util::GetStringUTF16( |
| IDS_TETHER_NOTIFICATION_CONNECTION_FAILED_MESSAGE))); |
| } |
| |
| void TetherNotificationPresenter::RemoveConnectionToHostFailedNotification() { |
| RemoveNotificationIfVisible(kActiveHostNotificationId); |
| } |
| |
| void TetherNotificationPresenter::NotifyEnableBluetooth() { |
| PA_LOG(INFO) << "Displaying \"enable Bluetooth\" notification. " |
| << "Notification ID = " << kEnableBluetoothNotificationId; |
| |
| ShowNotification(CreateNotificationWithMediumSignalStrengthIcon( |
| kEnableBluetoothNotificationId, |
| l10n_util::GetStringUTF16(IDS_TETHER_NOTIFICATION_ENABLE_BLUETOOTH_TITLE), |
| base::string16())); |
| } |
| |
| void TetherNotificationPresenter::RemoveEnableBluetoothNotification() { |
| RemoveNotificationIfVisible(kEnableBluetoothNotificationId); |
| } |
| |
| void TetherNotificationPresenter::OnNotificationClicked( |
| const std::string& notification_id) { |
| if (notification_id == kEnableBluetoothNotificationId) { |
| OpenSettingsAndRemoveNotification(chrome::kBluetoothSubPage, |
| notification_id); |
| return; |
| } |
| |
| // Iterate through all IDs corresponding to notifications which should open |
| // the Tether settings page when clicked. If the notification ID provided |
| // exists in |kIdsWhichOpenTetherSettingsOnClick|, open settings. |
| for (size_t i = 0; i < arraysize(kIdsWhichOpenTetherSettingsOnClick); ++i) { |
| const char* const curr_clickable_id = kIdsWhichOpenTetherSettingsOnClick[i]; |
| if (notification_id == curr_clickable_id) { |
| OpenSettingsAndRemoveNotification(kTetherSettingsSubpage, |
| notification_id); |
| return; |
| } |
| } |
| |
| // Otherwise, ignore this click since it is not in the list of clickable IDs |
| // (e.g., it could have been created by another feature/application). |
| } |
| |
| void TetherNotificationPresenter::OnNotificationButtonClicked( |
| const std::string& notification_id, |
| int button_index) { |
| PA_LOG(INFO) << "Button at index " << button_index |
| << " of notification with ID " << notification_id |
| << " was clicked."; |
| |
| if (notification_id == kPotentialHotspotNotificationId && button_index == 0) { |
| network_connect_->ConnectToNetworkId(hotspot_nearby_device_.GetDeviceId()); |
| } |
| message_center_->RemoveNotification(notification_id, true /* by_user */); |
| } |
| |
| void TetherNotificationPresenter::SetSettingsUiDelegateForTesting( |
| std::unique_ptr<SettingsUiDelegate> settings_ui_delegate) { |
| settings_ui_delegate_ = std::move(settings_ui_delegate); |
| } |
| |
| void TetherNotificationPresenter::ShowNotification( |
| std::unique_ptr<message_center::Notification> notification) { |
| std::string notification_id = notification->id(); |
| if (message_center_->FindVisibleNotificationById(notification_id)) { |
| message_center_->UpdateNotification(notification_id, |
| std::move(notification)); |
| } else { |
| message_center_->AddNotification(std::move(notification)); |
| } |
| } |
| |
| void TetherNotificationPresenter::OpenSettingsAndRemoveNotification( |
| const std::string& settings_subpage, |
| const std::string& notification_id) { |
| PA_LOG(INFO) << "Notification with ID " << notification_id << " was clicked. " |
| << "Opening settings subpage: " << settings_subpage; |
| |
| settings_ui_delegate_->ShowSettingsSubPageForProfile(profile_, |
| settings_subpage); |
| message_center_->RemoveNotification(notification_id, true /* by_user */); |
| } |
| |
| void TetherNotificationPresenter::RemoveNotificationIfVisible( |
| const std::string& notification_id) { |
| if (!message_center_->FindVisibleNotificationById(notification_id)) |
| return; |
| |
| PA_LOG(INFO) << "Removing notification with ID \"" << notification_id |
| << "\"."; |
| message_center_->RemoveNotification(notification_id, false /* by_user */); |
| } |
| |
| } // namespace tether |
| |
| } // namespace chromeos |