OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/webui/media_router/media_router_dialog_controller.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "chrome/browser/media/router/presentation_service_delegate_impl.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h" | |
13 #include "chrome/browser/ui/webui/media_router/media_router_ui.h" | |
14 #include "chrome/common/url_constants.h" | |
15 #include "components/web_modal/web_contents_modal_dialog_host.h" | |
16 #include "content/public/browser/browser_thread.h" | |
17 #include "content/public/browser/navigation_controller.h" | |
18 #include "content/public/browser/navigation_details.h" | |
19 #include "content/public/browser/navigation_entry.h" | |
20 #include "content/public/browser/render_frame_host.h" | |
21 #include "content/public/browser/render_process_host.h" | |
22 #include "content/public/browser/render_view_host.h" | |
23 #include "content/public/browser/web_contents.h" | |
24 #include "content/public/browser/web_contents_delegate.h" | |
25 #include "ui/web_dialogs/web_dialog_delegate.h" | |
26 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h" | |
27 #include "url/gurl.h" | |
28 | |
29 DEFINE_WEB_CONTENTS_USER_DATA_KEY(media_router::MediaRouterDialogController); | |
30 | |
31 using content::LoadCommittedDetails; | |
32 using content::NavigationController; | |
33 using content::WebContents; | |
34 using content::WebUIMessageHandler; | |
35 using ui::WebDialogDelegate; | |
36 | |
37 namespace { | |
38 const int kMaxHeight = 260; | |
39 #if !defined(OS_MACOSX) | |
40 const int kMinHeight = 130; | |
41 #endif // !defined(OS_MACOSX) | |
42 const int kWidth = 340; | |
43 } | |
44 | |
45 namespace media_router { | |
46 | |
47 namespace { | |
48 | |
49 // WebDialogDelegate that specifies what the media router dialog | |
50 // will look like. | |
51 class MediaRouterDialogDelegate : public WebDialogDelegate { | |
52 public: | |
53 MediaRouterDialogDelegate() {} | |
54 ~MediaRouterDialogDelegate() override {} | |
55 | |
56 // WebDialogDelegate implementation. | |
57 ui::ModalType GetDialogModalType() const override { | |
58 // Not used, returning dummy value. | |
59 return ui::MODAL_TYPE_WINDOW; | |
60 } | |
61 | |
62 base::string16 GetDialogTitle() const override { | |
63 return base::string16(); | |
64 } | |
65 | |
66 GURL GetDialogContentURL() const override { | |
67 return GURL(chrome::kChromeUIMediaRouterURL); | |
68 } | |
69 | |
70 void GetWebUIMessageHandlers( | |
71 std::vector<WebUIMessageHandler*>* handlers) const override { | |
72 // MediaRouterUI adds its own message handlers. | |
73 } | |
74 | |
75 void GetDialogSize(gfx::Size* size) const override; | |
76 | |
77 std::string GetDialogArgs() const override { | |
78 return std::string(); | |
79 } | |
80 | |
81 void OnDialogClosed(const std::string& json_retval) override { | |
82 // We don't delete |this| here because this class is owned | |
83 // by ConstrainedWebDialogDelegate. | |
84 } | |
85 | |
86 void OnCloseContents(WebContents* source, bool* out_close_dialog) override { | |
87 if (out_close_dialog) | |
88 *out_close_dialog = true; | |
89 } | |
90 | |
91 bool ShouldShowDialogTitle() const override { | |
92 return false; | |
93 } | |
94 | |
95 private: | |
96 DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogDelegate); | |
97 }; | |
98 | |
99 void MediaRouterDialogDelegate::GetDialogSize(gfx::Size* size) const { | |
100 DCHECK(size); | |
101 // TODO(apacible): Remove after autoresizing is implemented for OSX. | |
102 #if defined(OS_MACOSX) | |
103 *size = gfx::Size(kWidth, kMaxHeight); | |
104 #else | |
105 // size is not used because the dialog is auto-resizeable. | |
106 *size = gfx::Size(); | |
107 #endif | |
108 } | |
109 | |
110 } // namespace | |
111 | |
112 // static | |
113 MediaRouterDialogController* | |
114 MediaRouterDialogController::GetOrCreateForWebContents( | |
115 WebContents* web_contents) { | |
116 DCHECK(web_contents); | |
117 // This call does nothing if the controller already exists. | |
118 MediaRouterDialogController::CreateForWebContents(web_contents); | |
119 return MediaRouterDialogController::FromWebContents(web_contents); | |
120 } | |
121 | |
122 class MediaRouterDialogController::DialogWebContentsObserver | |
123 : public content::WebContentsObserver { | |
124 public: | |
125 DialogWebContentsObserver( | |
126 WebContents* web_contents, | |
127 MediaRouterDialogController* dialog_controller) | |
128 : content::WebContentsObserver(web_contents), | |
129 dialog_controller_(dialog_controller) { | |
130 } | |
131 | |
132 private: | |
133 void WebContentsDestroyed() override { | |
134 // The dialog is already closed. No need to call Close() again. | |
135 // NOTE: |this| is deleted after Reset() returns. | |
136 dialog_controller_->Reset(); | |
137 } | |
138 | |
139 void NavigationEntryCommitted(const LoadCommittedDetails& load_details) | |
140 override { | |
141 dialog_controller_->OnDialogNavigated(load_details); | |
142 } | |
143 | |
144 void RenderProcessGone(base::TerminationStatus status) override { | |
145 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns. | |
146 dialog_controller_->CloseMediaRouterDialog(); | |
147 } | |
148 | |
149 MediaRouterDialogController* const dialog_controller_; | |
150 }; | |
151 | |
152 class MediaRouterDialogController::InitiatorWebContentsObserver | |
153 : public content::WebContentsObserver { | |
154 public: | |
155 InitiatorWebContentsObserver( | |
156 WebContents* web_contents, | |
157 MediaRouterDialogController* dialog_controller) | |
158 : content::WebContentsObserver(web_contents), | |
159 dialog_controller_(dialog_controller) { | |
160 } | |
161 | |
162 private: | |
163 void WebContentsDestroyed() override { | |
164 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns. | |
165 dialog_controller_->CloseMediaRouterDialog(); | |
166 } | |
167 | |
168 void NavigationEntryCommitted(const LoadCommittedDetails& load_details) | |
169 override { | |
170 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns. | |
171 dialog_controller_->CloseMediaRouterDialog(); | |
172 } | |
173 | |
174 void RenderProcessGone(base::TerminationStatus status) override { | |
175 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns. | |
176 dialog_controller_->CloseMediaRouterDialog(); | |
177 } | |
178 | |
179 MediaRouterDialogController* const dialog_controller_; | |
180 }; | |
181 | |
182 MediaRouterDialogController::MediaRouterDialogController( | |
183 WebContents* web_contents) | |
184 : initiator_(web_contents), | |
185 media_router_dialog_pending_(false) { | |
186 DCHECK(initiator_); | |
187 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
188 } | |
189 | |
190 MediaRouterDialogController::~MediaRouterDialogController() { | |
191 DCHECK(thread_checker_.CalledOnValidThread()); | |
192 } | |
193 | |
194 WebContents* MediaRouterDialogController::ShowMediaRouterDialog() { | |
195 DCHECK(thread_checker_.CalledOnValidThread()); | |
196 | |
197 // Get the media router dialog for |initiator|, or create a new dialog | |
198 // if not found. | |
199 WebContents* media_router_dialog = GetMediaRouterDialog(); | |
200 if (!media_router_dialog) { | |
201 CreateMediaRouterDialog(); | |
202 return GetMediaRouterDialog(); | |
203 } | |
204 | |
205 // Show the initiator holding the existing media router dialog. | |
206 initiator_->GetDelegate()->ActivateContents(initiator_); | |
207 return media_router_dialog; | |
208 } | |
209 | |
210 WebContents* MediaRouterDialogController::ShowMediaRouterDialogForPresentation( | |
211 scoped_ptr<CreatePresentationSessionRequest> request) { | |
212 DCHECK(thread_checker_.CalledOnValidThread()); | |
213 | |
214 // Get the media router dialog for |initiator|, or create a new dialog | |
215 // if not found. | |
216 WebContents* media_router_dialog = GetMediaRouterDialog(); | |
217 if (!media_router_dialog) { | |
218 CreateMediaRouterDialog(); | |
219 media_router_dialog = GetMediaRouterDialog(); | |
220 presentation_request_ = request.Pass(); | |
221 return media_router_dialog; | |
222 } | |
223 | |
224 // Show the initiator holding the existing media router dialog. | |
225 initiator_->GetDelegate()->ActivateContents(initiator_); | |
226 return nullptr; | |
227 } | |
228 | |
229 WebContents* MediaRouterDialogController::GetMediaRouterDialog() const { | |
230 DCHECK(thread_checker_.CalledOnValidThread()); | |
231 return dialog_observer_.get() ? dialog_observer_->web_contents() : nullptr; | |
232 } | |
233 | |
234 void MediaRouterDialogController::CloseMediaRouterDialog() { | |
235 DCHECK(thread_checker_.CalledOnValidThread()); | |
236 DCHECK(initiator_observer_.get()); | |
237 WebContents* media_router_dialog = GetMediaRouterDialog(); | |
238 CHECK(media_router_dialog); | |
239 Reset(); | |
240 | |
241 content::WebUI* web_ui = media_router_dialog->GetWebUI(); | |
242 if (web_ui) { | |
243 MediaRouterUI* media_router_ui = | |
244 static_cast<MediaRouterUI*>(web_ui->GetController()); | |
245 if (media_router_ui) | |
246 media_router_ui->Close(); | |
247 } | |
248 } | |
249 | |
250 void MediaRouterDialogController::CreateMediaRouterDialog() { | |
251 DCHECK(!initiator_observer_.get()); | |
252 DCHECK(!dialog_observer_.get()); | |
253 | |
254 Profile* profile = | |
255 Profile::FromBrowserContext(initiator_->GetBrowserContext()); | |
256 DCHECK(profile); | |
257 | |
258 WebDialogDelegate* web_dialog_delegate = new MediaRouterDialogDelegate; | |
259 | |
260 // |web_dialog_delegate|'s owner is |constrained_delegate|. | |
261 // |constrained_delegate| is owned by the parent |views::View|. | |
262 // TODO(apacible): Remove after autoresizing is implemented for OSX. | |
263 #if defined(OS_MACOSX) | |
264 ConstrainedWebDialogDelegate* constrained_delegate = | |
265 ShowConstrainedWebDialog(profile, web_dialog_delegate, initiator_); | |
266 #else | |
267 // TODO(apacible): Adjust min and max sizes based on new WebUI design. | |
268 gfx::Size min_size = gfx::Size(kWidth, kMinHeight); | |
269 gfx::Size max_size = gfx::Size(kWidth, kMaxHeight); | |
270 | |
271 // |ShowConstrainedWebDialogWithAutoResize()| will end up creating | |
272 // ConstrainedWebDialogDelegateViewViews containing a WebContents containing | |
273 // the MediaRouterUI, using the provided |web_dialog_delegate|. Then, the | |
274 // view is shown as a modal dialog constrained to the |initiator| WebContents. | |
275 // The dialog will resize between the |min_size| and |max_size| bounds based | |
276 // on the currently rendered contents. | |
277 ConstrainedWebDialogDelegate* constrained_delegate = | |
278 ShowConstrainedWebDialogWithAutoResize( | |
279 profile, web_dialog_delegate, initiator_, min_size, max_size); | |
280 #endif | |
281 | |
282 WebContents* media_router_dialog = constrained_delegate->GetWebContents(); | |
283 | |
284 media_router_dialog_pending_ = true; | |
285 | |
286 initiator_observer_.reset(new InitiatorWebContentsObserver( | |
287 initiator_, this)); | |
288 dialog_observer_.reset(new DialogWebContentsObserver( | |
289 media_router_dialog, this)); | |
290 } | |
291 | |
292 void MediaRouterDialogController::Reset() { | |
293 DCHECK(thread_checker_.CalledOnValidThread()); | |
294 DCHECK(initiator_observer_.get()); | |
295 DCHECK(dialog_observer_.get()); | |
296 initiator_observer_.reset(); | |
297 dialog_observer_.reset(); | |
298 presentation_request_.reset(); | |
299 } | |
300 | |
301 void MediaRouterDialogController::OnDialogNavigated( | |
302 const content::LoadCommittedDetails& details) { | |
303 DCHECK(thread_checker_.CalledOnValidThread()); | |
304 WebContents* media_router_dialog = GetMediaRouterDialog(); | |
305 CHECK(media_router_dialog); | |
306 ui::PageTransition transition_type = details.entry->GetTransitionType(); | |
307 content::NavigationType nav_type = details.type; | |
308 | |
309 // New |media_router_dialog| is created. | |
310 DCHECK(media_router_dialog_pending_); | |
311 DCHECK(transition_type == ui::PAGE_TRANSITION_AUTO_TOPLEVEL && | |
312 nav_type == content::NAVIGATION_TYPE_NEW_PAGE) | |
313 << "transition_type: " << transition_type << ", " | |
314 << "nav_type: " << nav_type; | |
315 | |
316 media_router_dialog_pending_ = false; | |
317 | |
318 PopulateDialog(media_router_dialog); | |
319 } | |
320 | |
321 void MediaRouterDialogController::PopulateDialog( | |
322 content::WebContents* media_router_dialog) { | |
323 DCHECK(media_router_dialog); | |
324 DCHECK(initiator_observer_); | |
325 if (!initiator_observer_) { | |
326 Reset(); | |
327 return; | |
328 } | |
329 content::WebContents* initiator = initiator_observer_->web_contents(); | |
330 DCHECK(initiator); | |
331 if (!initiator || !media_router_dialog->GetWebUI()) { | |
332 Reset(); | |
333 return; | |
334 } | |
335 | |
336 MediaRouterUI* media_router_ui = static_cast<MediaRouterUI*>( | |
337 media_router_dialog->GetWebUI()->GetController()); | |
338 DCHECK(media_router_ui); | |
339 if (!media_router_ui) { | |
340 Reset(); | |
341 return; | |
342 } | |
343 | |
344 if (!presentation_request_.get()) { | |
345 // TODO(imcheng): Don't create PresentationServiceDelegateImpl if it doesn't | |
346 // exist (crbug.com/508695). | |
347 base::WeakPtr<PresentationServiceDelegateImpl> delegate = | |
348 PresentationServiceDelegateImpl::GetOrCreateForWebContents(initiator) | |
349 ->GetWeakPtr(); | |
350 media_router_ui->InitWithDefaultMediaSource(delegate); | |
351 } else { | |
352 media_router_ui->InitWithPresentationSessionRequest( | |
353 initiator, presentation_request_.Pass()); | |
354 } | |
355 } | |
356 | |
357 } // namespace media_router | |
358 | |
OLD | NEW |