Update frame around SAML IdP pages to new GAIA style
[chromium-blink-merge.git] / content / browser / presentation / presentation_service_impl.cc
blob2d6769e0f102397ace4313ab131c28f4e247d1b9
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 "content/browser/presentation/presentation_service_impl.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "content/browser/presentation/presentation_type_converters.h"
11 #include "content/public/browser/content_browser_client.h"
12 #include "content/public/browser/navigation_details.h"
13 #include "content/public/browser/render_frame_host.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/content_client.h"
17 #include "content/public/common/frame_navigate_params.h"
19 namespace content {
21 PresentationServiceImpl::PresentationServiceImpl(
22 RenderFrameHost* render_frame_host,
23 WebContents* web_contents,
24 PresentationServiceDelegate* delegate)
25 : WebContentsObserver(web_contents),
26 render_frame_host_(render_frame_host),
27 delegate_(delegate),
28 is_start_session_pending_(false),
29 next_request_session_id_(0),
30 weak_factory_(this) {
31 DCHECK(render_frame_host_);
32 DCHECK(web_contents);
33 DVLOG(2) << "PresentationServiceImpl: "
34 << render_frame_host_->GetProcess()->GetID() << ", "
35 << render_frame_host_->GetRoutingID();
36 if (delegate_)
37 delegate_->AddObserver(this);
40 PresentationServiceImpl::~PresentationServiceImpl() {
41 if (delegate_)
42 delegate_->RemoveObserver(this);
43 FlushNewSessionCallbacks();
46 // static
47 void PresentationServiceImpl::CreateMojoService(
48 RenderFrameHost* render_frame_host,
49 mojo::InterfaceRequest<presentation::PresentationService> request) {
50 DVLOG(2) << "CreateMojoService";
51 WebContents* web_contents =
52 WebContents::FromRenderFrameHost(render_frame_host);
53 DCHECK(web_contents);
55 // This object will be deleted when the RenderFrameHost is about to be
56 // deleted (RenderFrameDeleted) or if a connection error occurred
57 // (OnConnectionError).
58 PresentationServiceImpl* impl = new PresentationServiceImpl(
59 render_frame_host,
60 web_contents,
61 GetContentClient()->browser()->GetPresentationServiceDelegate(
62 web_contents));
63 impl->Bind(request.Pass());
66 void PresentationServiceImpl::Bind(
67 mojo::InterfaceRequest<presentation::PresentationService> request) {
68 binding_.reset(new mojo::Binding<presentation::PresentationService>(
69 this, request.Pass()));
70 binding_->set_error_handler(this);
73 void PresentationServiceImpl::OnConnectionError() {
74 DVLOG(1) << "OnConnectionError";
75 delete this;
78 PresentationServiceImpl::ScreenAvailabilityContext*
79 PresentationServiceImpl::GetOrCreateAvailabilityContext(
80 const std::string& presentation_url) {
81 auto it = availability_contexts_.find(presentation_url);
82 if (it == availability_contexts_.end()) {
83 linked_ptr<ScreenAvailabilityContext> context(
84 new ScreenAvailabilityContext(presentation_url));
85 if (!delegate_->AddScreenAvailabilityListener(
86 render_frame_host_->GetProcess()->GetID(),
87 render_frame_host_->GetRoutingID(),
88 context.get())) {
89 DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
90 return nullptr;
92 it = availability_contexts_.insert(
93 std::make_pair(context->GetPresentationUrl(), context)).first;
95 return it->second.get();
98 void PresentationServiceImpl::ListenForScreenAvailability(
99 const mojo::String& presentation_url,
100 const ScreenAvailabilityMojoCallback& callback) {
101 DVLOG(2) << "ListenForScreenAvailability";
102 if (!delegate_) {
103 callback.Run(presentation_url, false);
104 return;
107 ScreenAvailabilityContext* context =
108 GetOrCreateAvailabilityContext(presentation_url.get());
109 if (!context) {
110 callback.Run(presentation_url, false);
111 return;
113 context->CallbackReceived(callback);
116 void PresentationServiceImpl::RemoveScreenAvailabilityListener(
117 const mojo::String& presentation_url) {
118 DVLOG(2) << "RemoveScreenAvailabilityListener";
119 if (!delegate_)
120 return;
122 const std::string& presentation_url_str = presentation_url.get();
123 auto it = availability_contexts_.find(presentation_url_str);
124 if (it == availability_contexts_.end())
125 return;
127 delegate_->RemoveScreenAvailabilityListener(
128 render_frame_host_->GetProcess()->GetID(),
129 render_frame_host_->GetRoutingID(),
130 it->second.get());
131 // Resolve the context's pending callbacks before removing it.
132 it->second->OnScreenAvailabilityChanged(false);
133 availability_contexts_.erase(it);
136 void PresentationServiceImpl::ListenForDefaultSessionStart(
137 const DefaultSessionMojoCallback& callback) {
138 NOTIMPLEMENTED();
141 void PresentationServiceImpl::StartSession(
142 const mojo::String& presentation_url,
143 const mojo::String& presentation_id,
144 const NewSessionMojoCallback& callback) {
145 DVLOG(2) << "StartSession";
146 if (!delegate_) {
147 InvokeNewSessionMojoCallbackWithError(callback);
148 return;
151 if (is_start_session_pending_) {
152 queued_start_session_requests_.push_back(make_linked_ptr(
153 new StartSessionRequest(presentation_url, presentation_id, callback)));
154 return;
157 DoStartSession(presentation_url, presentation_id, callback);
160 void PresentationServiceImpl::JoinSession(
161 const mojo::String& presentation_url,
162 const mojo::String& presentation_id,
163 const NewSessionMojoCallback& callback) {
164 DVLOG(2) << "JoinSession";
165 if (!delegate_) {
166 InvokeNewSessionMojoCallbackWithError(callback);
167 return;
170 int request_session_id = RegisterNewSessionCallback(callback);
171 delegate_->JoinSession(
172 render_frame_host_->GetProcess()->GetID(),
173 render_frame_host_->GetRoutingID(),
174 presentation_url,
175 presentation_id,
176 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
177 weak_factory_.GetWeakPtr(), false, request_session_id),
178 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
179 weak_factory_.GetWeakPtr(), false, request_session_id));
182 void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
183 if (queued_start_session_requests_.empty()) {
184 is_start_session_pending_ = false;
185 return;
187 linked_ptr<StartSessionRequest> request =
188 queued_start_session_requests_.front();
189 queued_start_session_requests_.pop_front();
190 DoStartSession(request->presentation_url(),
191 request->presentation_id(),
192 request->PassCallback());
195 int PresentationServiceImpl::RegisterNewSessionCallback(
196 const NewSessionMojoCallback& callback) {
197 ++next_request_session_id_;
198 pending_session_cbs_[next_request_session_id_].reset(
199 new NewSessionMojoCallback(callback));
200 return next_request_session_id_;
203 void PresentationServiceImpl::FlushNewSessionCallbacks() {
204 for (auto& pending_entry : pending_session_cbs_) {
205 InvokeNewSessionMojoCallbackWithError(*pending_entry.second);
207 pending_session_cbs_.clear();
210 void PresentationServiceImpl::DoStartSession(
211 const std::string& presentation_url,
212 const std::string& presentation_id,
213 const NewSessionMojoCallback& callback) {
214 int request_session_id = RegisterNewSessionCallback(callback);
215 is_start_session_pending_ = true;
216 delegate_->StartSession(
217 render_frame_host_->GetProcess()->GetID(),
218 render_frame_host_->GetRoutingID(),
219 presentation_url,
220 presentation_id,
221 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
222 weak_factory_.GetWeakPtr(), true, request_session_id),
223 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
224 weak_factory_.GetWeakPtr(), true, request_session_id));
227 void PresentationServiceImpl::OnStartOrJoinSessionSucceeded(
228 bool is_start_session,
229 int request_session_id,
230 const PresentationSessionInfo& session_info) {
231 RunAndEraseNewSessionMojoCallback(
232 request_session_id,
233 presentation::PresentationSessionInfo::From(session_info),
234 presentation::PresentationErrorPtr());
235 if (is_start_session)
236 HandleQueuedStartSessionRequests();
239 void PresentationServiceImpl::OnStartOrJoinSessionError(
240 bool is_start_session,
241 int request_session_id,
242 const PresentationError& error) {
243 RunAndEraseNewSessionMojoCallback(
244 request_session_id,
245 presentation::PresentationSessionInfoPtr(),
246 presentation::PresentationError::From(error));
247 if (is_start_session)
248 HandleQueuedStartSessionRequests();
251 void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback(
252 int request_session_id,
253 presentation::PresentationSessionInfoPtr session,
254 presentation::PresentationErrorPtr error) {
255 auto it = pending_session_cbs_.find(request_session_id);
256 if (it == pending_session_cbs_.end())
257 return;
259 DCHECK(it->second.get());
260 it->second->Run(session.Pass(), error.Pass());
261 pending_session_cbs_.erase(it);
264 void PresentationServiceImpl::DoSetDefaultPresentationUrl(
265 const std::string& default_presentation_url,
266 const std::string& default_presentation_id) {
267 DCHECK(delegate_);
268 delegate_->SetDefaultPresentationUrl(
269 render_frame_host_->GetProcess()->GetID(),
270 render_frame_host_->GetRoutingID(),
271 default_presentation_url,
272 default_presentation_id);
273 default_presentation_url_ = default_presentation_url;
274 default_presentation_id_ = default_presentation_id;
277 void PresentationServiceImpl::SetDefaultPresentationURL(
278 const mojo::String& default_presentation_url,
279 const mojo::String& default_presentation_id) {
280 DVLOG(2) << "SetDefaultPresentationURL";
281 if (!delegate_)
282 return;
284 const std::string& old_default_url = default_presentation_url_;
285 const std::string& new_default_url = default_presentation_url.get();
287 // Don't call delegate if nothing changed.
288 if (old_default_url == new_default_url &&
289 default_presentation_id_ == default_presentation_id) {
290 return;
293 auto old_it = availability_contexts_.find(old_default_url);
294 // Haven't started listening yet.
295 if (old_it == availability_contexts_.end()) {
296 DoSetDefaultPresentationUrl(new_default_url, default_presentation_id);
297 return;
300 // Have already started listening. Create a listener for the new URL and
301 // transfer the callbacks from the old listener, if any.
302 // This is done so that a listener added before default URL is changed
303 // will continue to work.
304 ScreenAvailabilityContext* context =
305 GetOrCreateAvailabilityContext(new_default_url);
306 old_it->second->PassPendingCallbacks(context);
308 // Remove listener for old default presentation URL.
309 delegate_->RemoveScreenAvailabilityListener(
310 render_frame_host_->GetProcess()->GetID(),
311 render_frame_host_->GetRoutingID(),
312 old_it->second.get());
313 availability_contexts_.erase(old_it);
314 DoSetDefaultPresentationUrl(new_default_url, default_presentation_id);
317 void PresentationServiceImpl::CloseSession(
318 const mojo::String& presentation_url,
319 const mojo::String& presentation_id) {
320 NOTIMPLEMENTED();
323 void PresentationServiceImpl::ListenForSessionStateChange(
324 const SessionStateCallback& callback) {
325 NOTIMPLEMENTED();
328 void PresentationServiceImpl::DidNavigateAnyFrame(
329 content::RenderFrameHost* render_frame_host,
330 const content::LoadCommittedDetails& details,
331 const content::FrameNavigateParams& params) {
332 DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame";
333 if (render_frame_host_ != render_frame_host)
334 return;
336 std::string prev_url_host = details.previous_url.host();
337 std::string curr_url_host = params.url.host();
339 // If a frame navigation is in-page (e.g. navigating to a fragment in
340 // same page) then we do not unregister listeners.
341 bool in_page_navigation = details.is_in_page ||
342 details.type == content::NAVIGATION_TYPE_IN_PAGE;
344 DVLOG(2) << "DidNavigateAnyFrame: "
345 << "prev host: " << prev_url_host << ", curr host: " << curr_url_host
346 << ", in_page_navigation: " << in_page_navigation;
348 if (in_page_navigation)
349 return;
351 // Reset if the frame actually navigated.
352 Reset();
355 void PresentationServiceImpl::RenderFrameDeleted(
356 content::RenderFrameHost* render_frame_host) {
357 DVLOG(2) << "PresentationServiceImpl::RenderFrameDeleted";
358 if (render_frame_host_ != render_frame_host)
359 return;
361 // RenderFrameDeleted means |render_frame_host_| is going to be deleted soon.
362 // This object should also be deleted.
363 Reset();
364 render_frame_host_ = nullptr;
365 delete this;
368 void PresentationServiceImpl::Reset() {
369 DVLOG(2) << "PresentationServiceImpl::Reset";
370 if (delegate_) {
371 delegate_->Reset(
372 render_frame_host_->GetProcess()->GetID(),
373 render_frame_host_->GetRoutingID());
376 default_presentation_url_.clear();
377 default_presentation_id_.clear();
378 availability_contexts_.clear();
379 queued_start_session_requests_.clear();
380 FlushNewSessionCallbacks();
383 // static
384 void PresentationServiceImpl::InvokeNewSessionMojoCallbackWithError(
385 const NewSessionMojoCallback& callback) {
386 callback.Run(
387 presentation::PresentationSessionInfoPtr(),
388 presentation::PresentationError::From(
389 PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
392 void PresentationServiceImpl::OnDelegateDestroyed() {
393 DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed";
394 delegate_ = nullptr;
395 Reset();
398 PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext(
399 const std::string& presentation_url)
400 : presentation_url_(presentation_url) {
403 PresentationServiceImpl::ScreenAvailabilityContext::
404 ~ScreenAvailabilityContext() {
405 // Ensure that pending callbacks are flushed.
406 OnScreenAvailabilityChanged(false);
409 void PresentationServiceImpl::ScreenAvailabilityContext::CallbackReceived(
410 const ScreenAvailabilityMojoCallback& callback) {
411 // NOTE: This will overwrite previously registered callback if any.
412 if (!available_ptr_) {
413 // No results yet, store callback for later invocation.
414 callbacks_.push_back(new ScreenAvailabilityMojoCallback(callback));
415 } else {
416 // Run callback now, reset result.
417 // There shouldn't be any callbacks stored in this scenario.
418 DCHECK(!HasPendingCallbacks());
419 callback.Run(presentation_url_, *available_ptr_);
420 available_ptr_.reset();
424 std::string PresentationServiceImpl::ScreenAvailabilityContext
425 ::GetPresentationUrl() const {
426 return presentation_url_;
429 void PresentationServiceImpl::ScreenAvailabilityContext
430 ::OnScreenAvailabilityChanged(bool available) {
431 if (!HasPendingCallbacks()) {
432 // No callback, stash the result for now.
433 available_ptr_.reset(new bool(available));
434 } else {
435 // Invoke callbacks and erase them.
436 // There shouldn't be any result stored in this scenario.
437 DCHECK(!available_ptr_);
438 ScopedVector<ScreenAvailabilityMojoCallback> callbacks;
439 callbacks.swap(callbacks_);
440 for (const auto& callback : callbacks)
441 callback->Run(presentation_url_, available);
445 void PresentationServiceImpl::ScreenAvailabilityContext
446 ::PassPendingCallbacks(
447 PresentationServiceImpl::ScreenAvailabilityContext* other) {
448 std::vector<ScreenAvailabilityMojoCallback*> callbacks;
449 callbacks_.release(&callbacks);
450 std::copy(callbacks.begin(), callbacks.end(),
451 std::back_inserter(other->callbacks_));
454 bool PresentationServiceImpl::ScreenAvailabilityContext
455 ::HasPendingCallbacks() const {
456 return !callbacks_.empty();
459 PresentationServiceImpl::StartSessionRequest::StartSessionRequest(
460 const std::string& presentation_url,
461 const std::string& presentation_id,
462 const NewSessionMojoCallback& callback)
463 : presentation_url_(presentation_url),
464 presentation_id_(presentation_id),
465 callback_(callback) {
468 PresentationServiceImpl::StartSessionRequest::~StartSessionRequest() {
469 // Ensure that a pending callback is not dropped.
470 if (!callback_.is_null())
471 InvokeNewSessionMojoCallbackWithError(callback_);
474 PresentationServiceImpl::NewSessionMojoCallback
475 PresentationServiceImpl::StartSessionRequest::PassCallback() {
476 NewSessionMojoCallback callback = callback_;
477 callback_.reset();
478 return callback;
481 } // namespace content