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

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

Issue 2598063002: [Presentation API] Handle multiple Presentation URLs in PresentationRequest::getAvailability() (Closed)
Patch Set: seperate AvailabilityStatus from ListeningStatus and simplify book keeping code 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 // Resolve promise if we know some URLs' status.
mark a. foltz 2017/01/11 00:06:02 // Reject Promise if screen availability is unsupp
zhaobin 2017/01/12 03:02:12 Done.
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
268 AvailabilityStatus* status = nullptr; 286 AvailabilityStatus* status = nullptr;
mark a. foltz 2017/01/11 00:06:02 Consider using std::find_if instead of looping.
zhaobin 2017/01/12 03:02:12 Done.
269 auto status_it = availability_status_.find(availabilityUrl); 287 for (const auto& availability : availability_set_) {
270 if (status_it == availability_status_.end()) { 288 if (availability->urls == urls) {
271 status = new AvailabilityStatus(availabilityUrl); 289 status = availability.get();
272 availability_status_[availabilityUrl] = base::WrapUnique(status); 290 break;
273 } else { 291 }
274 status = status_it->second.get();
275 } 292 }
276 DCHECK(status);
277 293
278 if (status->listening_state == ListeningState::ACTIVE) { 294 if (!status) {
295 status = new AvailabilityStatus(urls);
296 availability_set_.insert(base::WrapUnique(status));
mark a. foltz 2017/01/11 00:06:02 When are entries removed from |availability_set_|?
zhaobin 2017/01/12 03:02:12 We do not. |availability_set_| will finally be cle
297 }
298
299 if (screen_availability != ScreenAvailability::UNKNOWN) {
279 base::ThreadTaskRunnerHandle::Get()->PostTask( 300 base::ThreadTaskRunnerHandle::Get()->PostTask(
280 FROM_HERE, 301 FROM_HERE,
281 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess, 302 base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess,
282 base::Passed(&callbacks), status->last_known_availability)); 303 base::Passed(&callback),
283 return; 304 screen_availability == ScreenAvailability::AVAILABLE));
305 } else {
306 status->availability_callbacks.Add(std::move(callback));
284 } 307 }
285 308
286 status->availability_callbacks.Add(std::move(callbacks)); 309 for (const auto& availabilityUrl : urls)
287 UpdateListeningState(status); 310 StartListening(availabilityUrl);
288 } 311 }
289 312
290 void PresentationDispatcher::startListening( 313 void PresentationDispatcher::startListening(
291 blink::WebPresentationAvailabilityObserver* observer) { 314 blink::WebPresentationAvailabilityObserver* observer) {
292 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 315 std::vector<GURL> urls;
293 const blink::WebURL& availabilityUrl = observer->urls()[0]; 316 for (const auto& url : observer->urls())
294 auto status_it = availability_status_.find(availabilityUrl); 317 urls.push_back(url);
295 if (status_it == availability_status_.end()) { 318
296 DLOG(WARNING) << "Start listening for availability for unknown URL " 319 for (auto& status : availability_set_) {
297 << GURL(availabilityUrl); 320 if (status->urls == urls)
298 return; 321 status->availability_observers.insert(observer);
mark a. foltz 2017/01/11 00:06:02 Do you need to break the loop after inserting the
zhaobin 2017/01/12 03:02:12 Done.
299 } 322 }
mark a. foltz 2017/01/11 00:06:02 Can you add a DCHECK() that one observer was actua
zhaobin 2017/01/12 03:02:12 Done.
300 status_it->second->availability_observers.insert(observer); 323
301 UpdateListeningState(status_it->second.get()); 324 for (const auto& availabilityUrl : urls)
325 StartListening(availabilityUrl);
302 } 326 }
303 327
304 void PresentationDispatcher::stopListening( 328 void PresentationDispatcher::stopListening(
305 blink::WebPresentationAvailabilityObserver* observer) { 329 blink::WebPresentationAvailabilityObserver* observer) {
306 // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655. 330 std::vector<GURL> urls;
307 const blink::WebURL& availabilityUrl = observer->urls()[0]; 331 for (const auto& url : observer->urls())
308 auto status_it = availability_status_.find(availabilityUrl); 332 urls.push_back(url);
309 if (status_it == availability_status_.end()) { 333
310 DLOG(WARNING) << "Stop listening for availability for unknown URL " 334 for (auto& status : availability_set_) {
311 << GURL(availabilityUrl); 335 if (status->urls == urls)
312 return; 336 status->availability_observers.erase(observer);
mark a. foltz 2017/01/11 00:06:02 Do you need to break after finding the matching st
zhaobin 2017/01/12 03:02:12 Done.
313 } 337 }
mark a. foltz 2017/01/11 00:06:02 Can you add a DCHECK that exactly one observer was
zhaobin 2017/01/12 03:02:12 Done.
314 status_it->second->availability_observers.erase(observer); 338
315 UpdateListeningState(status_it->second.get()); 339 for (const auto& availabilityUrl : urls)
340 StopListening(availabilityUrl);
316 } 341 }
317 342
318 void PresentationDispatcher::setDefaultPresentationUrls( 343 void PresentationDispatcher::setDefaultPresentationUrls(
319 const blink::WebVector<blink::WebURL>& presentationUrls) { 344 const blink::WebVector<blink::WebURL>& presentationUrls) {
320 ConnectToPresentationServiceIfNeeded(); 345 ConnectToPresentationServiceIfNeeded();
321 346
322 std::vector<GURL> urls; 347 std::vector<GURL> urls;
323 for (const auto& url : presentationUrls) 348 for (const auto& url : presentationUrls)
324 urls.push_back(url); 349 urls.push_back(url);
325 350
(...skipping 18 matching lines...) Expand all
344 MessageRequestQueue empty; 369 MessageRequestQueue empty;
345 std::swap(message_request_queue_, empty); 370 std::swap(message_request_queue_, empty);
346 } 371 }
347 372
348 void PresentationDispatcher::OnDestruct() { 373 void PresentationDispatcher::OnDestruct() {
349 delete this; 374 delete this;
350 } 375 }
351 376
352 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url, 377 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url,
353 bool available) { 378 bool available) {
354 auto status_it = availability_status_.find(url); 379 auto* listening_status = GetListeningStatus(url);
355 if (status_it == availability_status_.end()) 380 if (!listening_status)
356 return; 381 return;
357 AvailabilityStatus* status = status_it->second.get();
358 DCHECK(status);
359 382
360 if (status->listening_state == ListeningState::WAITING) 383 if (listening_status->listening_state == ListeningState::WAITING)
361 status->listening_state = ListeningState::ACTIVE; 384 listening_status->listening_state = ListeningState::ACTIVE;
362 385
363 for (auto* observer : status->availability_observers) 386 auto new_screen_availability = available ? ScreenAvailability::AVAILABLE
364 observer->availabilityChanged(available); 387 : ScreenAvailability::UNAVAILABLE;
388 if (listening_status->last_known_availability == new_screen_availability)
389 return;
365 390
366 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 391 listening_status->last_known_availability = new_screen_availability;
367 !iter.IsAtEnd(); iter.Advance()) { 392
368 iter.GetCurrentValue()->onSuccess(available); 393 for (auto& status : availability_set_) {
394 if (!base::ContainsValue(status->urls, url))
395 continue;
396 auto screen_availability = GetScreenAvailability(status->urls);
397 // screen_availability cannot be UNKNOWN or UNSUPPORTED here
mark a. foltz 2017/01/11 00:06:02 DCHECK(availability == AVAILABLE || availability =
zhaobin 2017/01/12 03:02:12 Done.
398 for (auto* observer : status->availability_observers) {
399 observer->availabilityChanged(screen_availability ==
400 ScreenAvailability::AVAILABLE);
401 }
402
403 for (AvailabilityCallbacksMap::iterator iter(
404 &status->availability_callbacks);
405 !iter.IsAtEnd(); iter.Advance()) {
406 iter.GetCurrentValue()->onSuccess(screen_availability ==
407 ScreenAvailability::AVAILABLE);
408 }
409 status->availability_callbacks.Clear();
369 } 410 }
370 status->last_known_availability = available;
371 status->availability_callbacks.Clear();
372 UpdateListeningState(status);
373 } 411 }
374 412
375 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) { 413 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) {
376 auto status_it = availability_status_.find(url); 414 auto* listening_status = GetListeningStatus(url);
377 if (status_it == availability_status_.end()) 415 if (!listening_status)
378 return; 416 return;
379 AvailabilityStatus* status = status_it->second.get();
380 DCHECK(status);
381 DCHECK(status->listening_state == ListeningState::WAITING);
382 417
383 const blink::WebString& not_supported_error = blink::WebString::fromUTF8( 418 if (listening_status->listening_state == ListeningState::WAITING)
384 "getAvailability() isn't supported at the moment. It can be due to " 419 listening_status->listening_state = ListeningState::ACTIVE;
385 "a permanent or temporary system limitation. It is recommended to " 420
386 "try to blindly start a session in that case."); 421 if (listening_status->last_known_availability ==
387 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 422 ScreenAvailability::UNSUPPORTED)
388 !iter.IsAtEnd(); iter.Advance()) { 423 return;
389 iter.GetCurrentValue()->onError(blink::WebPresentationError( 424
390 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported, 425 listening_status->last_known_availability = ScreenAvailability::UNSUPPORTED;
391 not_supported_error)); 426
427 for (auto& status : availability_set_) {
428 if (!base::ContainsValue(status->urls, url))
429 continue;
430
431 // ScreenAvailabilityNotSupported should be a browser side setting, which
432 // means all urls in PresentationAvailability should report NotSupported.
433 // It is not possible to change listening status from Available or
434 // Unavailable to NotSupported. No need to update observer.
435 auto screen_availability = GetScreenAvailability(status->urls);
436 DCHECK_EQ(screen_availability, ScreenAvailability::UNSUPPORTED);
mark a. foltz 2017/01/11 00:06:02 What if a different URL in |status->urls| was alre
zhaobin 2017/01/12 03:02:12 Is it possible to have some URLs report AVAILABLE
437
438 const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
439 "getAvailability() isn't supported at the moment. It can be due to "
440 "a permanent or temporary system limitation. It is recommended to "
441 "try to blindly start a session in that case.");
442 for (AvailabilityCallbacksMap::iterator iter(
443 &status->availability_callbacks);
444 !iter.IsAtEnd(); iter.Advance()) {
445 iter.GetCurrentValue()->onError(blink::WebPresentationError(
446 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
447 not_supported_error));
448 }
449 status->availability_callbacks.Clear();
450
451 for (const auto& availability_url : status->urls)
452 StopListening(availability_url);
392 } 453 }
393 status->availability_callbacks.Clear();
394 UpdateListeningState(status);
395 } 454 }
396 455
397 void PresentationDispatcher::OnDefaultSessionStarted( 456 void PresentationDispatcher::OnDefaultSessionStarted(
398 blink::mojom::PresentationSessionInfoPtr session_info) { 457 blink::mojom::PresentationSessionInfoPtr session_info) {
399 if (!controller_) 458 if (!controller_)
400 return; 459 return;
401 460
402 if (!session_info.is_null()) { 461 if (!session_info.is_null()) {
403 presentation_service_->ListenForConnectionMessages(session_info.Clone()); 462 presentation_service_->ListenForConnectionMessages(session_info.Clone());
404 controller_->didStartDefaultSession( 463 controller_->didStartDefaultSession(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 } 551 }
493 552
494 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { 553 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
495 if (presentation_service_.get()) 554 if (presentation_service_.get())
496 return; 555 return;
497 556
498 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_); 557 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_);
499 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind()); 558 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind());
500 } 559 }
501 560
502 void PresentationDispatcher::UpdateListeningState(AvailabilityStatus* status) { 561 void PresentationDispatcher::SetPresentationServiceForTest(
503 bool should_listen = !status->availability_callbacks.IsEmpty() || 562 blink::mojom::PresentationServicePtr presentation_service) {
504 !status->availability_observers.empty(); 563 presentation_service_ = std::move(presentation_service);
505 bool is_listening = status->listening_state != ListeningState::INACTIVE; 564 }
506 565
507 if (should_listen == is_listening) 566 void PresentationDispatcher::StartListening(const GURL& url) {
mark a. foltz 2017/01/11 00:06:02 It's potentially confusing to have startListening
zhaobin 2017/01/12 03:02:12 Done.
567 auto* listening_status = GetListeningStatus(url);
568 if (!listening_status) {
569 listening_status = new ListeningStatus(url);
570 listening_status_[url] = base::WrapUnique(listening_status);
mark a. foltz 2017/01/11 00:06:02 Nit: Use .insert() to avoid an extra allocation.
zhaobin 2017/01/12 03:02:12 Done.
571 }
572
573 // Already listening.
574 if (listening_status->listening_state != ListeningState::INACTIVE)
508 return; 575 return;
509 576
510 ConnectToPresentationServiceIfNeeded(); 577 ConnectToPresentationServiceIfNeeded();
511 if (should_listen) { 578 listening_status->listening_state = ListeningState::WAITING;
512 status->listening_state = ListeningState::WAITING; 579 presentation_service_->ListenForScreenAvailability(url);
513 presentation_service_->ListenForScreenAvailability(status->url); 580 }
514 } else { 581
515 status->listening_state = ListeningState::INACTIVE; 582 void PresentationDispatcher::StopListening(const GURL& url) {
516 presentation_service_->StopListeningForScreenAvailability(status->url); 583 for (const auto& status : availability_set_) {
584 if (!base::ContainsValue(status->urls, url))
585 continue;
586
587 // URL is still observed by some availability object.
588 if (!status->availability_callbacks.IsEmpty() ||
589 !status->availability_observers.empty())
590 return;
517 } 591 }
592
593 auto* listening_status = GetListeningStatus(url);
594 DCHECK(listening_status);
mark a. foltz 2017/01/11 00:06:02 This means that StopListening was called on a URL
zhaobin 2017/01/12 03:02:12 It means StartListening was never called on. Calli
595
596 if (listening_status->listening_state == ListeningState::INACTIVE)
597 return;
598
599 ConnectToPresentationServiceIfNeeded();
600 listening_status->listening_state = ListeningState::INACTIVE;
601 presentation_service_->StopListeningForScreenAvailability(url);
602 }
603
604 PresentationDispatcher::ListeningStatus*
605 PresentationDispatcher::GetListeningStatus(const GURL& url) {
606 ListeningStatus* status = nullptr;
607 auto status_it = listening_status_.find(url);
608 if (status_it != listening_status_.end())
609 status = status_it->second.get();
610 return status;
611 }
612
613 PresentationDispatcher::ScreenAvailability
614 PresentationDispatcher::GetScreenAvailability(const std::vector<GURL>& urls) {
615 std::map<ScreenAvailability, size_t> counters;
mark a. foltz 2017/01/11 00:06:02 Does this initialize the values to zero?
zhaobin 2017/01/12 03:02:12 Yes.
616
617 for (const auto& url : urls) {
618 if (!base::ContainsKey(listening_status_, url)) {
619 counters[ScreenAvailability::UNKNOWN]++;
620 } else {
621 auto url_availability = listening_status_[url]->last_known_availability;
622 counters[url_availability]++;
623 }
624 }
625
626 if (counters[ScreenAvailability::AVAILABLE] > 0)
627 return ScreenAvailability::AVAILABLE;
628 if (counters[ScreenAvailability::UNSUPPORTED] > 0)
629 return ScreenAvailability::UNSUPPORTED;
630 if (counters[ScreenAvailability::UNAVAILABLE] > 0)
631 return ScreenAvailability::UNAVAILABLE;
632
633 DCHECK_EQ(counters[ScreenAvailability::UNKNOWN], urls.size());
634 return ScreenAvailability::UNKNOWN;
518 } 635 }
519 636
520 PresentationDispatcher::SendMessageRequest::SendMessageRequest( 637 PresentationDispatcher::SendMessageRequest::SendMessageRequest(
521 blink::mojom::PresentationSessionInfoPtr session_info, 638 blink::mojom::PresentationSessionInfoPtr session_info,
522 blink::mojom::ConnectionMessagePtr message) 639 blink::mojom::ConnectionMessagePtr message)
523 : session_info(std::move(session_info)), message(std::move(message)) {} 640 : session_info(std::move(session_info)), message(std::move(message)) {}
524 641
525 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {} 642 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {}
526 643
527 // static 644 // static
(...skipping 30 matching lines...) Expand all
558 675
559 blink::mojom::ConnectionMessagePtr session_message = 676 blink::mojom::ConnectionMessagePtr session_message =
560 blink::mojom::ConnectionMessage::New(); 677 blink::mojom::ConnectionMessage::New();
561 session_message->type = type; 678 session_message->type = type;
562 session_message->data = std::vector<uint8_t>(data, data + length); 679 session_message->data = std::vector<uint8_t>(data, data + length);
563 return new SendMessageRequest(std::move(session_info), 680 return new SendMessageRequest(std::move(session_info),
564 std::move(session_message)); 681 std::move(session_message));
565 } 682 }
566 683
567 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus( 684 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus(
685 const std::vector<GURL>& availability_urls)
686 : urls(availability_urls) {}
687
688 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() {}
689
690 PresentationDispatcher::ListeningStatus::ListeningStatus(
568 const GURL& availability_url) 691 const GURL& availability_url)
569 : url(availability_url), 692 : url(availability_url),
570 last_known_availability(false), 693 last_known_availability(ScreenAvailability::UNKNOWN),
571 listening_state(ListeningState::INACTIVE) {} 694 listening_state(ListeningState::INACTIVE) {}
572 695
573 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() { 696 PresentationDispatcher::ListeningStatus::~ListeningStatus() {}
574 }
575 697
576 } // namespace content 698 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698