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

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

Issue 2598063002: [Presentation API] Handle multiple Presentation URLs in PresentationRequest::getAvailability() (Closed)
Patch Set: merge presentation_dispatcher_unittest.cc 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
267 std::vector<GURL> urls;
268 for (const auto& availability_url : availabilityUrls)
269 urls.push_back(availability_url);
270
271 auto screen_availability = GetScreenAvailability(urls);
272 // Reject Promise if screen availability is unsupported for all URLs.
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;
284 }
285
286 auto status_it =
287 std::find_if(availability_set_.begin(), availability_set_.end(),
288 [&urls](const std::unique_ptr<AvailabilityStatus>& x) {
289 return x->urls == urls;
290 });
291
268 AvailabilityStatus* status = nullptr; 292 AvailabilityStatus* status = nullptr;
269 auto status_it = availability_status_.find(availabilityUrl); 293 if (status_it == availability_set_.end()) {
270 if (status_it == availability_status_.end()) { 294 status = new AvailabilityStatus(urls);
271 status = new AvailabilityStatus(availabilityUrl); 295 availability_set_.insert(base::WrapUnique(status));
272 availability_status_[availabilityUrl] = base::WrapUnique(status);
273 } else { 296 } else {
274 status = status_it->second.get(); 297 status = status_it->get();
275 } 298 }
276 DCHECK(status);
277 299
278 if (status->listening_state == ListeningState::ACTIVE) { 300 if (screen_availability != ScreenAvailability::UNKNOWN) {
279 base::ThreadTaskRunnerHandle::Get()->PostTask( 301 base::ThreadTaskRunnerHandle::Get()->PostTask(
280 FROM_HERE, 302 FROM_HERE,
281 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess, 303 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess,
282 base::Passed(&callbacks), status->last_known_availability)); 304 base::Passed(&callback),
283 return; 305 screen_availability == ScreenAvailability::AVAILABLE));
306 } else {
307 status->availability_callbacks.Add(std::move(callback));
284 } 308 }
285 309
286 status->availability_callbacks.Add(std::move(callbacks)); 310 for (const auto& availabilityUrl : urls)
287 UpdateListeningState(status); 311 StartListeningToURL(availabilityUrl);
288 } 312 }
289 313
290 void PresentationDispatcher::startListening( 314 void PresentationDispatcher::startListening(
291 blink::WebPresentationAvailabilityObserver* observer) { 315 blink::WebPresentationAvailabilityObserver* observer) {
292 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 316 std::vector<GURL> urls;
293 const blink::WebURL& availabilityUrl = observer->urls()[0]; 317 for (const auto& url : observer->urls())
294 auto status_it = availability_status_.find(availabilityUrl); 318 urls.push_back(url);
295 if (status_it == availability_status_.end()) { 319
296 DLOG(WARNING) << "Start listening for availability for unknown URL " 320 auto status_it =
mark a. foltz 2017/01/13 19:06:32 This is repeated a few times; add a private method
zhaobin 2017/01/14 01:45:32 Done.
297 << GURL(availabilityUrl); 321 std::find_if(availability_set_.begin(), availability_set_.end(),
322 [&urls](const std::unique_ptr<AvailabilityStatus>& x) {
323 return x->urls == urls;
324 });
325
326 if (status_it == availability_set_.end()) {
327 DLOG(WARNING) << "Start listening for availability for unknown URLs.";
298 return; 328 return;
299 } 329 }
300 status_it->second->availability_observers.insert(observer); 330
301 UpdateListeningState(status_it->second.get()); 331 (*status_it)->availability_observers.insert(observer);
332 for (const auto& availabilityUrl : urls)
333 StartListeningToURL(availabilityUrl);
302 } 334 }
303 335
304 void PresentationDispatcher::stopListening( 336 void PresentationDispatcher::stopListening(
305 blink::WebPresentationAvailabilityObserver* observer) { 337 blink::WebPresentationAvailabilityObserver* observer) {
306 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 338 std::vector<GURL> urls;
307 const blink::WebURL& availabilityUrl = observer->urls()[0]; 339 for (const auto& url : observer->urls())
308 auto status_it = availability_status_.find(availabilityUrl); 340 urls.push_back(url);
309 if (status_it == availability_status_.end()) { 341
310 DLOG(WARNING) << "Stop listening for availability for unknown URL " 342 auto status_it =
311 << GURL(availabilityUrl); 343 std::find_if(availability_set_.begin(), availability_set_.end(),
344 [&urls](const std::unique_ptr<AvailabilityStatus>& x) {
345 return x->urls == urls;
346 });
347
348 if (status_it == availability_set_.end()) {
349 DLOG(WARNING) << "Stop listening for availability for unknown URLs.";
312 return; 350 return;
313 } 351 }
314 status_it->second->availability_observers.erase(observer); 352
315 UpdateListeningState(status_it->second.get()); 353 (*status_it)->availability_observers.erase(observer);
354
355 for (const auto& availabilityUrl : urls)
356 StopListeningToURL(availabilityUrl);
316 } 357 }
317 358
318 void PresentationDispatcher::setDefaultPresentationUrls( 359 void PresentationDispatcher::setDefaultPresentationUrls(
319 const blink::WebVector<blink::WebURL>& presentationUrls) { 360 const blink::WebVector<blink::WebURL>& presentationUrls) {
320 ConnectToPresentationServiceIfNeeded(); 361 ConnectToPresentationServiceIfNeeded();
321 362
322 std::vector<GURL> urls; 363 std::vector<GURL> urls;
323 for (const auto& url : presentationUrls) 364 for (const auto& url : presentationUrls)
324 urls.push_back(url); 365 urls.push_back(url);
325 366
(...skipping 18 matching lines...) Expand all
344 MessageRequestQueue empty; 385 MessageRequestQueue empty;
345 std::swap(message_request_queue_, empty); 386 std::swap(message_request_queue_, empty);
346 } 387 }
347 388
348 void PresentationDispatcher::OnDestruct() { 389 void PresentationDispatcher::OnDestruct() {
349 delete this; 390 delete this;
350 } 391 }
351 392
352 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url, 393 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url,
353 bool available) { 394 bool available) {
354 auto status_it = availability_status_.find(url); 395 auto* listening_status = GetListeningStatus(url);
355 if (status_it == availability_status_.end()) 396 if (!listening_status)
356 return; 397 return;
357 AvailabilityStatus* status = status_it->second.get();
358 DCHECK(status);
359 398
360 if (status->listening_state == ListeningState::WAITING) 399 if (listening_status->listening_state == ListeningState::WAITING)
361 status->listening_state = ListeningState::ACTIVE; 400 listening_status->listening_state = ListeningState::ACTIVE;
362 401
363 for (auto* observer : status->availability_observers) 402 auto new_screen_availability = available ? ScreenAvailability::AVAILABLE
364 observer->availabilityChanged(available); 403 : ScreenAvailability::UNAVAILABLE;
404 if (listening_status->last_known_availability == new_screen_availability)
405 return;
365 406
366 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 407 listening_status->last_known_availability = new_screen_availability;
367 !iter.IsAtEnd(); iter.Advance()) { 408
368 iter.GetCurrentValue()->onSuccess(available); 409 for (auto& status : availability_set_) {
410 if (!base::ContainsValue(status->urls, url))
411 continue;
412 auto screen_availability = GetScreenAvailability(status->urls);
413 DCHECK(screen_availability == ScreenAvailability::AVAILABLE ||
414 screen_availability == ScreenAvailability::UNAVAILABLE);
415 bool is_available = (screen_availability == ScreenAvailability::AVAILABLE);
416
417 for (auto* observer : status->availability_observers)
418 observer->availabilityChanged(is_available);
419
420 for (AvailabilityCallbacksMap::iterator iter(
421 &status->availability_callbacks);
422 !iter.IsAtEnd(); iter.Advance()) {
423 iter.GetCurrentValue()->onSuccess(is_available);
424 }
425 status->availability_callbacks.Clear();
369 } 426 }
370 status->last_known_availability = available;
371 status->availability_callbacks.Clear();
372 UpdateListeningState(status);
373 } 427 }
374 428
375 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) { 429 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) {
376 auto status_it = availability_status_.find(url); 430 auto* listening_status = GetListeningStatus(url);
377 if (status_it == availability_status_.end()) 431 if (!listening_status)
378 return; 432 return;
379 AvailabilityStatus* status = status_it->second.get();
380 DCHECK(status);
381 DCHECK(status->listening_state == ListeningState::WAITING);
382 433
383 const blink::WebString& not_supported_error = blink::WebString::fromUTF8( 434 if (listening_status->listening_state == ListeningState::WAITING)
384 "getAvailability() isn't supported at the moment. It can be due to " 435 listening_status->listening_state = ListeningState::ACTIVE;
385 "a permanent or temporary system limitation. It is recommended to " 436
386 "try to blindly start a session in that case."); 437 if (listening_status->last_known_availability ==
387 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 438 ScreenAvailability::UNSUPPORTED)
388 !iter.IsAtEnd(); iter.Advance()) { 439 return;
389 iter.GetCurrentValue()->onError(blink::WebPresentationError( 440
390 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported, 441 listening_status->last_known_availability = ScreenAvailability::UNSUPPORTED;
391 not_supported_error)); 442
443 for (auto& status : availability_set_) {
444 if (!base::ContainsValue(status->urls, url))
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(status->urls);
452 DCHECK_EQ(screen_availability, ScreenAvailability::UNSUPPORTED);
453
454 const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
455 "getAvailability() isn't supported at the moment. It can be due to "
456 "a permanent or temporary system limitation. It is recommended to "
457 "try to blindly start a session in that case.");
458 for (AvailabilityCallbacksMap::iterator iter(
459 &status->availability_callbacks);
460 !iter.IsAtEnd(); iter.Advance()) {
461 iter.GetCurrentValue()->onError(blink::WebPresentationError(
462 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
463 not_supported_error));
464 }
465 status->availability_callbacks.Clear();
466
467 for (const auto& availability_url : status->urls)
468 StopListeningToURL(availability_url);
392 } 469 }
393 status->availability_callbacks.Clear();
394 UpdateListeningState(status);
395 } 470 }
396 471
397 void PresentationDispatcher::OnDefaultSessionStarted( 472 void PresentationDispatcher::OnDefaultSessionStarted(
398 blink::mojom::PresentationSessionInfoPtr session_info) { 473 blink::mojom::PresentationSessionInfoPtr session_info) {
399 if (!controller_) 474 if (!controller_)
400 return; 475 return;
401 476
402 if (!session_info.is_null()) { 477 if (!session_info.is_null()) {
403 presentation_service_->ListenForConnectionMessages(session_info.Clone()); 478 presentation_service_->ListenForConnectionMessages(session_info.Clone());
404 controller_->didStartDefaultSession( 479 controller_->didStartDefaultSession(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 } 567 }
493 568
494 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { 569 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
495 if (presentation_service_.get()) 570 if (presentation_service_.get())
496 return; 571 return;
497 572
498 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_); 573 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_);
499 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind()); 574 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind());
500 } 575 }
501 576
502 void PresentationDispatcher::UpdateListeningState(AvailabilityStatus* status) { 577 void PresentationDispatcher::StartListeningToURL(const GURL& url) {
503 bool should_listen = !status->availability_callbacks.IsEmpty() || 578 auto* listening_status = GetListeningStatus(url);
504 !status->availability_observers.empty(); 579 if (!listening_status) {
505 bool is_listening = status->listening_state != ListeningState::INACTIVE; 580 listening_status = new ListeningStatus(url);
581 listening_status_.insert(
582 std::make_pair(url, base::WrapUnique(listening_status)));
583 }
506 584
507 if (should_listen == is_listening) 585 // Already listening.
586 if (listening_status->listening_state != ListeningState::INACTIVE)
508 return; 587 return;
509 588
510 ConnectToPresentationServiceIfNeeded(); 589 ConnectToPresentationServiceIfNeeded();
511 if (should_listen) { 590 listening_status->listening_state = ListeningState::WAITING;
512 status->listening_state = ListeningState::WAITING; 591 presentation_service_->ListenForScreenAvailability(url);
513 presentation_service_->ListenForScreenAvailability(status->url); 592 }
514 } else { 593
515 status->listening_state = ListeningState::INACTIVE; 594 void PresentationDispatcher::StopListeningToURL(const GURL& url) {
516 presentation_service_->StopListeningForScreenAvailability(status->url); 595 for (const auto& status : availability_set_) {
596 if (!base::ContainsValue(status->urls, url))
597 continue;
598
599 // URL is still observed by some availability object.
600 if (!status->availability_callbacks.IsEmpty() ||
601 !status->availability_observers.empty())
602 return;
517 } 603 }
604
605 auto* listening_status = GetListeningStatus(url);
606 DCHECK(listening_status);
607
608 if (listening_status->listening_state == ListeningState::INACTIVE)
609 return;
610
611 ConnectToPresentationServiceIfNeeded();
612 listening_status->listening_state = ListeningState::INACTIVE;
613 presentation_service_->StopListeningForScreenAvailability(url);
614 }
615
616 PresentationDispatcher::ListeningStatus*
617 PresentationDispatcher::GetListeningStatus(const GURL& url) {
618 ListeningStatus* status = nullptr;
619 auto status_it = listening_status_.find(url);
620 if (status_it != listening_status_.end())
621 status = status_it->second.get();
622 return status;
623 }
624
625 PresentationDispatcher::ScreenAvailability
626 PresentationDispatcher::GetScreenAvailability(const std::vector<GURL>& urls) {
627 std::map<ScreenAvailability, size_t> counters;
628
629 for (const auto& url : urls) {
630 if (!base::ContainsKey(listening_status_, url)) {
631 counters[ScreenAvailability::UNKNOWN]++;
632 } else {
633 auto url_availability = listening_status_[url]->last_known_availability;
634 counters[url_availability]++;
635 }
636 }
637
638 if (counters[ScreenAvailability::AVAILABLE] > 0)
639 return ScreenAvailability::AVAILABLE;
640 if (counters[ScreenAvailability::UNSUPPORTED] > 0)
641 return ScreenAvailability::UNSUPPORTED;
642 if (counters[ScreenAvailability::UNAVAILABLE] > 0)
643 return ScreenAvailability::UNAVAILABLE;
644
645 DCHECK_EQ(counters[ScreenAvailability::UNKNOWN], urls.size());
646 return ScreenAvailability::UNKNOWN;
518 } 647 }
519 648
520 PresentationDispatcher::SendMessageRequest::SendMessageRequest( 649 PresentationDispatcher::SendMessageRequest::SendMessageRequest(
521 blink::mojom::PresentationSessionInfoPtr session_info, 650 blink::mojom::PresentationSessionInfoPtr session_info,
522 blink::mojom::ConnectionMessagePtr message) 651 blink::mojom::ConnectionMessagePtr message)
523 : session_info(std::move(session_info)), message(std::move(message)) {} 652 : session_info(std::move(session_info)), message(std::move(message)) {}
524 653
525 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {} 654 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {}
526 655
527 // static 656 // static
(...skipping 30 matching lines...) Expand all
558 687
559 blink::mojom::ConnectionMessagePtr session_message = 688 blink::mojom::ConnectionMessagePtr session_message =
560 blink::mojom::ConnectionMessage::New(); 689 blink::mojom::ConnectionMessage::New();
561 session_message->type = type; 690 session_message->type = type;
562 session_message->data = std::vector<uint8_t>(data, data + length); 691 session_message->data = std::vector<uint8_t>(data, data + length);
563 return new SendMessageRequest(std::move(session_info), 692 return new SendMessageRequest(std::move(session_info),
564 std::move(session_message)); 693 std::move(session_message));
565 } 694 }
566 695
567 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus( 696 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus(
697 const std::vector<GURL>& availability_urls)
698 : urls(availability_urls) {}
699
700 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() {}
701
702 PresentationDispatcher::ListeningStatus::ListeningStatus(
568 const GURL& availability_url) 703 const GURL& availability_url)
569 : url(availability_url), 704 : url(availability_url),
570 last_known_availability(false), 705 last_known_availability(ScreenAvailability::UNKNOWN),
571 listening_state(ListeningState::INACTIVE) {} 706 listening_state(ListeningState::INACTIVE) {}
572 707
573 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() { 708 PresentationDispatcher::ListeningStatus::~ListeningStatus() {}
574 }
575 709
576 } // namespace content 710 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698