Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: content/renderer/presentation/presentation_dispatcher.cc

Issue 2598063002: [Presentation API] Handle multiple Presentation URLs in PresentationRequest::getAvailability() (Closed)
Patch Set: resolve code review comments from Derek Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/presentation/presentation_dispatcher.h" 5 #include "content/renderer/presentation/presentation_dispatcher.h"
6 6
7 #include <string> 7 #include <string>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 return blink::WebPresentationConnectionCloseReason::Error; 85 return blink::WebPresentationConnectionCloseReason::Error;
86 case blink::mojom::PresentationConnectionCloseReason::CLOSED: 86 case blink::mojom::PresentationConnectionCloseReason::CLOSED:
87 return blink::WebPresentationConnectionCloseReason::Closed; 87 return blink::WebPresentationConnectionCloseReason::Closed;
88 case blink::mojom::PresentationConnectionCloseReason::WENT_AWAY: 88 case blink::mojom::PresentationConnectionCloseReason::WENT_AWAY:
89 return blink::WebPresentationConnectionCloseReason::WentAway; 89 return blink::WebPresentationConnectionCloseReason::WentAway;
90 default: 90 default:
91 NOTREACHED(); 91 NOTREACHED();
92 return blink::WebPresentationConnectionCloseReason::Error; 92 return blink::WebPresentationConnectionCloseReason::Error;
93 } 93 }
94 } 94 }
95
96 } // namespace 95 } // namespace
97 96
98 namespace content { 97 namespace content {
99 98
100 PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame) 99 PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame)
101 : RenderFrameObserver(render_frame), 100 : RenderFrameObserver(render_frame),
102 controller_(nullptr), 101 controller_(nullptr),
103 binding_(this) { 102 binding_(this) {
104 } 103 }
105 104
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 254
256 void PresentationDispatcher::terminateSession( 255 void PresentationDispatcher::terminateSession(
257 const blink::WebURL& presentationUrl, 256 const blink::WebURL& presentationUrl,
258 const blink::WebString& presentationId) { 257 const blink::WebString& presentationId) {
259 ConnectToPresentationServiceIfNeeded(); 258 ConnectToPresentationServiceIfNeeded();
260 presentation_service_->Terminate(presentationUrl, presentationId.utf8()); 259 presentation_service_->Terminate(presentationUrl, presentationId.utf8());
261 } 260 }
262 261
263 void PresentationDispatcher::getAvailability( 262 void PresentationDispatcher::getAvailability(
264 const blink::WebVector<blink::WebURL>& availabilityUrls, 263 const blink::WebVector<blink::WebURL>& availabilityUrls,
265 std::unique_ptr<blink::WebPresentationAvailabilityCallbacks> callbacks) { 264 std::unique_ptr<blink::WebPresentationAvailabilityCallbacks> callback) {
266 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 265 DCHECK(!availabilityUrls.isEmpty());
267 const blink::WebURL& availabilityUrl = availabilityUrls[0]; 266
268 AvailabilityStatus* status = nullptr; 267 std::vector<GURL> urls;
269 auto status_it = availability_status_.find(availabilityUrl); 268 for (const auto& availability_url : availabilityUrls)
270 if (status_it == availability_status_.end()) { 269 urls.push_back(availability_url);
271 status = new AvailabilityStatus(availabilityUrl); 270
272 availability_status_[availabilityUrl] = base::WrapUnique(status); 271 auto screen_availability = GetScreenAvailability(urls);
273 } else { 272 // Reject Promise if screen availability is unsupported for all URLs.
274 status = status_it->second.get(); 273 if (screen_availability == ScreenAvailability::UNSUPPORTED) {
274 base::ThreadTaskRunnerHandle::Get()->PostTask(
275 FROM_HERE,
276 base::Bind(
277 &blink::WebPresentationAvailabilityCallbacks::onError,
278 base::Passed(&callback),
279 blink::WebPresentationError(
280 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
281 "Screen availability monitoring not supported")));
282 // Do not listen to urls if we reject the promise.
283 return;
275 } 284 }
276 DCHECK(status);
277 285
278 if (status->listening_state == ListeningState::ACTIVE) { 286 auto* listener = GetAvailabilityListener(urls);
287 if (!listener) {
288 listener = new AvailabilityListener(urls);
289 availability_set_.insert(base::WrapUnique(listener));
290 }
291
292 if (screen_availability != ScreenAvailability::UNKNOWN) {
279 base::ThreadTaskRunnerHandle::Get()->PostTask( 293 base::ThreadTaskRunnerHandle::Get()->PostTask(
280 FROM_HERE, 294 FROM_HERE,
281 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess, 295 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess,
282 base::Passed(&callbacks), status->last_known_availability)); 296 base::Passed(&callback),
283 return; 297 screen_availability == ScreenAvailability::AVAILABLE));
298 } else {
299 listener->availability_callbacks.Add(std::move(callback));
284 } 300 }
285 301
286 status->availability_callbacks.Add(std::move(callbacks)); 302 for (const auto& availabilityUrl : urls)
287 UpdateListeningState(status); 303 StartListeningToURL(availabilityUrl);
288 } 304 }
289 305
290 void PresentationDispatcher::startListening( 306 void PresentationDispatcher::startListening(
291 blink::WebPresentationAvailabilityObserver* observer) { 307 blink::WebPresentationAvailabilityObserver* observer) {
292 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 308 std::vector<GURL> urls;
293 const blink::WebURL& availabilityUrl = observer->urls()[0]; 309 for (const auto& url : observer->urls())
294 auto status_it = availability_status_.find(availabilityUrl); 310 urls.push_back(url);
295 if (status_it == availability_status_.end()) { 311
296 DLOG(WARNING) << "Start listening for availability for unknown URL " 312 auto* listener = GetAvailabilityListener(urls);
297 << GURL(availabilityUrl); 313 if (!listener) {
298 return; 314 listener = new AvailabilityListener(urls);
315 availability_set_.insert(base::WrapUnique(listener));
299 } 316 }
300 status_it->second->availability_observers.insert(observer); 317
301 UpdateListeningState(status_it->second.get()); 318 listener->availability_observers.insert(observer);
319 for (const auto& availabilityUrl : urls)
320 StartListeningToURL(availabilityUrl);
302 } 321 }
303 322
304 void PresentationDispatcher::stopListening( 323 void PresentationDispatcher::stopListening(
305 blink::WebPresentationAvailabilityObserver* observer) { 324 blink::WebPresentationAvailabilityObserver* observer) {
306 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 325 std::vector<GURL> urls;
307 const blink::WebURL& availabilityUrl = observer->urls()[0]; 326 for (const auto& url : observer->urls())
308 auto status_it = availability_status_.find(availabilityUrl); 327 urls.push_back(url);
309 if (status_it == availability_status_.end()) { 328
310 DLOG(WARNING) << "Stop listening for availability for unknown URL " 329 auto* listener = GetAvailabilityListener(urls);
311 << GURL(availabilityUrl); 330 if (!listener) {
331 DLOG(WARNING) << "Stop listening for availability for unknown URLs.";
312 return; 332 return;
313 } 333 }
314 status_it->second->availability_observers.erase(observer); 334
315 UpdateListeningState(status_it->second.get()); 335 listener->availability_observers.erase(observer);
336 for (const auto& availabilityUrl : urls)
337 StopListeningToURL(availabilityUrl);
338
339 TryRemoveAvailabilityListener(listener);
316 } 340 }
317 341
318 void PresentationDispatcher::setDefaultPresentationUrls( 342 void PresentationDispatcher::setDefaultPresentationUrls(
319 const blink::WebVector<blink::WebURL>& presentationUrls) { 343 const blink::WebVector<blink::WebURL>& presentationUrls) {
320 ConnectToPresentationServiceIfNeeded(); 344 ConnectToPresentationServiceIfNeeded();
321 345
322 std::vector<GURL> urls; 346 std::vector<GURL> urls;
323 for (const auto& url : presentationUrls) 347 for (const auto& url : presentationUrls)
324 urls.push_back(url); 348 urls.push_back(url);
325 349
(...skipping 18 matching lines...) Expand all
344 MessageRequestQueue empty; 368 MessageRequestQueue empty;
345 std::swap(message_request_queue_, empty); 369 std::swap(message_request_queue_, empty);
346 } 370 }
347 371
348 void PresentationDispatcher::OnDestruct() { 372 void PresentationDispatcher::OnDestruct() {
349 delete this; 373 delete this;
350 } 374 }
351 375
352 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url, 376 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url,
353 bool available) { 377 bool available) {
354 auto status_it = availability_status_.find(url); 378 auto* listening_status = GetListeningStatus(url);
355 if (status_it == availability_status_.end()) 379 if (!listening_status)
356 return; 380 return;
357 AvailabilityStatus* status = status_it->second.get();
358 DCHECK(status);
359 381
360 if (status->listening_state == ListeningState::WAITING) 382 if (listening_status->listening_state == ListeningState::WAITING)
361 status->listening_state = ListeningState::ACTIVE; 383 listening_status->listening_state = ListeningState::ACTIVE;
362 384
363 for (auto* observer : status->availability_observers) 385 auto new_screen_availability = available ? ScreenAvailability::AVAILABLE
364 observer->availabilityChanged(available); 386 : ScreenAvailability::UNAVAILABLE;
387 if (listening_status->last_known_availability == new_screen_availability)
388 return;
365 389
366 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 390 listening_status->last_known_availability = new_screen_availability;
367 !iter.IsAtEnd(); iter.Advance()) { 391
368 iter.GetCurrentValue()->onSuccess(available); 392 std::set<AvailabilityListener*> modified_listeners;
393 for (auto& listener : availability_set_) {
394 if (!base::ContainsValue(listener->urls, url))
395 continue;
396
397 auto screen_availability = GetScreenAvailability(listener->urls);
398 DCHECK(screen_availability == ScreenAvailability::AVAILABLE ||
399 screen_availability == ScreenAvailability::UNAVAILABLE);
400 bool is_available = (screen_availability == ScreenAvailability::AVAILABLE);
401
402 for (auto* observer : listener->availability_observers)
403 observer->availabilityChanged(is_available);
404
405 for (AvailabilityCallbacksMap::iterator iter(
406 &listener->availability_callbacks);
407 !iter.IsAtEnd(); iter.Advance()) {
408 iter.GetCurrentValue()->onSuccess(is_available);
409 }
410 listener->availability_callbacks.Clear();
411
412 for (const auto& availabilityUrl : listener->urls)
413 StopListeningToURL(availabilityUrl);
414
415 modified_listeners.insert(listener.get());
369 } 416 }
370 status->last_known_availability = available; 417
371 status->availability_callbacks.Clear(); 418 for (auto* listener : modified_listeners)
372 UpdateListeningState(status); 419 TryRemoveAvailabilityListener(listener);
373 } 420 }
374 421
375 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) { 422 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) {
376 auto status_it = availability_status_.find(url); 423 auto* listening_status = GetListeningStatus(url);
377 if (status_it == availability_status_.end()) 424 if (!listening_status)
378 return; 425 return;
379 AvailabilityStatus* status = status_it->second.get(); 426
380 DCHECK(status); 427 if (listening_status->listening_state == ListeningState::WAITING)
381 DCHECK(status->listening_state == ListeningState::WAITING); 428 listening_status->listening_state = ListeningState::ACTIVE;
429
430 if (listening_status->last_known_availability ==
431 ScreenAvailability::UNSUPPORTED) {
432 return;
433 }
434
435 listening_status->last_known_availability = ScreenAvailability::UNSUPPORTED;
382 436
383 const blink::WebString& not_supported_error = blink::WebString::fromUTF8( 437 const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
384 "getAvailability() isn't supported at the moment. It can be due to " 438 "getAvailability() isn't supported at the moment. It can be due to "
385 "a permanent or temporary system limitation. It is recommended to " 439 "a permanent or temporary system limitation. It is recommended to "
386 "try to blindly start a session in that case."); 440 "try to blindly start a session in that case.");
387 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 441
388 !iter.IsAtEnd(); iter.Advance()) { 442 std::set<AvailabilityListener*> modified_listeners;
389 iter.GetCurrentValue()->onError(blink::WebPresentationError( 443 for (auto& listener : availability_set_) {
390 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported, 444 if (!base::ContainsValue(listener->urls, url))
391 not_supported_error)); 445 continue;
446
447 // ScreenAvailabilityNotSupported should be a browser side setting, which
448 // means all urls in PresentationAvailability should report NotSupported.
449 // It is not possible to change listening status from Available or
450 // Unavailable to NotSupported. No need to update observer.
451 auto screen_availability = GetScreenAvailability(listener->urls);
452 DCHECK_EQ(screen_availability, ScreenAvailability::UNSUPPORTED);
453
454 for (AvailabilityCallbacksMap::iterator iter(
455 &listener->availability_callbacks);
456 !iter.IsAtEnd(); iter.Advance()) {
457 iter.GetCurrentValue()->onError(blink::WebPresentationError(
458 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
459 not_supported_error));
460 }
461 listener->availability_callbacks.Clear();
462
463 for (const auto& availability_url : listener->urls)
464 StopListeningToURL(availability_url);
465
466 modified_listeners.insert(listener.get());
392 } 467 }
393 status->availability_callbacks.Clear(); 468
394 UpdateListeningState(status); 469 for (auto* listener : modified_listeners)
470 TryRemoveAvailabilityListener(listener);
395 } 471 }
396 472
397 void PresentationDispatcher::OnDefaultSessionStarted( 473 void PresentationDispatcher::OnDefaultSessionStarted(
398 blink::mojom::PresentationSessionInfoPtr session_info) { 474 blink::mojom::PresentationSessionInfoPtr session_info) {
399 if (!controller_) 475 if (!controller_)
400 return; 476 return;
401 477
402 if (!session_info.is_null()) { 478 if (!session_info.is_null()) {
403 presentation_service_->ListenForConnectionMessages(session_info.Clone()); 479 presentation_service_->ListenForConnectionMessages(session_info.Clone());
404 controller_->didStartDefaultSession( 480 controller_->didStartDefaultSession(
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 } 570 }
495 571
496 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { 572 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
497 if (presentation_service_.get()) 573 if (presentation_service_.get())
498 return; 574 return;
499 575
500 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_); 576 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_);
501 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind()); 577 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind());
502 } 578 }
503 579
504 void PresentationDispatcher::UpdateListeningState(AvailabilityStatus* status) { 580 void PresentationDispatcher::StartListeningToURL(const GURL& url) {
505 bool should_listen = !status->availability_callbacks.IsEmpty() || 581 auto* listening_status = GetListeningStatus(url);
506 !status->availability_observers.empty(); 582 if (!listening_status) {
507 bool is_listening = status->listening_state != ListeningState::INACTIVE; 583 listening_status = new ListeningStatus(url);
584 listening_status_.insert(
585 std::make_pair(url, base::WrapUnique(listening_status)));
586 }
508 587
509 if (should_listen == is_listening) 588 // Already listening.
589 if (listening_status->listening_state != ListeningState::INACTIVE)
510 return; 590 return;
511 591
512 ConnectToPresentationServiceIfNeeded(); 592 ConnectToPresentationServiceIfNeeded();
513 if (should_listen) { 593 listening_status->listening_state = ListeningState::WAITING;
514 status->listening_state = ListeningState::WAITING; 594 presentation_service_->ListenForScreenAvailability(url);
515 presentation_service_->ListenForScreenAvailability(status->url); 595 }
516 } else { 596
517 status->listening_state = ListeningState::INACTIVE; 597 void PresentationDispatcher::StopListeningToURL(const GURL& url) {
imcheng 2017/01/18 22:40:32 nit: rename to MaybeStopListeningToURL since it do
zhaobin 2017/01/19 00:56:16 Done.
518 presentation_service_->StopListeningForScreenAvailability(status->url); 598 for (const auto& listener : availability_set_) {
599 if (!base::ContainsValue(listener->urls, url))
600 continue;
601
602 // URL is still observed by some availability object.
603 if (!listener->availability_callbacks.IsEmpty() ||
604 !listener->availability_observers.empty()) {
605 return;
606 }
607 }
608
609 auto* listening_status = GetListeningStatus(url);
610 if (!listening_status) {
611 LOG(WARNING) << "Stop listening to unknown url: " << url;
612 return;
613 }
614
615 if (listening_status->listening_state == ListeningState::INACTIVE)
616 return;
617
618 ConnectToPresentationServiceIfNeeded();
619 listening_status->listening_state = ListeningState::INACTIVE;
620 presentation_service_->StopListeningForScreenAvailability(url);
621 }
622
623 PresentationDispatcher::ListeningStatus*
624 PresentationDispatcher::GetListeningStatus(const GURL& url) const {
625 auto status_it = listening_status_.find(url);
626 return status_it == listening_status_.end() ? nullptr
627 : status_it->second.get();
628 }
629
630 PresentationDispatcher::AvailabilityListener*
631 PresentationDispatcher::GetAvailabilityListener(
632 const std::vector<GURL>& urls) const {
633 auto listener_it =
634 std::find_if(availability_set_.begin(), availability_set_.end(),
635 [&urls](const std::unique_ptr<AvailabilityListener>& x) {
636 return x->urls == urls;
637 });
638 return listener_it == availability_set_.end() ? nullptr : listener_it->get();
639 }
640
641 void PresentationDispatcher::TryRemoveAvailabilityListener(
642 AvailabilityListener* listener) {
643 // URL is still observed by some availability object.
644 if (!listener->availability_callbacks.IsEmpty() ||
645 !listener->availability_observers.empty()) {
646 return;
647 }
648
649 auto listener_it = availability_set_.begin();
650 while (listener_it != availability_set_.end()) {
651 if (listener_it->get() == listener) {
652 availability_set_.erase(listener_it++);
imcheng 2017/01/18 22:40:32 There should only be at most one listener entry in
zhaobin 2017/01/19 00:56:16 Done.
653 } else {
654 ++listener_it;
655 }
519 } 656 }
520 } 657 }
521 658
659 PresentationDispatcher::ScreenAvailability
660 PresentationDispatcher::GetScreenAvailability(
661 const std::vector<GURL>& urls) const {
662 std::map<ScreenAvailability, size_t> counters;
663
664 for (const auto& url : urls) {
665 auto* status = GetListeningStatus(url);
666 auto screen_availability =
667 status ? status->last_known_availability : ScreenAvailability::UNKNOWN;
668 counters[screen_availability]++;
669 }
670
671 if (counters[ScreenAvailability::AVAILABLE] > 0)
672 return ScreenAvailability::AVAILABLE;
673 if (counters[ScreenAvailability::UNSUPPORTED] > 0)
674 return ScreenAvailability::UNSUPPORTED;
675 if (counters[ScreenAvailability::UNAVAILABLE] > 0)
676 return ScreenAvailability::UNAVAILABLE;
677
678 auto unknown_counter = counters[ScreenAvailability::UNKNOWN];
imcheng 2017/01/18 22:40:32 Sorry to be pedantic but this is introduces unneed
zhaobin 2017/01/19 00:56:16 Done.
679 DCHECK_EQ(unknown_counter, urls.size());
680 return ScreenAvailability::UNKNOWN;
681 }
682
522 PresentationDispatcher::SendMessageRequest::SendMessageRequest( 683 PresentationDispatcher::SendMessageRequest::SendMessageRequest(
523 blink::mojom::PresentationSessionInfoPtr session_info, 684 blink::mojom::PresentationSessionInfoPtr session_info,
524 blink::mojom::ConnectionMessagePtr message) 685 blink::mojom::ConnectionMessagePtr message)
525 : session_info(std::move(session_info)), message(std::move(message)) {} 686 : session_info(std::move(session_info)), message(std::move(message)) {}
526 687
527 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {} 688 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {}
528 689
529 // static 690 // static
530 PresentationDispatcher::SendMessageRequest* 691 PresentationDispatcher::SendMessageRequest*
531 PresentationDispatcher::CreateSendTextMessageRequest( 692 PresentationDispatcher::CreateSendTextMessageRequest(
(...skipping 27 matching lines...) Expand all
559 session_info->id = presentationId.utf8(); 720 session_info->id = presentationId.utf8();
560 721
561 blink::mojom::ConnectionMessagePtr session_message = 722 blink::mojom::ConnectionMessagePtr session_message =
562 blink::mojom::ConnectionMessage::New(); 723 blink::mojom::ConnectionMessage::New();
563 session_message->type = type; 724 session_message->type = type;
564 session_message->data = std::vector<uint8_t>(data, data + length); 725 session_message->data = std::vector<uint8_t>(data, data + length);
565 return new SendMessageRequest(std::move(session_info), 726 return new SendMessageRequest(std::move(session_info),
566 std::move(session_message)); 727 std::move(session_message));
567 } 728 }
568 729
569 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus( 730 PresentationDispatcher::AvailabilityListener::AvailabilityListener(
731 const std::vector<GURL>& availability_urls)
732 : urls(availability_urls) {}
733
734 PresentationDispatcher::AvailabilityListener::~AvailabilityListener() {}
735
736 PresentationDispatcher::ListeningStatus::ListeningStatus(
570 const GURL& availability_url) 737 const GURL& availability_url)
571 : url(availability_url), 738 : url(availability_url),
572 last_known_availability(false), 739 last_known_availability(ScreenAvailability::UNKNOWN),
573 listening_state(ListeningState::INACTIVE) {} 740 listening_state(ListeningState::INACTIVE) {}
574 741
575 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() { 742 PresentationDispatcher::ListeningStatus::~ListeningStatus() {}
576 }
577 743
578 } // namespace content 744 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698