blob: 4a4bbfb02757f79c5a9f23dc4fb51723935d0734 [file] [log] [blame]
// Copyright 2019 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/ui/views/global_media_controls/media_dialog_view.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/global_media_controls/media_dialog_view_observer.h"
#include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.h"
#include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "ui/views/background.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
using media_session::mojom::MediaSessionAction;
// static
MediaDialogView* MediaDialogView::instance_ = nullptr;
// static
bool MediaDialogView::has_been_opened_ = false;
// static
void MediaDialogView::ShowDialog(views::View* anchor_view,
MediaToolbarButtonController* controller,
service_manager::Connector* connector) {
DCHECK(!instance_);
DCHECK(controller);
instance_ = new MediaDialogView(anchor_view, controller, connector);
views::Widget* widget =
views::BubbleDialogDelegateView::CreateBubble(instance_);
widget->Show();
base::UmaHistogramBoolean("Media.GlobalMediaControls.RepeatUsage",
has_been_opened_);
has_been_opened_ = true;
}
// static
void MediaDialogView::HideDialog() {
if (IsShowing()) {
instance_->controller_->SetDialogDelegate(nullptr);
instance_->GetWidget()->Close();
}
// Set |instance_| to nullptr so that |IsShowing()| returns false immediately.
// We also set to nullptr in |WindowClosing()| (which happens asynchronously),
// since |HideDialog()| is not always called.
instance_ = nullptr;
}
// static
bool MediaDialogView::IsShowing() {
return instance_ != nullptr;
}
MediaNotificationContainerImpl* MediaDialogView::ShowMediaSession(
const std::string& id,
base::WeakPtr<media_message_center::MediaNotificationItem> item) {
auto container =
std::make_unique<MediaNotificationContainerImplView>(id, item);
MediaNotificationContainerImplView* container_ptr = container.get();
container_ptr->AddObserver(this);
observed_containers_[id] = container_ptr;
active_sessions_view_->ShowNotification(id, std::move(container));
OnAnchorBoundsChanged();
for (auto& observer : observers_)
observer.OnMediaSessionShown();
return container_ptr;
}
void MediaDialogView::HideMediaSession(const std::string& id) {
active_sessions_view_->HideNotification(id);
if (active_sessions_view_->empty())
HideDialog();
else
OnAnchorBoundsChanged();
for (auto& observer : observers_)
observer.OnMediaSessionHidden();
}
int MediaDialogView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
bool MediaDialogView::Close() {
return Cancel();
}
void MediaDialogView::AddedToWidget() {
int corner_radius =
views::LayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH);
views::BubbleFrameView* frame = GetBubbleFrameView();
if (frame) {
frame->SetCornerRadius(corner_radius);
}
SetPaintToLayer();
layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(corner_radius));
controller_->SetDialogDelegate(this);
}
gfx::Size MediaDialogView::CalculatePreferredSize() const {
// If we have active sessions, then fit to them.
if (!active_sessions_view_->empty())
return views::BubbleDialogDelegateView::CalculatePreferredSize();
// Otherwise, use a standard size for bubble dialogs.
const int width = ChromeLayoutProvider::Get()->GetDistanceMetric(
DISTANCE_BUBBLE_PREFERRED_WIDTH);
return gfx::Size(width, 1);
}
void MediaDialogView::OnContainerExpanded(bool expanded) {
OnAnchorBoundsChanged();
}
void MediaDialogView::OnContainerMetadataChanged() {
for (auto& observer : observers_)
observer.OnMediaSessionMetadataUpdated();
}
void MediaDialogView::OnContainerDestroyed(const std::string& id) {
auto iter = observed_containers_.find(id);
DCHECK(iter != observed_containers_.end());
iter->second->RemoveObserver(this);
observed_containers_.erase(iter);
}
void MediaDialogView::AddObserver(MediaDialogViewObserver* observer) {
observers_.AddObserver(observer);
}
void MediaDialogView::RemoveObserver(MediaDialogViewObserver* observer) {
observers_.RemoveObserver(observer);
}
const std::map<const std::string, MediaNotificationContainerImplView*>&
MediaDialogView::GetNotificationsForTesting() const {
return active_sessions_view_->notifications_for_testing();
}
MediaDialogView::MediaDialogView(views::View* anchor_view,
MediaToolbarButtonController* controller,
service_manager::Connector* connector)
: BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
controller_(controller),
active_sessions_view_(
AddChildView(std::make_unique<MediaNotificationListView>())) {
DCHECK(controller_);
}
MediaDialogView::~MediaDialogView() {
for (auto container_pair : observed_containers_)
container_pair.second->RemoveObserver(this);
}
void MediaDialogView::Init() {
// Remove margins.
set_margins(gfx::Insets());
SetLayoutManager(std::make_unique<views::FillLayout>());
}
void MediaDialogView::WindowClosing() {
if (instance_ == this) {
instance_ = nullptr;
controller_->SetDialogDelegate(nullptr);
}
}