| 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 |