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.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
12 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
13 #include "chrome/common/url_constants.h"
14 #include "components/web_modal/web_contents_modal_dialog_host.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_details.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/render_frame_host.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_delegate.h"
24 #include "ui/web_dialogs/web_dialog_delegate.h"
25 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
28 DEFINE_WEB_CONTENTS_USER_DATA_KEY(media_router::MediaRouterDialogController
);
30 using content::LoadCommittedDetails
;
31 using content::NavigationController
;
32 using content::WebContents
;
33 using content::WebUIMessageHandler
;
34 using ui::WebDialogDelegate
;
36 namespace media_router
{
40 // WebDialogDelegate that specifies what the media router dialog
42 class MediaRouterDialogDelegate
: public WebDialogDelegate
{
44 MediaRouterDialogDelegate() {}
45 ~MediaRouterDialogDelegate() override
{}
47 // WebDialogDelegate implementation.
48 ui::ModalType
GetDialogModalType() const override
{
49 // Not used, returning dummy value.
50 return ui::MODAL_TYPE_WINDOW
;
53 base::string16
GetDialogTitle() const override
{
54 return base::string16();
57 GURL
GetDialogContentURL() const override
{
58 return GURL(chrome::kChromeUIMediaRouterURL
);
61 void GetWebUIMessageHandlers(
62 std::vector
<WebUIMessageHandler
*>* handlers
) const override
{
63 // MediaRouterUI adds its own message handlers.
66 void GetDialogSize(gfx::Size
* size
) const override
;
68 std::string
GetDialogArgs() const override
{
72 void OnDialogClosed(const std::string
& json_retval
) override
{
73 // We don't delete |this| here because this class is owned
74 // by ConstrainedWebDialogDelegate.
77 void OnCloseContents(WebContents
* source
, bool* out_close_dialog
) override
{
79 *out_close_dialog
= true;
82 bool ShouldShowDialogTitle() const override
{
87 DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogDelegate
);
90 void MediaRouterDialogDelegate::GetDialogSize(gfx::Size
* size
) const {
92 // TODO(apacible): Remove after autoresizing is implemented for OSX.
93 #if defined(OS_MACOSX)
94 *size
= gfx::Size(330, 400);
96 // size is not used because the dialog is auto-resizeable.
103 class MediaRouterDialogController::DialogWebContentsObserver
104 : public content::WebContentsObserver
{
106 DialogWebContentsObserver(
107 WebContents
* web_contents
,
108 MediaRouterDialogController
* dialog_controller
)
109 : content::WebContentsObserver(web_contents
),
110 dialog_controller_(dialog_controller
) {
114 void WebContentsDestroyed() override
{
115 // The dialog is already closed. No need to call Close() again.
116 // NOTE: |this| is deleted after RemoveObservers() returns.
117 dialog_controller_
->RemoveObservers();
120 void NavigationEntryCommitted(const LoadCommittedDetails
& load_details
)
122 dialog_controller_
->OnDialogNavigated(load_details
);
125 void RenderProcessGone(base::TerminationStatus status
) override
{
126 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns.
127 dialog_controller_
->CloseMediaRouterDialog();
130 MediaRouterDialogController
* const dialog_controller_
;
133 class MediaRouterDialogController::InitiatorWebContentsObserver
134 : public content::WebContentsObserver
{
136 InitiatorWebContentsObserver(
137 WebContents
* web_contents
,
138 MediaRouterDialogController
* dialog_controller
)
139 : content::WebContentsObserver(web_contents
),
140 dialog_controller_(dialog_controller
) {
144 void WebContentsDestroyed() override
{
145 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns.
146 dialog_controller_
->CloseMediaRouterDialog();
149 void NavigationEntryCommitted(const LoadCommittedDetails
& load_details
)
151 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns.
152 dialog_controller_
->CloseMediaRouterDialog();
155 void RenderProcessGone(base::TerminationStatus status
) override
{
156 // NOTE: |this| is deleted after CloseMediaRouterDialog() returns.
157 dialog_controller_
->CloseMediaRouterDialog();
160 MediaRouterDialogController
* const dialog_controller_
;
163 MediaRouterDialogController::MediaRouterDialogController(
164 WebContents
* web_contents
)
165 : initiator_(web_contents
),
166 media_router_dialog_pending_(false) {
168 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
171 MediaRouterDialogController::~MediaRouterDialogController() {
172 DCHECK(thread_checker_
.CalledOnValidThread());
175 WebContents
* MediaRouterDialogController::ShowMediaRouterDialog() {
176 DCHECK(thread_checker_
.CalledOnValidThread());
178 // Get the media router dialog for |initiator|, or create a new dialog
180 WebContents
* media_router_dialog
= GetMediaRouterDialog();
181 if (!media_router_dialog
)
182 return CreateMediaRouterDialog();
184 // Show the initiator holding the existing media router dialog.
185 initiator_
->GetDelegate()->ActivateContents(initiator_
);
186 return media_router_dialog
;
189 WebContents
* MediaRouterDialogController::GetMediaRouterDialog() const {
190 DCHECK(thread_checker_
.CalledOnValidThread());
191 return dialog_observer_
.get() ? dialog_observer_
->web_contents() : nullptr;
194 void MediaRouterDialogController::CloseMediaRouterDialog() {
195 DCHECK(thread_checker_
.CalledOnValidThread());
196 DCHECK(initiator_observer_
.get());
197 WebContents
* media_router_dialog
= GetMediaRouterDialog();
198 CHECK(media_router_dialog
);
201 content::WebUI
* web_ui
= media_router_dialog
->GetWebUI();
203 MediaRouterUI
* media_router_ui
=
204 static_cast<MediaRouterUI
*>(web_ui
->GetController());
206 media_router_ui
->Close();
210 WebContents
* MediaRouterDialogController::CreateMediaRouterDialog() {
211 DCHECK(!initiator_observer_
.get());
212 DCHECK(!dialog_observer_
.get());
215 Profile::FromBrowserContext(initiator_
->GetBrowserContext());
218 WebDialogDelegate
* web_dialog_delegate
= new MediaRouterDialogDelegate
;
220 // |web_dialog_delegate|'s owner is |constrained_delegate|.
221 // |constrained_delegate| is owned by the parent |views::View|.
222 // TODO(apacible): Remove after autoresizing is implemented for OSX.
223 #if defined(OS_MACOSX)
224 ConstrainedWebDialogDelegate
* constrained_delegate
=
225 ShowConstrainedWebDialog(profile
, web_dialog_delegate
, initiator_
);
227 // TODO(apacible): Adjust min and max sizes based on new WebUI design.
228 gfx::Size min_size
= gfx::Size(330, 1);
229 gfx::Size max_size
= gfx::Size(500, 500);
230 // |ShowConstrainedWebDialogWithAutoResize()| will end up creating
231 // ConstrainedWebDialogDelegateViewViews containing a WebContents containing
232 // the MediaRouterUI, using the provided |web_dialog_delegate|. Then, the
233 // view is shown as a modal dialog constrained to the |initiator| WebContents.
234 // The dialog will resize between the |min_size| and |max_size| bounds based
235 // on the currently rendered contents.
236 ConstrainedWebDialogDelegate
* constrained_delegate
=
237 ShowConstrainedWebDialogWithAutoResize(
238 profile
, web_dialog_delegate
, initiator_
, min_size
, max_size
);
241 WebContents
* media_router_dialog
= constrained_delegate
->GetWebContents();
243 media_router_dialog_pending_
= true;
245 initiator_observer_
.reset(new InitiatorWebContentsObserver(
247 dialog_observer_
.reset(new DialogWebContentsObserver(
248 media_router_dialog
, this));
249 return media_router_dialog
;
252 void MediaRouterDialogController::RemoveObservers() {
253 DCHECK(thread_checker_
.CalledOnValidThread());
254 DCHECK(initiator_observer_
.get());
255 DCHECK(dialog_observer_
.get());
256 initiator_observer_
.reset();
257 dialog_observer_
.reset();
260 void MediaRouterDialogController::OnDialogNavigated(
261 const content::LoadCommittedDetails
& details
) {
262 DCHECK(thread_checker_
.CalledOnValidThread());
263 WebContents
* media_router_dialog
= GetMediaRouterDialog();
264 CHECK(media_router_dialog
);
265 ui::PageTransition transition_type
= details
.entry
->GetTransitionType();
266 content::NavigationType nav_type
= details
.type
;
268 // New |media_router_dialog| is created.
269 DCHECK(media_router_dialog_pending_
);
270 DCHECK(transition_type
== ui::PAGE_TRANSITION_AUTO_TOPLEVEL
&&
271 nav_type
== content::NAVIGATION_TYPE_NEW_PAGE
)
272 << "transition_type: " << transition_type
<< ", "
273 << "nav_type: " << nav_type
;
275 media_router_dialog_pending_
= false;
277 // TODO(imcheng): Initialize dialog.
280 } // namespace media_router