blob: d98b803d7cccf37c943c6936e3e8ef91913abece [file] [log] [blame]
// Copyright 2019 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/tab_sharing/tab_sharing_infobar_delegate.h"
#include <string>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/infobars/confirm_infobar_creator.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_sharing/tab_sharing_ui.h"
#include "chrome/grit/generated_resources.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "components/infobars/core/infobar.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/elide_url.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "net/base/url_util.h"
#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h"
#include "ui/base/l10n/l10n_util.h"
class TabSharingInfoBarDelegate::TabSharingInfoBarDelegateButton {
public:
TabSharingInfoBarDelegateButton() = default;
// Deleted copy and assignment operator.
TabSharingInfoBarDelegateButton(const TabSharingInfoBarDelegateButton&) =
delete;
TabSharingInfoBarDelegateButton& operator=(
const TabSharingInfoBarDelegateButton&) = delete;
virtual ~TabSharingInfoBarDelegateButton() = default;
virtual void Click(infobars::InfoBar* infobar) = 0;
virtual std::u16string GetLabel() const = 0;
virtual ui::ImageModel GetImage() const { return {}; }
virtual bool IsEnabled() const { return true; }
virtual std::u16string GetTooltip() const { return u""; }
};
namespace {
// Represents a button which, when clicked, changes the tab being shared/cast to
// be the current tab (the one associated with this infobar.)
class ShareTabInsteadButton
: public TabSharingInfoBarDelegate::TabSharingInfoBarDelegateButton {
public:
ShareTabInsteadButton(TabSharingUI* ui,
TabSharingInfoBarDelegate::ButtonState button_state,
TabSharingInfoBarDelegate::TabShareType capture_type)
: ui_(ui), button_state_(button_state), capture_type_(capture_type) {}
~ShareTabInsteadButton() override = default;
void Click(infobars::InfoBar* infobar) override {
DCHECK(ui_); // Not verified in ctor to keep tests simple.
ui_->StartSharing(infobar);
}
std::u16string GetLabel() const override {
switch (capture_type_) {
case TabSharingInfoBarDelegate::TabShareType::CAST:
return l10n_util::GetStringUTF16(IDS_TAB_CASTING_INFOBAR_CAST_BUTTON);
case TabSharingInfoBarDelegate::TabShareType::CAPTURE:
return l10n_util::GetStringUTF16(IDS_TAB_SHARING_INFOBAR_SHARE_BUTTON);
}
NOTREACHED();
return std::u16string();
}
bool IsEnabled() const override {
return button_state_ == TabSharingInfoBarDelegate::ButtonState::ENABLED;
}
std::u16string GetTooltip() const override {
return button_state_ == TabSharingInfoBarDelegate::ButtonState::DISABLED
? l10n_util::GetStringUTF16(
IDS_POLICY_DLP_SCREEN_SHARE_BLOCKED_TITLE)
: u"";
}
private:
const raw_ptr<TabSharingUI, DanglingUntriaged> ui_;
const TabSharingInfoBarDelegate::ButtonState button_state_;
const TabSharingInfoBarDelegate::TabShareType capture_type_;
};
// Represents a button which, when clicked, changes the activated tab to be
// the one which was hard-coded into this infobar. The intended use for this
// class is for the captured tab to activate the capturing tab, and vice versa.
class SwitchToTabButton
: public TabSharingInfoBarDelegate::TabSharingInfoBarDelegateButton {
public:
SwitchToTabButton(const TabSharingInfoBarDelegate::FocusTarget& focus_target,
bool focus_target_is_capturer)
: focus_target_(focus_target),
focus_target_is_capturer_(focus_target_is_capturer) {}
~SwitchToTabButton() override = default;
void Click(infobars::InfoBar* infobar) override {
content::RenderFrameHost* const rfh =
content::RenderFrameHost::FromID(focus_target_.id);
if (!rfh) {
return;
}
page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
rfh, focus_target_is_capturer_
? blink::mojom::WebFeature::kTabSharingBarSwitchToCapturer
: blink::mojom::WebFeature::kTabSharingBarSwitchToCapturee);
content::WebContents* const web_contents =
content::WebContents::FromRenderFrameHost(rfh);
DCHECK(web_contents);
web_contents->GetDelegate()->ActivateContents(web_contents);
Browser* const browser = chrome::FindBrowserWithWebContents(web_contents);
if (browser && browser->window()) {
browser->window()->Activate();
}
}
std::u16string GetLabel() const override {
// TODO(crbug.com/1224363): Hard-code this text into the button.
content::RenderFrameHost* const rfh =
content::RenderFrameHost::FromID(focus_target_.id);
if (!rfh) {
return GetDefaultLabel();
}
return l10n_util::GetStringFUTF16(
IDS_TAB_SHARING_INFOBAR_SWITCH_TO_BUTTON,
url_formatter::FormatOriginForSecurityDisplay(
rfh->GetLastCommittedOrigin(),
url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS));
}
ui::ImageModel GetImage() const override { return focus_target_.icon; }
private:
std::u16string GetDefaultLabel() const {
return l10n_util::GetStringUTF16(
focus_target_is_capturer_
? IDS_TAB_SHARING_INFOBAR_SWITCH_TO_CAPTURER_BUTTON
: IDS_TAB_SHARING_INFOBAR_SWITCH_TO_CAPTURED_BUTTON);
}
const TabSharingInfoBarDelegate::FocusTarget focus_target_;
const bool focus_target_is_capturer_;
};
std::u16string GetMessageTextCastingNoSinkName(
bool shared_tab,
const std::u16string& shared_tab_name) {
if (shared_tab) {
return l10n_util::GetStringUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_CURRENT_TAB_NO_DEVICE_NAME_LABEL);
}
return shared_tab_name.empty()
? l10n_util::GetStringUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_ANOTHER_UNTITLED_TAB_NO_DEVICE_NAME_LABEL)
: l10n_util::GetStringFUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_ANOTHER_TAB_NO_DEVICE_NAME_LABEL,
shared_tab_name);
}
std::u16string GetMessageTextCasting(bool shared_tab,
const std::u16string& shared_tab_name,
const std::u16string& sink_name) {
if (sink_name.empty()) {
return GetMessageTextCastingNoSinkName(shared_tab, shared_tab_name);
}
if (shared_tab) {
return l10n_util::GetStringFUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_CURRENT_TAB_LABEL, sink_name);
}
return shared_tab_name.empty()
? l10n_util::GetStringFUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_ANOTHER_UNTITLED_TAB_LABEL,
sink_name)
: l10n_util::GetStringFUTF16(
IDS_TAB_CASTING_INFOBAR_CASTING_ANOTHER_TAB_LABEL,
shared_tab_name, sink_name);
}
std::u16string GetMessageTextCapturing(bool shared_tab,
const std::u16string& shared_tab_name,
const std::u16string& app_name) {
if (shared_tab) {
return l10n_util::GetStringFUTF16(
IDS_TAB_SHARING_INFOBAR_SHARING_CURRENT_TAB_LABEL, app_name);
}
return !shared_tab_name.empty()
? l10n_util::GetStringFUTF16(
IDS_TAB_SHARING_INFOBAR_SHARING_ANOTHER_TAB_LABEL,
shared_tab_name, app_name)
: l10n_util::GetStringFUTF16(
IDS_TAB_SHARING_INFOBAR_SHARING_ANOTHER_UNTITLED_TAB_LABEL,
app_name);
}
} // namespace
// static
infobars::InfoBar* TabSharingInfoBarDelegate::Create(
infobars::ContentInfoBarManager* infobar_manager,
const std::u16string& shared_tab_name,
const std::u16string& capturer_name,
bool shared_tab,
ButtonState share_this_tab_instead_button_state,
absl::optional<FocusTarget> focus_target,
TabSharingUI* ui,
TabShareType capture_type,
bool favicons_used_for_switch_to_tab_button) {
DCHECK(infobar_manager);
return infobar_manager->AddInfoBar(
CreateConfirmInfoBar(base::WrapUnique(new TabSharingInfoBarDelegate(
shared_tab_name, capturer_name, shared_tab,
share_this_tab_instead_button_state, focus_target, ui, capture_type,
favicons_used_for_switch_to_tab_button))));
}
TabSharingInfoBarDelegate::TabSharingInfoBarDelegate(
std::u16string shared_tab_name,
std::u16string capturer_name,
bool shared_tab,
ButtonState share_this_tab_instead_button_state,
absl::optional<FocusTarget> focus_target,
TabSharingUI* ui,
TabShareType capture_type,
bool favicons_used_for_switch_to_tab_button)
: shared_tab_name_(std::move(shared_tab_name)),
shared_tab_(shared_tab),
capturer_name_(std::move(capturer_name)),
ui_(ui),
favicons_used_for_switch_to_tab_button_(
favicons_used_for_switch_to_tab_button),
capture_type_(capture_type) {
auto share_this_tab_instead_button =
share_this_tab_instead_button_state != ButtonState::NOT_SHOWN
? std::make_unique<ShareTabInsteadButton>(
ui_, share_this_tab_instead_button_state, capture_type_)
: nullptr;
auto quick_nav =
focus_target.has_value()
? std::make_unique<SwitchToTabButton>(*focus_target, shared_tab)
: nullptr;
if (share_this_tab_instead_button && quick_nav) {
// [Stop] [Share-this-tab-instead] [View tab: ...]
secondary_button_ = std::move(share_this_tab_instead_button);
tertiary_button_ = std::move(quick_nav);
} else if (share_this_tab_instead_button) {
// [Stop] [Share-this-tab-instead]
secondary_button_ = std::move(share_this_tab_instead_button);
} else if (quick_nav) {
// [Stop] [View tab: ...]
secondary_button_ = std::move(quick_nav);
}
}
TabSharingInfoBarDelegate::~TabSharingInfoBarDelegate() = default;
bool TabSharingInfoBarDelegate::EqualsDelegate(
InfoBarDelegate* delegate) const {
return false;
}
bool TabSharingInfoBarDelegate::ShouldExpire(
const NavigationDetails& details) const {
return false;
}
infobars::InfoBarDelegate::InfoBarIdentifier
TabSharingInfoBarDelegate::GetIdentifier() const {
return TAB_SHARING_INFOBAR_DELEGATE;
}
std::u16string TabSharingInfoBarDelegate::GetMessageText() const {
switch (capture_type_) {
case TabShareType::CAST:
return GetMessageTextCasting(shared_tab_, shared_tab_name_,
capturer_name_);
case TabShareType::CAPTURE:
return GetMessageTextCapturing(shared_tab_, shared_tab_name_,
capturer_name_);
}
NOTREACHED();
return std::u16string();
}
std::u16string TabSharingInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
if (button == BUTTON_OK) {
switch (capture_type_) {
case TabSharingInfoBarDelegate::TabShareType::CAST:
return l10n_util::GetStringUTF16(IDS_TAB_CASTING_INFOBAR_STOP_BUTTON);
case TabSharingInfoBarDelegate::TabShareType::CAPTURE:
return l10n_util::GetStringUTF16(IDS_TAB_SHARING_INFOBAR_STOP_BUTTON);
}
NOTREACHED();
return std::u16string();
} else if (button == BUTTON_CANCEL) {
DCHECK(secondary_button_);
return secondary_button_->GetLabel();
} else if (button == BUTTON_EXTRA) {
DCHECK(tertiary_button_);
return tertiary_button_->GetLabel();
}
return ConfirmInfoBarDelegate::GetButtonLabel(button);
}
ui::ImageModel TabSharingInfoBarDelegate::GetButtonImage(
InfoBarButton button) const {
if (favicons_used_for_switch_to_tab_button_) {
if (button == BUTTON_CANCEL) {
DCHECK(secondary_button_);
return secondary_button_->GetImage();
} else if (button == BUTTON_EXTRA) {
DCHECK(tertiary_button_);
return tertiary_button_->GetImage();
}
}
return ConfirmInfoBarDelegate::GetButtonImage(button);
}
bool TabSharingInfoBarDelegate::GetButtonEnabled(InfoBarButton button) const {
if (button == BUTTON_CANCEL) {
DCHECK(secondary_button_);
return secondary_button_->IsEnabled();
} else if (button == BUTTON_EXTRA) {
DCHECK(tertiary_button_);
return tertiary_button_->IsEnabled();
}
return ConfirmInfoBarDelegate::GetButtonEnabled(button);
}
std::u16string TabSharingInfoBarDelegate::GetButtonTooltip(
InfoBarButton button) const {
if (button == BUTTON_CANCEL) {
DCHECK(secondary_button_);
return secondary_button_->GetTooltip();
} else if (button == BUTTON_EXTRA) {
DCHECK(tertiary_button_);
return tertiary_button_->GetTooltip();
}
return ConfirmInfoBarDelegate::GetButtonTooltip(button);
}
int TabSharingInfoBarDelegate::GetButtons() const {
return BUTTON_OK | (secondary_button_ ? BUTTON_CANCEL : 0) |
(tertiary_button_ ? BUTTON_EXTRA : 0);
}
bool TabSharingInfoBarDelegate::Accept() {
ui_->StopSharing();
return false;
}
bool TabSharingInfoBarDelegate::Cancel() {
DCHECK(secondary_button_);
secondary_button_->Click(infobar());
return false;
}
bool TabSharingInfoBarDelegate::ExtraButtonPressed() {
DCHECK(tertiary_button_);
tertiary_button_->Click(infobar());
return false;
}
bool TabSharingInfoBarDelegate::IsCloseable() const {
return false;
}
const gfx::VectorIcon& TabSharingInfoBarDelegate::GetVectorIcon() const {
return vector_icons::kScreenShareIcon;
}