| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/media_router/cast_notification_controller_lacros.h" |
| |
| #include <algorithm> |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/media/router/discovery/access_code/access_code_cast_feature.h" |
| #include "chrome/browser/notifications/notification_display_service.h" |
| #include "chrome/browser/notifications/notification_handler.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/media_router/browser/media_router.h" |
| #include "components/media_router/browser/media_router_factory.h" |
| #include "components/media_router/browser/mirroring_media_controller_host.h" |
| #include "components/vector_icons/vector_icons.h" |
| #include "content/public/browser/browser_context.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/models/image_model.h" |
| #include "ui/message_center/public/cpp/message_center_constants.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| #include "ui/message_center/public/cpp/notification_types.h" |
| |
| namespace media_router { |
| |
| namespace { |
| |
| constexpr char kNotificationId[] = "browser.cast.session"; |
| constexpr char kNotifierId[] = "browser.cast"; |
| |
| std::u16string GetNotificationTitle(const std::string& sink_name) { |
| if (sink_name.empty()) { |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_TITLE_UNKNOWN); |
| } |
| return l10n_util::GetStringFUTF16(IDS_MEDIA_ROUTER_NOTIFICATION_TITLE, |
| base::UTF8ToUTF16(sink_name)); |
| } |
| |
| std::u16string GetNotificationMessage(const MediaRoute& route, |
| MirroringMediaControllerHost* freeze_host, |
| bool freeze_enabled) { |
| if (!freeze_enabled || !freeze_host || !freeze_host->CanFreeze()) { |
| if (route.media_source().IsDesktopMirroringSource()) { |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_MESSAGE_CAST_SCREEN); |
| } |
| return base::UTF8ToUTF16(route.description()); |
| } |
| if (freeze_host->IsFrozen()) { |
| if (route.media_source().IsDesktopMirroringSource()) { |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_MESSAGE_SCREEN_PAUSED); |
| } |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_MESSAGE_PAUSED); |
| } |
| if (route.media_source().IsDesktopMirroringSource()) { |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_MESSAGE_SCREEN_CAN_PAUSE); |
| } |
| if (route.media_source().IsTabMirroringSource()) { |
| return l10n_util::GetStringUTF16( |
| IDS_MEDIA_ROUTER_NOTIFICATION_MESSAGE_TAB_CAN_PAUSE); |
| } |
| return base::UTF8ToUTF16(route.description()); |
| } |
| |
| } // namespace |
| |
| CastNotificationControllerLacros::CastNotificationControllerLacros( |
| Profile* profile) |
| : CastNotificationControllerLacros( |
| profile, |
| NotificationDisplayService::GetForProfile(profile), |
| MediaRouterFactory::GetApiForBrowserContext(profile)) {} |
| |
| CastNotificationControllerLacros::CastNotificationControllerLacros( |
| Profile* profile, |
| NotificationDisplayService* notification_service, |
| MediaRouter* router) |
| : MediaRoutesObserver(router), |
| profile_(profile), |
| notification_service_(notification_service), |
| media_router_(router) {} |
| |
| CastNotificationControllerLacros::~CastNotificationControllerLacros() = default; |
| |
| void CastNotificationControllerLacros::OnRoutesUpdated( |
| const std::vector<MediaRoute>& routes) { |
| freeze_button_index_.reset(); |
| stop_button_index_.reset(); |
| displayed_route_is_frozen_ = false; |
| |
| auto route_it = |
| std::find_if(routes.begin(), routes.end(), |
| [](const MediaRoute& route) { return route.is_local(); }); |
| if (route_it == routes.end()) { |
| // There was no active local route, so we hide the current outstanding |
| // notification, if it exists. |
| HideNotification(); |
| return; |
| } |
| // This will overwrite the existing notification if there is one. |
| ShowNotification(*route_it); |
| } |
| |
| void CastNotificationControllerLacros::ShowNotification( |
| const MediaRoute& route) { |
| displayed_route_id_ = route.media_route_id(); |
| notification_service_->Display(NotificationHandler::Type::TRANSIENT, |
| CreateNotification(route), nullptr); |
| } |
| |
| void CastNotificationControllerLacros::HideNotification() { |
| displayed_route_id_ = ""; |
| notification_service_->Close(NotificationHandler::Type::TRANSIENT, |
| kNotificationId); |
| } |
| |
| message_center::Notification |
| CastNotificationControllerLacros::CreateNotification(const MediaRoute& route) { |
| MirroringMediaControllerHost* freeze_host = |
| media_router_->GetMirroringMediaControllerHost(route.media_route_id()); |
| message_center::RichNotificationData data; |
| data.buttons = GetButtons(route, freeze_host); |
| |
| return message_center::Notification{ |
| message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, |
| kNotificationId, |
| GetNotificationTitle(route.media_sink_name()), |
| GetNotificationMessage(route, freeze_host, |
| IsAccessCodeCastFreezeUiEnabled(profile_)), |
| /*icon=*/ui::ImageModel{}, |
| /*display_source=*/u"", |
| /*origin_url=*/GURL{}, |
| message_center::NotifierId{message_center::NotifierType::SYSTEM_COMPONENT, |
| kNotifierId}, |
| std::move(data), |
| base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( |
| base::BindRepeating( |
| &CastNotificationControllerLacros::OnNotificationClicked, |
| weak_ptr_factory_.GetWeakPtr())), |
| }; |
| } |
| |
| std::vector<message_center::ButtonInfo> |
| CastNotificationControllerLacros::GetButtons( |
| const MediaRoute& route, |
| MirroringMediaControllerHost* freeze_host) { |
| std::vector<message_center::ButtonInfo> buttons; |
| if (IsAccessCodeCastFreezeUiEnabled(profile_) && freeze_host && |
| freeze_host->CanFreeze()) { |
| displayed_route_is_frozen_ = freeze_host->IsFrozen(); |
| buttons.emplace_back( |
| displayed_route_is_frozen_ |
| ? l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_RESUME) |
| : l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_PAUSE)); |
| freeze_button_index_ = buttons.size() - 1; |
| } |
| buttons.emplace_back( |
| l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_SINK_VIEW_STOP)); |
| stop_button_index_ = buttons.size() - 1; |
| return buttons; |
| } |
| |
| void CastNotificationControllerLacros::OnNotificationClicked( |
| absl::optional<int> button_index) { |
| if (freeze_button_index_ && button_index == freeze_button_index_) { |
| FreezeOrUnfreezeCastStream(); |
| } else if (button_index == stop_button_index_) { |
| StopCasting(); |
| } |
| } |
| |
| void CastNotificationControllerLacros::StopCasting() { |
| media_router_->TerminateRoute(displayed_route_id_); |
| } |
| |
| void CastNotificationControllerLacros::FreezeOrUnfreezeCastStream() { |
| MirroringMediaControllerHost* freeze_host = |
| media_router_->GetMirroringMediaControllerHost(displayed_route_id_); |
| if (!freeze_host) { |
| return; |
| } |
| if (displayed_route_is_frozen_) { |
| freeze_host->Unfreeze(); |
| } else { |
| freeze_host->Freeze(); |
| } |
| } |
| |
| } // namespace media_router |