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.
5 #include "chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.h"
10 #include "chrome/browser/media/router/presentation_service_delegate_impl.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/toolbar/media_router_action.h"
13 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
14 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
15 #include "chrome/common/url_constants.h"
16 #include "components/web_modal/web_contents_modal_dialog_host.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 "ui/web_dialogs/web_dialog_delegate.h"
24 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
27 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
28 media_router::MediaRouterDialogControllerImpl
);
30 using content::LoadCommittedDetails
;
31 using content::NavigationController
;
32 using content::WebContents
;
33 using content::WebUIMessageHandler
;
34 using ui::WebDialogDelegate
;
37 const int kMaxHeight
= 300;
38 #if !defined(OS_MACOSX)
39 const int kMinHeight
= 130;
40 #endif // !defined(OS_MACOSX)
41 const int kWidth
= 340;
44 namespace media_router
{
48 // WebDialogDelegate that specifies what the media router dialog
50 class MediaRouterDialogDelegate
: public WebDialogDelegate
{
52 explicit MediaRouterDialogDelegate(base::WeakPtr
<MediaRouterAction
> action
) {}
53 ~MediaRouterDialogDelegate() override
{}
55 // WebDialogDelegate implementation.
56 ui::ModalType
GetDialogModalType() const override
{
57 // Not used, returning dummy value.
58 return ui::MODAL_TYPE_WINDOW
;
61 base::string16
GetDialogTitle() const override
{
62 return base::string16();
65 GURL
GetDialogContentURL() const override
{
66 return GURL(chrome::kChromeUIMediaRouterURL
);
69 void GetWebUIMessageHandlers(
70 std::vector
<WebUIMessageHandler
*>* handlers
) const override
{
71 // MediaRouterUI adds its own message handlers.
74 void GetDialogSize(gfx::Size
* size
) const override
;
76 std::string
GetDialogArgs() const override
{
80 void OnDialogClosed(const std::string
& json_retval
) override
{
81 // We don't delete |this| here because this class is owned
82 // by ConstrainedWebDialogDelegate.
84 action_
->OnPopupHidden();
87 void OnCloseContents(WebContents
* source
, bool* out_close_dialog
) override
{
89 *out_close_dialog
= true;
92 bool ShouldShowDialogTitle() const override
{
96 void SetAction(const base::WeakPtr
<MediaRouterAction
>& action
) {
101 base::WeakPtr
<MediaRouterAction
> action_
;
103 DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogDelegate
);
106 void MediaRouterDialogDelegate::GetDialogSize(gfx::Size
* size
) const {
108 // TODO(apacible): Remove after autoresizing is implemented for OSX.
109 #if defined(OS_MACOSX)
110 *size
= gfx::Size(kWidth
, kMaxHeight
);
112 // size is not used because the dialog is auto-resizeable.
120 MediaRouterDialogControllerImpl
*
121 MediaRouterDialogControllerImpl::GetOrCreateForWebContents(
122 WebContents
* web_contents
) {
123 DCHECK(web_contents
);
124 // This call does nothing if the controller already exists.
125 MediaRouterDialogControllerImpl::CreateForWebContents(web_contents
);
126 return MediaRouterDialogControllerImpl::FromWebContents(web_contents
);
129 class MediaRouterDialogControllerImpl::DialogWebContentsObserver
130 : public content::WebContentsObserver
{
132 DialogWebContentsObserver(
133 WebContents
* web_contents
,
134 MediaRouterDialogControllerImpl
* dialog_controller
)
135 : content::WebContentsObserver(web_contents
),
136 dialog_controller_(dialog_controller
) {
140 void WebContentsDestroyed() override
{
141 // The dialog is already closed. No need to call Close() again.
142 // NOTE: |this| is deleted after Reset() returns.
143 dialog_controller_
->Reset();
146 void NavigationEntryCommitted(const LoadCommittedDetails
& load_details
)
148 dialog_controller_
->OnDialogNavigated(load_details
);
151 void RenderProcessGone(base::TerminationStatus status
) override
{
152 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns.
153 dialog_controller_
->CloseMediaRouterDialog();
156 MediaRouterDialogControllerImpl
* const dialog_controller_
;
159 MediaRouterDialogControllerImpl::MediaRouterDialogControllerImpl(
160 WebContents
* web_contents
)
161 : MediaRouterDialogController(web_contents
),
162 media_router_dialog_pending_(false) {
165 MediaRouterDialogControllerImpl::~MediaRouterDialogControllerImpl() {
168 WebContents
* MediaRouterDialogControllerImpl::GetMediaRouterDialog() const {
169 DCHECK(thread_checker_
.CalledOnValidThread());
170 return dialog_observer_
.get() ? dialog_observer_
->web_contents() : nullptr;
173 void MediaRouterDialogControllerImpl::SetMediaRouterAction(
174 const base::WeakPtr
<MediaRouterAction
>& action
) {
178 bool MediaRouterDialogControllerImpl::IsShowingMediaRouterDialog() const {
179 return GetMediaRouterDialog() != nullptr;
182 void MediaRouterDialogControllerImpl::CloseMediaRouterDialog() {
183 WebContents
* media_router_dialog
= GetMediaRouterDialog();
184 if (!media_router_dialog
)
187 content::WebUI
* web_ui
= media_router_dialog
->GetWebUI();
189 MediaRouterUI
* media_router_ui
=
190 static_cast<MediaRouterUI
*>(web_ui
->GetController());
192 media_router_ui
->Close();
195 // If there was no dialog to be closed, the action icon should not have been
196 // pressed and this would be a no-op.
198 action_
->OnPopupHidden();
201 void MediaRouterDialogControllerImpl::CreateMediaRouterDialog() {
202 DCHECK(!dialog_observer_
.get());
205 Profile::FromBrowserContext(initiator()->GetBrowserContext());
208 WebDialogDelegate
* web_dialog_delegate
=
209 new MediaRouterDialogDelegate(action_
);
210 // |web_dialog_delegate|'s owner is |constrained_delegate|.
211 // |constrained_delegate| is owned by the parent |views::View|.
212 // TODO(apacible): Remove after autoresizing is implemented for OSX.
213 #if defined(OS_MACOSX)
214 ConstrainedWebDialogDelegate
* constrained_delegate
=
215 ShowConstrainedWebDialog(profile
, web_dialog_delegate
, initiator());
217 // TODO(apacible): Adjust min and max sizes based on new WebUI design.
218 gfx::Size min_size
= gfx::Size(kWidth
, kMinHeight
);
219 gfx::Size max_size
= gfx::Size(kWidth
, kMaxHeight
);
221 // |ShowConstrainedWebDialogWithAutoResize()| will end up creating
222 // ConstrainedWebDialogDelegateViewViews containing a WebContents containing
223 // the MediaRouterUI, using the provided |web_dialog_delegate|. Then, the
224 // view is shown as a modal dialog constrained to the |initiator| WebContents.
225 // The dialog will resize between the |min_size| and |max_size| bounds based
226 // on the currently rendered contents.
227 ConstrainedWebDialogDelegate
* constrained_delegate
=
228 ShowConstrainedWebDialogWithAutoResize(
229 profile
, web_dialog_delegate
, initiator(), min_size
, max_size
);
232 WebContents
* media_router_dialog
= constrained_delegate
->GetWebContents();
234 media_router_dialog_pending_
= true;
236 dialog_observer_
.reset(new DialogWebContentsObserver(
237 media_router_dialog
, this));
240 action_
->OnPopupShown();
243 void MediaRouterDialogControllerImpl::Reset() {
244 MediaRouterDialogController::Reset();
245 dialog_observer_
.reset();
248 action_
->OnPopupHidden();
251 void MediaRouterDialogControllerImpl::OnDialogNavigated(
252 const content::LoadCommittedDetails
& details
) {
253 DCHECK(thread_checker_
.CalledOnValidThread());
254 WebContents
* media_router_dialog
= GetMediaRouterDialog();
255 CHECK(media_router_dialog
);
256 ui::PageTransition transition_type
= details
.entry
->GetTransitionType();
257 content::NavigationType nav_type
= details
.type
;
259 // New |media_router_dialog| is created.
260 DCHECK(media_router_dialog_pending_
);
261 DCHECK(transition_type
== ui::PAGE_TRANSITION_AUTO_TOPLEVEL
&&
262 nav_type
== content::NAVIGATION_TYPE_NEW_PAGE
)
263 << "transition_type: " << transition_type
<< ", "
264 << "nav_type: " << nav_type
;
266 media_router_dialog_pending_
= false;
268 PopulateDialog(media_router_dialog
);
271 void MediaRouterDialogControllerImpl::PopulateDialog(
272 content::WebContents
* media_router_dialog
) {
273 DCHECK(thread_checker_
.CalledOnValidThread());
274 DCHECK(media_router_dialog
);
275 if (!initiator() || !media_router_dialog
->GetWebUI()) {
280 MediaRouterUI
* media_router_ui
= static_cast<MediaRouterUI
*>(
281 media_router_dialog
->GetWebUI()->GetController());
282 DCHECK(media_router_ui
);
283 if (!media_router_ui
) {
288 scoped_ptr
<CreatePresentationSessionRequest
> presentation_request(
289 TakePresentationRequest());
290 // TODO(imcheng): Don't create PresentationServiceDelegateImpl if it doesn't
291 // exist (crbug.com/508695).
292 base::WeakPtr
<PresentationServiceDelegateImpl
> delegate
=
293 PresentationServiceDelegateImpl::GetOrCreateForWebContents(initiator())
295 if (!presentation_request
.get()) {
296 media_router_ui
->InitWithDefaultMediaSource(delegate
);
298 media_router_ui
->InitWithPresentationSessionRequest(
299 initiator(), delegate
, presentation_request
.Pass());
303 } // namespace media_router