1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/media_router/presentation_receiver_window_controller.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/check_op.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_destroyer.h"
15 #include "chrome/browser/ui/media_router/presentation_receiver_window.h"
16 #include "components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/presentation_receiver_flags.h"
20 #include "content/public/browser/web_contents.h"
21 #include "ui/views/widget/widget.h"
22
23 using content::WebContents;
24
25 namespace {
26
CreateWebContentsParams(Profile * profile)27 WebContents::CreateParams CreateWebContentsParams(Profile* profile) {
28 WebContents::CreateParams params(profile);
29 params.starting_sandbox_flags = content::kPresentationReceiverSandboxFlags;
30 return params;
31 }
32
33 } // namespace
34
35 // static
36 std::unique_ptr<PresentationReceiverWindowController>
CreateFromOriginalProfile(Profile * profile,const gfx::Rect & bounds,base::OnceClosure termination_callback,TitleChangeCallback title_change_callback)37 PresentationReceiverWindowController::CreateFromOriginalProfile(
38 Profile* profile,
39 const gfx::Rect& bounds,
40 base::OnceClosure termination_callback,
41 TitleChangeCallback title_change_callback) {
42 DCHECK(profile);
43 DCHECK(!profile->IsOffTheRecord());
44 DCHECK(termination_callback);
45 return base::WrapUnique(new PresentationReceiverWindowController(
46 profile, bounds, std::move(termination_callback),
47 std::move(title_change_callback)));
48 }
49
~PresentationReceiverWindowController()50 PresentationReceiverWindowController::~PresentationReceiverWindowController() {
51 DCHECK(!web_contents_);
52 DCHECK(!window_);
53
54 if (otr_profile_) {
55 otr_profile_->RemoveObserver(this);
56 ProfileDestroyer::DestroyProfileWhenAppropriate(otr_profile_);
57 }
58 }
59
Start(const std::string & presentation_id,const GURL & start_url)60 void PresentationReceiverWindowController::Start(
61 const std::string& presentation_id,
62 const GURL& start_url) {
63 DCHECK(window_);
64 DCHECK(web_contents_);
65
66 media_router::ReceiverPresentationServiceDelegateImpl::CreateForWebContents(
67 web_contents_.get(), presentation_id);
68
69 content::NavigationController::LoadURLParams load_params(start_url);
70 load_params.should_replace_current_entry = true;
71 load_params.should_clear_history_list = true;
72 web_contents_->GetController().LoadURLWithParams(load_params);
73
74 window_->ShowInactiveFullscreen();
75 }
76
Terminate()77 void PresentationReceiverWindowController::Terminate() {
78 if (web_contents_) {
79 web_contents_->ClosePage();
80 } else if (window_) {
81 window_->Close();
82 } else if (termination_callback_) {
83 std::move(termination_callback_).Run();
84 }
85 }
86
ExitFullscreen()87 void PresentationReceiverWindowController::ExitFullscreen() {
88 window_->ExitFullscreen();
89 }
90
CloseWindowForTest()91 void PresentationReceiverWindowController::CloseWindowForTest() {
92 window_->Close();
93 }
94
IsWindowActiveForTest() const95 bool PresentationReceiverWindowController::IsWindowActiveForTest() const {
96 return window_->IsWindowActive();
97 }
98
IsWindowFullscreenForTest() const99 bool PresentationReceiverWindowController::IsWindowFullscreenForTest() const {
100 return window_->IsWindowFullscreen();
101 }
102
GetWindowBoundsForTest() const103 gfx::Rect PresentationReceiverWindowController::GetWindowBoundsForTest() const {
104 return window_->GetWindowBounds();
105 }
106
web_contents() const107 WebContents* PresentationReceiverWindowController::web_contents() const {
108 return web_contents_.get();
109 }
110
PresentationReceiverWindowController(Profile * profile,const gfx::Rect & bounds,base::OnceClosure termination_callback,TitleChangeCallback title_change_callback)111 PresentationReceiverWindowController::PresentationReceiverWindowController(
112 Profile* profile,
113 const gfx::Rect& bounds,
114 base::OnceClosure termination_callback,
115 TitleChangeCallback title_change_callback)
116 : otr_profile_(profile->GetOffTheRecordProfile(
117 Profile::OTRProfileID::CreateUniqueForMediaRouter())),
118 web_contents_(WebContents::Create(CreateWebContentsParams(otr_profile_))),
119 window_(PresentationReceiverWindow::Create(this, bounds)),
120 termination_callback_(std::move(termination_callback)),
121 title_change_callback_(std::move(title_change_callback)) {
122 DCHECK(otr_profile_);
123 DCHECK(otr_profile_->IsOffTheRecord());
124 otr_profile_->AddObserver(this);
125 content::WebContentsObserver::Observe(web_contents_.get());
126 web_contents_->SetDelegate(this);
127 }
128
WindowClosed()129 void PresentationReceiverWindowController::WindowClosed() {
130 window_ = nullptr;
131 Terminate();
132 }
133
OnProfileWillBeDestroyed(Profile * profile)134 void PresentationReceiverWindowController::OnProfileWillBeDestroyed(
135 Profile* profile) {
136 DCHECK(profile == otr_profile_);
137 web_contents_.reset();
138 otr_profile_ = nullptr;
139 Terminate();
140 }
141
DidStartNavigation(content::NavigationHandle * handle)142 void PresentationReceiverWindowController::DidStartNavigation(
143 content::NavigationHandle* handle) {
144 if (!navigation_policy_.AllowNavigation(handle))
145 Terminate();
146 }
147
TitleWasSet(content::NavigationEntry * entry)148 void PresentationReceiverWindowController::TitleWasSet(
149 content::NavigationEntry* entry) {
150 window_->UpdateWindowTitle();
151 if (entry)
152 title_change_callback_.Run(base::UTF16ToUTF8(entry->GetTitle()));
153 }
154
NavigationStateChanged(WebContents * source,content::InvalidateTypes changed_flags)155 void PresentationReceiverWindowController::NavigationStateChanged(
156 WebContents* source,
157 content::InvalidateTypes changed_flags) {
158 window_->UpdateLocationBar();
159 }
160
CloseContents(content::WebContents * source)161 void PresentationReceiverWindowController::CloseContents(
162 content::WebContents* source) {
163 web_contents_.reset();
164 Terminate();
165 }
166
ShouldSuppressDialogs(content::WebContents * source)167 bool PresentationReceiverWindowController::ShouldSuppressDialogs(
168 content::WebContents* source) {
169 DCHECK_EQ(web_contents_.get(), source);
170 // Suppress all because there is no possible direct user interaction with
171 // dialogs.
172 // TODO(https://crbug.com/734191): This does not suppress window.print().
173 return true;
174 }
175
ShouldFocusLocationBarByDefault(content::WebContents * source)176 bool PresentationReceiverWindowController::ShouldFocusLocationBarByDefault(
177 content::WebContents* source) {
178 DCHECK_EQ(web_contents_.get(), source);
179 // Indicate the location bar should be focused instead of the page, even
180 // though there is no location bar in fullscreen (the presentation's default
181 // state). This will prevent the page from automatically receiving input
182 // focus, which is usually not intended.
183 return true;
184 }
185
ShouldFocusPageAfterCrash()186 bool PresentationReceiverWindowController::ShouldFocusPageAfterCrash() {
187 // Never focus the page after a crash.
188 return false;
189 }
190
CanDownload(const GURL & url,const std::string & request_method,base::OnceCallback<void (bool)> callback)191 void PresentationReceiverWindowController::CanDownload(
192 const GURL& url,
193 const std::string& request_method,
194 base::OnceCallback<void(bool)> callback) {
195 // Local presentation pages are not allowed to download files.
196 std::move(callback).Run(false);
197 }
198
IsWebContentsCreationOverridden(content::SiteInstance * source_site_instance,content::mojom::WindowContainerType window_container_type,const GURL & opener_url,const std::string & frame_name,const GURL & target_url)199 bool PresentationReceiverWindowController::IsWebContentsCreationOverridden(
200 content::SiteInstance* source_site_instance,
201 content::mojom::WindowContainerType window_container_type,
202 const GURL& opener_url,
203 const std::string& frame_name,
204 const GURL& target_url) {
205 // Disallow creating separate WebContentses. The WebContents implementation
206 // uses this to spawn new windows/tabs, which is also not allowed for
207 // local presentations.
208 return true;
209 }
210