blob: c1ff14e7b42964619d6cdf6e240927b62f77a569 [file] [log] [blame]
// Copyright 2013 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/desktop_capture/desktop_media_picker_views.h"
#include <algorithm>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/metrics/histogram_functions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/media/webrtc/desktop_media_list.h"
#include "chrome/browser/media/webrtc/desktop_media_picker_manager.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/strings/grit/components_strings.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/media_stream_request.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
#if defined(USE_AURA)
#include "ui/aura/window_tree_host.h"
#endif
using content::DesktopMediaID;
enum class DesktopMediaPickerDialogView::DialogSource : int {
kGetCurrentBrowsingContextMedia = 0,
kGetDisplayMedia = 1
};
namespace {
using DialogSource = DesktopMediaPickerDialogView::DialogSource;
#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
DesktopMediaID::Id AcceleratedWidgetToDesktopMediaId(
gfx::AcceleratedWidget accelerated_widget) {
#if defined(OS_WIN)
return reinterpret_cast<DesktopMediaID::Id>(accelerated_widget);
#else
return static_cast<DesktopMediaID::Id>(accelerated_widget);
#endif
}
#endif
enum class GCBCMResult {
kDialogDismissed = 0, // Tab/window closed, navigation, etc.
kUserCancelled = 1, // User explicitly cancelled.
kUserSelectedScreen = 2, // Screen selected.
kUserSelectedWindow = 3, // Window selected.
kUserSelectedOtherTab = 4, // Other tab selected from tab-list.
kUserSelectedThisTabAsGenericTab = 5, // Current tab selected from tab-list.
kUserSelectedThisTab = 6, // Current tab selected from current-tab menu.
kMaxValue = kUserSelectedThisTab
};
enum class GDMResult {
kDialogDismissed = 0, // Tab/window closed, navigation, etc.
kUserCancelled = 1, // User explicitly cancelled.
kUserSelectedScreen = 2, // Screen selected.
kUserSelectedWindow = 3, // Window selected.
kUserSelectedOtherTab = 4, // Other tab selected from tab-list.
kUserSelectedThisTab = 5, // Current tab selected from tab-list.
kMaxValue = kUserSelectedThisTab
};
void RecordUma(GCBCMResult result) {
base::UmaHistogramEnumeration(
"Media.Ui.GetCurrentBrowsingContextMedia.ExplicitSelection."
"UserInteraction",
result);
}
void RecordUma(GDMResult result) {
base::UmaHistogramEnumeration("Media.Ui.GetDisplayMedia.UserInteraction",
result);
}
void RecordUmaDismissal(DialogSource dialog_source) {
if (dialog_source == DialogSource::kGetCurrentBrowsingContextMedia) {
RecordUma(GCBCMResult::kDialogDismissed);
} else {
RecordUma(GDMResult::kDialogDismissed);
}
}
void RecordUmaCancellation(DialogSource dialog_source) {
if (dialog_source == DialogSource::kGetCurrentBrowsingContextMedia) {
RecordUma(GCBCMResult::kUserCancelled);
} else {
RecordUma(GDMResult::kUserCancelled);
}
}
// Convenience function for recording UMA.
// |source_type| is there to help us distinguish the current tab being
// selected explicitly, from it being selected from the list of all tabs.
void RecordUmaSelection(DialogSource dialog_source,
content::WebContents* web_contents,
const DesktopMediaID& selected_media,
DesktopMediaList::Type source_type) {
switch (source_type) {
case DesktopMediaList::Type::kNone: {
NOTREACHED();
break;
}
case DesktopMediaList::Type::kScreen: {
if (dialog_source == DialogSource::kGetCurrentBrowsingContextMedia) {
RecordUma(GCBCMResult::kUserSelectedScreen);
} else {
RecordUma(GDMResult::kUserSelectedScreen);
}
break;
}
case DesktopMediaList::Type::kWindow: {
if (dialog_source == DialogSource::kGetCurrentBrowsingContextMedia) {
RecordUma(GCBCMResult::kUserSelectedWindow);
} else {
RecordUma(GDMResult::kUserSelectedWindow);
}
break;
}
case DesktopMediaList::Type::kWebContents: {
// Whether the current tab was selected. Note that this can happen
// through a non-explicit selection of the current tab through the
// list of all available tabs.
const bool current_tab_selected =
web_contents &&
web_contents->GetMainFrame()->GetProcess()->GetID() ==
selected_media.web_contents_id.render_process_id &&
web_contents->GetMainFrame()->GetRoutingID() ==
selected_media.web_contents_id.main_render_frame_id;
if (dialog_source == DialogSource::kGetCurrentBrowsingContextMedia) {
RecordUma(current_tab_selected
? GCBCMResult::kUserSelectedThisTabAsGenericTab
: GCBCMResult::kUserSelectedOtherTab);
} else {
RecordUma(current_tab_selected ? GDMResult::kUserSelectedThisTab
: GDMResult::kUserSelectedOtherTab);
}
break;
}
case DesktopMediaList::Type::kCurrentTab: {
RecordUma(GCBCMResult::kUserSelectedThisTab);
break;
}
}
}
} // namespace
DesktopMediaPickerDialogView::DisplaySurfaceCategory::DisplaySurfaceCategory(
DesktopMediaList::Type type,
std::unique_ptr<DesktopMediaListController> controller)
: type(type), controller(std::move(controller)) {}
DesktopMediaPickerDialogView::DisplaySurfaceCategory::DisplaySurfaceCategory(
DesktopMediaPickerDialogView::DisplaySurfaceCategory&& other)
: type(other.type), controller(std::move(other.controller)) {}
DesktopMediaPickerDialogView::DisplaySurfaceCategory::
~DisplaySurfaceCategory() = default;
DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
const DesktopMediaPicker::Params& params,
DesktopMediaPickerViews* parent,
std::vector<std::unique_ptr<DesktopMediaList>> source_lists)
: web_contents_(params.web_contents), parent_(parent) {
SetModalType(params.modality);
SetButtonLabel(ui::DIALOG_BUTTON_OK,
l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_SHARE));
RegisterDeleteDelegateCallback(base::BindOnce(
[](DesktopMediaPickerDialogView* dialog) {
// If the dialog is being closed then notify the parent about it.
if (dialog->parent_)
dialog->parent_->NotifyDialogResult(DesktopMediaID());
},
this));
if (params.request_audio) {
std::unique_ptr<views::Checkbox> audio_share_checkbox =
std::make_unique<views::Checkbox>(
l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE));
audio_share_checkbox->SetChecked(params.approve_audio_by_default);
audio_share_checkbox_ = SetExtraView(std::move(audio_share_checkbox));
}
const ChromeLayoutProvider* const provider = ChromeLayoutProvider::Get();
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical,
provider->GetDialogInsetsForContentType(
views::DialogContentType::kText, views::DialogContentType::kControl),
provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)));
auto description_label = std::make_unique<views::Label>();
description_label->SetMultiLine(true);
description_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
description_label_ = AddChildView(std::move(description_label));
std::vector<std::pair<std::u16string, std::unique_ptr<View>>> panes;
const bool current_tab_among_sources = std::any_of(
source_lists.begin(), source_lists.end(),
[](const std::unique_ptr<DesktopMediaList>& list) {
return list->GetMediaListType() == DesktopMediaList::Type::kCurrentTab;
});
dialog_source_ = current_tab_among_sources
? DialogSource::kGetCurrentBrowsingContextMedia
: DialogSource::kGetDisplayMedia;
for (auto& source_list : source_lists) {
switch (source_list->GetMediaListType()) {
case DesktopMediaList::Type::kNone: {
NOTREACHED();
break;
}
case DesktopMediaList::Type::kScreen: {
const DesktopMediaSourceViewStyle kSingleScreenStyle(
1, // columns
gfx::Size(360, 280), // item_size
gfx::Rect(), // icon_rect
gfx::Rect(), // label_rect
gfx::HorizontalAlignment::ALIGN_CENTER, // text_alignment
gfx::Rect(20, 20, 320, 240), // image_rect
5); // focus_rectangle_inset
const DesktopMediaSourceViewStyle kGenericScreenStyle(
2, // columns
gfx::Size(270, 220), // item_size
gfx::Rect(), // icon_rect
gfx::Rect(15, 165, 240, 40), // label_rect
gfx::HorizontalAlignment::ALIGN_CENTER, // text_alignment
gfx::Rect(15, 15, 240, 150), // image_rect
5); // focus_rectangle_inset
std::unique_ptr<views::ScrollView> screen_scroll_view =
views::ScrollView::CreateScrollViewWithBorder();
std::u16string screen_title_text = l10n_util::GetStringUTF16(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN);
auto list_controller = std::make_unique<DesktopMediaListController>(
this, std::move(source_list));
screen_scroll_view->SetContents(list_controller->CreateView(
kGenericScreenStyle, kSingleScreenStyle, screen_title_text));
categories_.emplace_back(DesktopMediaList::Type::kScreen,
std::move(list_controller));
screen_scroll_view->ClipHeightTo(
kGenericScreenStyle.item_size.height(),
kGenericScreenStyle.item_size.height() * 2);
screen_scroll_view->SetHorizontalScrollBarMode(
views::ScrollView::ScrollBarMode::kDisabled);
panes.push_back(
std::make_pair(screen_title_text, std::move(screen_scroll_view)));
break;
}
case DesktopMediaList::Type::kWindow: {
const DesktopMediaSourceViewStyle kWindowStyle(
3, // columns
gfx::Size(180, 160), // item_size
gfx::Rect(10, 120, 20, 20), // icon_rect
gfx::Rect(32, 110, 138, 40), // label_rect
gfx::HorizontalAlignment::ALIGN_LEFT, // text_alignment
gfx::Rect(8, 8, 164, 104), // image_rect
5); // focus_rectangle_inset
std::unique_ptr<views::ScrollView> window_scroll_view =
views::ScrollView::CreateScrollViewWithBorder();
std::u16string window_title_text = l10n_util::GetStringUTF16(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_WINDOW);
auto list_controller = std::make_unique<DesktopMediaListController>(
this, std::move(source_list));
window_scroll_view->SetContents(list_controller->CreateView(
kWindowStyle, kWindowStyle, window_title_text));
categories_.emplace_back(DesktopMediaList::Type::kWindow,
std::move(list_controller));
window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(),
kWindowStyle.item_size.height() * 2);
window_scroll_view->SetHorizontalScrollBarMode(
views::ScrollView::ScrollBarMode::kDisabled);
panes.push_back(
std::make_pair(window_title_text, std::move(window_scroll_view)));
break;
}
case DesktopMediaList::Type::kWebContents: {
// Note that "other tab" is inaccurate - we actually allow any tab
// to be selected in either case.
const std::u16string title = l10n_util::GetStringUTF16(
current_tab_among_sources
? IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_OTHER_TAB
: IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_TAB);
auto list_controller = std::make_unique<DesktopMediaListController>(
this, std::move(source_list));
panes.push_back(
std::make_pair(title, list_controller->CreateTabListView(title)));
categories_.emplace_back(DesktopMediaList::Type::kWebContents,
std::move(list_controller));
break;
}
case DesktopMediaList::Type::kCurrentTab: {
const DesktopMediaSourceViewStyle kCurrentTabStyle(
1, // columns
gfx::Size(360, 280), // item_size
gfx::Rect(), // icon_rect
gfx::Rect(), // label_rect
gfx::HorizontalAlignment::ALIGN_CENTER, // text_alignment
gfx::Rect(20, 20, 320, 240), // image_rect
5); // focus_rectangle_inset
std::unique_ptr<views::ScrollView> window_scroll_view =
views::ScrollView::CreateScrollViewWithBorder();
const std::u16string title = l10n_util::GetStringUTF16(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_THIS_TAB);
auto list_controller = std::make_unique<DesktopMediaListController>(
this, std::move(source_list));
window_scroll_view->SetContents(list_controller->CreateView(
kCurrentTabStyle, kCurrentTabStyle, title));
categories_.emplace_back(DesktopMediaList::Type::kCurrentTab,
std::move(list_controller));
window_scroll_view->ClipHeightTo(
kCurrentTabStyle.item_size.height(),
kCurrentTabStyle.item_size.height() * 2);
window_scroll_view->SetHorizontalScrollBarMode(
views::ScrollView::ScrollBarMode::kDisabled);
panes.emplace_back(title, std::move(window_scroll_view));
break;
}
}
}
if (panes.size() > 1) {
auto tabbed_pane = std::make_unique<views::TabbedPane>();
for (auto& pane : panes)
tabbed_pane->AddTab(pane.first, std::move(pane.second));
tabbed_pane->set_listener(this);
tabbed_pane->SetFocusBehavior(views::View::FocusBehavior::NEVER);
tabbed_pane_ = AddChildView(std::move(tabbed_pane));
} else {
AddChildView(std::move(panes.front().second));
}
if (params.app_name == params.target_name) {
description_label_->SetText(l10n_util::GetStringFUTF16(
IDS_DESKTOP_MEDIA_PICKER_TEXT, params.app_name));
} else {
description_label_->SetText(
l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED,
params.app_name, params.target_name));
}
DCHECK(!categories_.empty());
OnSourceTypeSwitched(0);
// If |params.web_contents| is set and it's not a background page then the
// picker will be shown modal to the web contents. Otherwise the picker is
// shown in a separate window.
views::Widget* widget = nullptr;
bool modal_dialog = params.web_contents &&
!params.web_contents->GetDelegate()->IsNeverComposited(
params.web_contents);
if (modal_dialog) {
widget =
constrained_window::ShowWebModalDialogViews(this, params.web_contents);
} else {
#if defined(OS_MAC)
// On Mac, MODAL_TYPE_CHILD with a null parent isn't allowed - fall back to
// MODAL_TYPE_WINDOW.
SetModalType(ui::MODAL_TYPE_WINDOW);
#endif
widget = CreateDialogWidget(this, params.context, nullptr);
widget->Show();
}
chrome::RecordDialogCreation(chrome::DialogIdentifier::DESKTOP_MEDIA_PICKER);
#if defined(OS_MAC)
// On Mac, even modals are shown using separate native windows.
bool is_separate_native_window = true;
#else
bool is_separate_native_window = !modal_dialog;
#endif
// If the picker is a separate native window, it should not be shown in the
// source list, so its id is passed into NativeDesktopMediaList to be ignored.
DesktopMediaID dialog_window_id;
if (is_separate_native_window) {
dialog_window_id = DesktopMediaID::RegisterNativeWindow(
DesktopMediaID::TYPE_WINDOW, widget->GetNativeWindow());
#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
// Set native window ID if the windows is outside Ash.
dialog_window_id.id = AcceleratedWidgetToDesktopMediaId(
widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
#elif defined(OS_MAC)
// On Mac, the window_id in DesktopMediaID is the same as the actual native
// window ID. Note that assuming this is a bit of a layering violation; the
// fact that this code makes that assumption is documented at the code that
// causes it to hold, so hopefully nobody changes that :)
dialog_window_id.id = dialog_window_id.window_id;
#endif
}
for (const auto& category : categories_)
category.controller->StartUpdating(dialog_window_id);
}
DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {}
DialogSource DesktopMediaPickerDialogView::GetDialogSource() const {
return dialog_source_;
}
void DesktopMediaPickerDialogView::TabSelectedAt(int index) {
OnSourceTypeSwitched(index);
categories_[index].controller->FocusView();
DialogModelChanged();
}
void DesktopMediaPickerDialogView::OnSourceTypeSwitched(int index) {
// Set whether the checkbox is visible based on the source type.
if (audio_share_checkbox_) {
switch (categories_[index].type) {
case DesktopMediaList::Type::kScreen:
audio_share_checkbox_->SetVisible(
DesktopMediaPickerViews::kScreenAudioShareSupportedOnPlatform);
break;
case DesktopMediaList::Type::kWindow:
audio_share_checkbox_->SetVisible(false);
break;
case DesktopMediaList::Type::kWebContents:
case DesktopMediaList::Type::kCurrentTab:
audio_share_checkbox_->SetVisible(true);
break;
case DesktopMediaList::Type::kNone:
NOTREACHED();
break;
}
}
}
int DesktopMediaPickerDialogView::GetSelectedTabIndex() const {
return tabbed_pane_ ? tabbed_pane_->GetSelectedTabIndex() : 0;
}
const DesktopMediaListController*
DesktopMediaPickerDialogView::GetSelectedController() const {
return categories_[GetSelectedTabIndex()].controller.get();
}
DesktopMediaListController*
DesktopMediaPickerDialogView::GetSelectedController() {
return categories_[GetSelectedTabIndex()].controller.get();
}
DesktopMediaList::Type DesktopMediaPickerDialogView::GetSelectedSourceListType()
const {
const int index = GetSelectedTabIndex();
DCHECK_GE(index, 0);
DCHECK_LT(static_cast<size_t>(index), categories_.size());
return categories_[index].type;
}
void DesktopMediaPickerDialogView::DetachParent() {
parent_ = nullptr;
}
gfx::Size DesktopMediaPickerDialogView::CalculatePreferredSize() const {
static const size_t kDialogViewWidth = 600;
return gfx::Size(kDialogViewWidth, GetHeightForWidth(kDialogViewWidth));
}
std::u16string DesktopMediaPickerDialogView::GetWindowTitle() const {
int title_id = IDS_DESKTOP_MEDIA_PICKER_TITLE;
if (!tabbed_pane_) {
switch (categories_.front().type) {
case DesktopMediaList::Type::kScreen:
title_id = IDS_DESKTOP_MEDIA_PICKER_TITLE_SCREEN_ONLY;
break;
case DesktopMediaList::Type::kWindow:
title_id = IDS_DESKTOP_MEDIA_PICKER_TITLE_WINDOW_ONLY;
break;
case DesktopMediaList::Type::kWebContents:
title_id = IDS_DESKTOP_MEDIA_PICKER_TITLE_WEB_CONTENTS_ONLY;
break;
default:
break;
}
}
return l10n_util::GetStringUTF16(title_id);
}
bool DesktopMediaPickerDialogView::IsDialogButtonEnabled(
ui::DialogButton button) const {
return button != ui::DIALOG_BUTTON_OK ||
GetSelectedController()->GetSelection().has_value() ||
accepted_source_.has_value();
}
views::View* DesktopMediaPickerDialogView::GetInitiallyFocusedView() {
return GetCancelButton();
}
bool DesktopMediaPickerDialogView::Accept() {
DCHECK(IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Ok button should only be enabled when a source is selected.
absl::optional<DesktopMediaID> source_optional =
accepted_source_.has_value() ? accepted_source_
: GetSelectedController()->GetSelection();
DesktopMediaID source = source_optional.value();
source.audio_share = audio_share_checkbox_ &&
audio_share_checkbox_->GetVisible() &&
audio_share_checkbox_->GetChecked();
if (source.audio_share &&
dialog_source_ == DialogSource::kGetCurrentBrowsingContextMedia) {
source.web_contents_id.disable_local_echo = true;
}
if (source.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
// Activate the selected tab and bring the browser window for the selected
// tab to the front.
content::WebContents* tab = content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(
source.web_contents_id.render_process_id,
source.web_contents_id.main_render_frame_id));
if (tab) {
tab->GetDelegate()->ActivateContents(tab);
Browser* browser = chrome::FindBrowserWithWebContents(tab);
if (browser && browser->window())
browser->window()->Activate();
}
} else if (source.type == DesktopMediaID::TYPE_WINDOW) {
#if defined(USE_AURA)
aura::Window* window = DesktopMediaID::GetNativeWindowById(source);
Browser* browser = chrome::FindBrowserWithWindow(window);
if (browser && browser->window())
browser->window()->Activate();
#endif
}
RecordUmaSelection(dialog_source_, web_contents_, source,
GetSelectedSourceListType());
if (parent_)
parent_->NotifyDialogResult(source);
// Return true to close the window.
return true;
}
bool DesktopMediaPickerDialogView::Cancel() {
RecordUmaCancellation(dialog_source_);
return views::DialogDelegateView::Cancel();
}
bool DesktopMediaPickerDialogView::ShouldShowCloseButton() const {
return false;
}
void DesktopMediaPickerDialogView::OnSelectionChanged() {
DialogModelChanged();
}
void DesktopMediaPickerDialogView::AcceptSource() {
// This will call Accept() and close the dialog.
AcceptDialog();
}
void DesktopMediaPickerDialogView::AcceptSpecificSource(DesktopMediaID source) {
accepted_source_ = absl::optional<DesktopMediaID>(source);
AcceptSource();
}
void DesktopMediaPickerDialogView::Reject() {
CancelDialog();
}
void DesktopMediaPickerDialogView::OnSourceListLayoutChanged() {
PreferredSizeChanged();
// TODO(pbos): Ideally this would use shared logic similar to
// BubbleDialogDelegateView::SizeToContents() instead of implementing sizing
// logic in-place.
const gfx::Size new_size = GetWidget()->GetRootView()->GetPreferredSize();
if (GetModalType() == ui::ModalType::MODAL_TYPE_CHILD) {
// For the web-modal dialog resize the dialog in place.
// TODO(pbos): This should ideally use UpdateWebContentsModalDialogPosition
// to keep the widget centered horizontally. As this dialog is fixed-width
// we're effectively only changing the height, so reusing the current
// widget origin should be equivalent.
GetWidget()->SetSize(new_size);
return;
}
// When not using the web-modal dialog, center the dialog with its new size.
GetWidget()->CenterWindow(new_size);
}
BEGIN_METADATA(DesktopMediaPickerDialogView, views::DialogDelegateView)
END_METADATA
constexpr bool DesktopMediaPickerViews::kScreenAudioShareSupportedOnPlatform;
DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(nullptr) {}
DesktopMediaPickerViews::~DesktopMediaPickerViews() {
if (dialog_) {
RecordUmaDismissal(dialog_->GetDialogSource());
dialog_->DetachParent();
dialog_->GetWidget()->Close();
}
}
void DesktopMediaPickerViews::Show(
const DesktopMediaPicker::Params& params,
std::vector<std::unique_ptr<DesktopMediaList>> source_lists,
DoneCallback done_callback) {
DesktopMediaPickerManager::Get()->OnShowDialog();
callback_ = std::move(done_callback);
dialog_ =
new DesktopMediaPickerDialogView(params, this, std::move(source_lists));
}
void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) {
// Once this method is called the |dialog_| will close and destroy itself.
dialog_->DetachParent();
dialog_ = nullptr;
DesktopMediaPickerManager::Get()->OnHideDialog();
if (callback_.is_null())
return;
// Notify the |callback_| asynchronously because it may need to destroy
// DesktopMediaPicker.
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(std::move(callback_), source));
}
// static
std::unique_ptr<DesktopMediaPicker> DesktopMediaPicker::Create(
const content::MediaStreamRequest* request) {
return std::make_unique<DesktopMediaPickerViews>();
}