blob: 0c4c9c8ad4bf31ad0c918a36747cfb57a1df4c29 [file] [log] [blame]
// 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/ui/views/media_router/presentation_receiver_window_view.h"
#include "base/logging.h"
#include "base/macros.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
#include "chrome/browser/ui/media_router/presentation_receiver_window_delegate.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "chrome/browser/ui/search/search_tab_helper.h"
#include "chrome/browser/ui/tab_dialogs.h"
#include "chrome/browser/ui/views/accelerator_table.h"
#include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
#include "chrome/browser/ui/views/media_router/presentation_receiver_window_frame.h"
#include "components/toolbar/toolbar_model_impl.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_constants.h"
#include "ui/base/accelerators/accelerator_manager.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS)
#include "ash/public/cpp/window_properties.h"
#include "ash/public/interfaces/window_state_type.mojom.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/gfx/native_widget_types.h"
#endif
using content::WebContents;
#if defined(OS_CHROMEOS)
// Observes the NativeWindow hosting the receiver view to look for fullscreen
// state changes. This helps monitor fullscreen changes that don't go through
// the normal key accelerator to display and hide the location bar.
class PresentationReceiverWindowView::FullscreenWindowObserver final
: public aura::WindowObserver {
public:
explicit FullscreenWindowObserver(
PresentationReceiverWindowView* presentation_receiver_window_view);
~FullscreenWindowObserver() final;
private:
// aura::WindowObserver overrides.
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) final;
void OnWindowDestroying(aura::Window* window) final;
PresentationReceiverWindowView* const presentation_receiver_window_view_;
DISALLOW_COPY_AND_ASSIGN(FullscreenWindowObserver);
};
PresentationReceiverWindowView::FullscreenWindowObserver::
FullscreenWindowObserver(
PresentationReceiverWindowView* presentation_receiver_window_view)
: presentation_receiver_window_view_(presentation_receiver_window_view) {
DCHECK(presentation_receiver_window_view);
DCHECK(presentation_receiver_window_view->GetWidget());
DCHECK(presentation_receiver_window_view->GetWidget()->GetNativeWindow());
presentation_receiver_window_view_->GetWidget()
->GetNativeWindow()
->AddObserver(this);
}
PresentationReceiverWindowView::FullscreenWindowObserver::
~FullscreenWindowObserver() = default;
void PresentationReceiverWindowView::FullscreenWindowObserver::
OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
DCHECK(presentation_receiver_window_view_->GetWidget());
DCHECK(window ==
presentation_receiver_window_view_->GetWidget()->GetNativeWindow());
if (key == ash::kWindowStateTypeKey) {
ash::mojom::WindowStateType new_state =
window->GetProperty(ash::kWindowStateTypeKey);
ash::mojom::WindowStateType old_state(
static_cast<ash::mojom::WindowStateType>(old));
// Toggle fullscreen when the user toggles fullscreen without going through
// FullscreenController::ToggleBrowserFullscreenMode(). This is the case if
// the user uses a hardware window state toggle button.
if (new_state != ash::mojom::WindowStateType::FULLSCREEN &&
new_state != ash::mojom::WindowStateType::PINNED &&
new_state != ash::mojom::WindowStateType::TRUSTED_PINNED &&
new_state != ash::mojom::WindowStateType::MINIMIZED &&
old_state == ash::mojom::WindowStateType::FULLSCREEN) {
presentation_receiver_window_view_->ExitFullscreen();
} else if (new_state == ash::mojom::WindowStateType::FULLSCREEN &&
old_state != ash::mojom::WindowStateType::PINNED &&
old_state != ash::mojom::WindowStateType::TRUSTED_PINNED) {
presentation_receiver_window_view_->EnterFullscreen();
}
}
}
void PresentationReceiverWindowView::FullscreenWindowObserver::
OnWindowDestroying(aura::Window* window) {
DCHECK(presentation_receiver_window_view_->GetWidget());
DCHECK(window ==
presentation_receiver_window_view_->GetWidget()->GetNativeWindow());
presentation_receiver_window_view_->GetWidget()
->GetNativeWindow()
->RemoveObserver(this);
}
#endif
PresentationReceiverWindowView::PresentationReceiverWindowView(
PresentationReceiverWindowFrame* frame,
PresentationReceiverWindowDelegate* delegate)
: frame_(frame),
delegate_(delegate),
toolbar_model_(
std::make_unique<ToolbarModelImpl>(this,
content::kMaxURLDisplayChars)),
command_updater_(this),
exclusive_access_manager_(this) {
DCHECK(frame);
DCHECK(delegate);
}
PresentationReceiverWindowView::~PresentationReceiverWindowView() = default;
void PresentationReceiverWindowView::Init() {
auto* const focus_manager = GetFocusManager();
DCHECK(focus_manager);
const auto accelerators = GetAcceleratorList();
const auto fullscreen_accelerator =
std::find_if(accelerators.begin(), accelerators.end(),
[](const AcceleratorMapping& accelerator) {
return accelerator.command_id == IDC_FULLSCREEN;
});
DCHECK(fullscreen_accelerator != accelerators.end());
fullscreen_accelerator_ = ui::Accelerator(fullscreen_accelerator->keycode,
fullscreen_accelerator->modifiers);
focus_manager->RegisterAccelerator(
fullscreen_accelerator_, ui::AcceleratorManager::kNormalPriority, this);
auto* const web_contents = GetWebContents();
DCHECK(web_contents);
SecurityStateTabHelper::CreateForWebContents(web_contents);
ChromeTranslateClient::CreateForWebContents(web_contents);
autofill::ChromeAutofillClient::CreateForWebContents(web_contents);
ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
web_contents,
autofill::ChromeAutofillClient::FromWebContents(web_contents));
ManagePasswordsUIController::CreateForWebContents(web_contents);
SearchTabHelper::CreateForWebContents(web_contents);
TabDialogs::CreateForWebContents(web_contents);
FramebustBlockTabHelper::CreateForWebContents(web_contents);
ChromeSubresourceFilterClient::CreateForWebContents(web_contents);
InfoBarService::CreateForWebContents(web_contents);
MixedContentSettingsTabHelper::CreateForWebContents(web_contents);
PopupBlockerTabHelper::CreateForWebContents(web_contents);
TabSpecificContentSettings::CreateForWebContents(web_contents);
auto* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
auto* web_view = new views::WebView(profile);
web_view->SetWebContents(web_contents);
web_view->set_allow_accelerators(true);
location_bar_view_ =
new LocationBarView(nullptr, profile, &command_updater_, this, true);
auto box_owner =
std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical);
box_owner->set_cross_axis_alignment(
views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
auto* box = SetLayoutManager(std::move(box_owner));
AddChildView(location_bar_view_);
box->SetFlexForView(location_bar_view_, 0);
AddChildView(web_view);
box->SetFlexForView(web_view, 1);
location_bar_view_->Init();
#if defined(OS_CHROMEOS)
window_observer_ = std::make_unique<FullscreenWindowObserver>(this);
#endif
}
void PresentationReceiverWindowView::Close() {
frame_->Close();
}
bool PresentationReceiverWindowView::IsWindowActive() const {
return frame_->IsActive();
}
bool PresentationReceiverWindowView::IsWindowFullscreen() const {
return frame_->IsFullscreen();
}
gfx::Rect PresentationReceiverWindowView::GetWindowBounds() const {
return frame_->GetWindowBoundsInScreen();
}
void PresentationReceiverWindowView::ShowInactiveFullscreen() {
frame_->ShowInactive();
exclusive_access_manager_.fullscreen_controller()
->ToggleBrowserFullscreenMode();
}
void PresentationReceiverWindowView::UpdateWindowTitle() {
frame_->UpdateWindowTitle();
}
void PresentationReceiverWindowView::UpdateLocationBar() {
DCHECK(location_bar_view_);
location_bar_view_->Update(nullptr);
}
WebContents* PresentationReceiverWindowView::GetWebContents() {
return delegate_->web_contents();
}
ToolbarModel* PresentationReceiverWindowView::GetToolbarModel() {
return toolbar_model_.get();
}
const ToolbarModel* PresentationReceiverWindowView::GetToolbarModel() const {
return toolbar_model_.get();
}
ContentSettingBubbleModelDelegate*
PresentationReceiverWindowView::GetContentSettingBubbleModelDelegate() {
NOTREACHED();
return nullptr;
}
void PresentationReceiverWindowView::ExecuteCommandWithDisposition(
int id,
WindowOpenDisposition disposition) {
NOTREACHED();
}
WebContents* PresentationReceiverWindowView::GetActiveWebContents() const {
return delegate_->web_contents();
}
bool PresentationReceiverWindowView::CanResize() const {
return true;
}
bool PresentationReceiverWindowView::CanMaximize() const {
return true;
}
bool PresentationReceiverWindowView::CanMinimize() const {
return true;
}
void PresentationReceiverWindowView::DeleteDelegate() {
auto* const delegate = delegate_;
delete this;
delegate->WindowClosed();
}
base::string16 PresentationReceiverWindowView::GetWindowTitle() const {
return delegate_->web_contents()->GetTitle();
}
bool PresentationReceiverWindowView::AcceleratorPressed(
const ui::Accelerator& accelerator) {
exclusive_access_manager_.fullscreen_controller()
->ToggleBrowserFullscreenMode();
return true;
}
Profile* PresentationReceiverWindowView::GetProfile() {
return Profile::FromBrowserContext(
delegate_->web_contents()->GetBrowserContext());
}
bool PresentationReceiverWindowView::IsFullscreen() const {
return frame_->IsFullscreen();
}
void PresentationReceiverWindowView::EnterFullscreen(
const GURL& url,
ExclusiveAccessBubbleType bubble_type) {
EnterFullscreen();
UpdateExclusiveAccessExitBubbleContent(url, bubble_type,
ExclusiveAccessBubbleHideCallback());
}
void PresentationReceiverWindowView::ExitFullscreen() {
exclusive_access_bubble_.reset();
location_bar_view_->SetVisible(true);
frame_->SetFullscreen(false);
}
void PresentationReceiverWindowView::UpdateExclusiveAccessExitBubbleContent(
const GURL& url,
ExclusiveAccessBubbleType bubble_type,
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback) {
if (bubble_type == EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE) {
// |exclusive_access_bubble_.reset()| will trigger callback for current
// bubble with |ExclusiveAccessBubbleHideReason::kInterrupted| if available.
exclusive_access_bubble_.reset();
if (bubble_first_hide_callback) {
std::move(bubble_first_hide_callback)
.Run(ExclusiveAccessBubbleHideReason::kNotShown);
}
return;
}
if (exclusive_access_bubble_) {
exclusive_access_bubble_->UpdateContent(
url, bubble_type, std::move(bubble_first_hide_callback));
return;
}
exclusive_access_bubble_ = std::make_unique<ExclusiveAccessBubbleViews>(
this, url, bubble_type, std::move(bubble_first_hide_callback));
}
void PresentationReceiverWindowView::OnExclusiveAccessUserInput() {}
content::WebContents* PresentationReceiverWindowView::GetActiveWebContents() {
return delegate_->web_contents();
}
void PresentationReceiverWindowView::UnhideDownloadShelf() {}
void PresentationReceiverWindowView::HideDownloadShelf() {}
ExclusiveAccessManager*
PresentationReceiverWindowView::GetExclusiveAccessManager() {
return &exclusive_access_manager_;
}
views::Widget* PresentationReceiverWindowView::GetBubbleAssociatedWidget() {
return frame_;
}
ui::AcceleratorProvider*
PresentationReceiverWindowView::GetAcceleratorProvider() {
return this;
}
gfx::NativeView PresentationReceiverWindowView::GetBubbleParentView() const {
return frame_->GetNativeView();
}
gfx::Point PresentationReceiverWindowView::GetCursorPointInParent() const {
gfx::Point cursor_pos = display::Screen::GetScreen()->GetCursorScreenPoint();
views::View::ConvertPointFromScreen(GetWidget()->GetRootView(), &cursor_pos);
return cursor_pos;
}
gfx::Rect PresentationReceiverWindowView::GetClientAreaBoundsInScreen() const {
return GetWidget()->GetClientAreaBoundsInScreen();
}
bool PresentationReceiverWindowView::IsImmersiveModeEnabled() const {
return false;
}
gfx::Rect PresentationReceiverWindowView::GetTopContainerBoundsInScreen() {
return GetBoundsInScreen();
}
void PresentationReceiverWindowView::DestroyAnyExclusiveAccessBubble() {
exclusive_access_bubble_.reset();
}
bool PresentationReceiverWindowView::CanTriggerOnMouse() const {
return true;
}
bool PresentationReceiverWindowView::GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* accelerator) const {
if (command_id != IDC_FULLSCREEN)
return false;
*accelerator = fullscreen_accelerator_;
return true;
}
void PresentationReceiverWindowView::EnterFullscreen() {
location_bar_view_->SetVisible(false);
frame_->SetFullscreen(true);
}