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

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 Mark 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* status = GetAvailabilityStatus(urls);
287 if (!status) {
288 status = new AvailabilityStatus(urls);
289 availability_set_.insert(base::WrapUnique(status));
imcheng 2017/01/17 20:53:17 Do we ever erase from / clear |availability_set_|?
zhaobin 2017/01/18 03:38:57 Done.
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 status->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* status = GetAvailabilityStatus(urls);
297 << GURL(availabilityUrl); 313 if (!status) {
314 DLOG(WARNING) << "Start listening for availability for unknown URLs.";
298 return; 315 return;
299 } 316 }
300 status_it->second->availability_observers.insert(observer); 317
301 UpdateListeningState(status_it->second.get()); 318 status->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* status = GetAvailabilityStatus(urls);
311 << GURL(availabilityUrl); 330 if (!status) {
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 status->availability_observers.erase(observer);
336 for (const auto& availabilityUrl : urls)
337 StopListeningToURL(availabilityUrl);
316 } 338 }
317 339
318 void PresentationDispatcher::setDefaultPresentationUrls( 340 void PresentationDispatcher::setDefaultPresentationUrls(
319 const blink::WebVector<blink::WebURL>& presentationUrls) { 341 const blink::WebVector<blink::WebURL>& presentationUrls) {
320 ConnectToPresentationServiceIfNeeded(); 342 ConnectToPresentationServiceIfNeeded();
321 343
322 std::vector<GURL> urls; 344 std::vector<GURL> urls;
323 for (const auto& url : presentationUrls) 345 for (const auto& url : presentationUrls)
324 urls.push_back(url); 346 urls.push_back(url);
325 347
(...skipping 18 matching lines...) Expand all
344 MessageRequestQueue empty; 366 MessageRequestQueue empty;
345 std::swap(message_request_queue_, empty); 367 std::swap(message_request_queue_, empty);
346 } 368 }
347 369
348 void PresentationDispatcher::OnDestruct() { 370 void PresentationDispatcher::OnDestruct() {
349 delete this; 371 delete this;
350 } 372 }
351 373
352 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url, 374 void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url,
353 bool available) { 375 bool available) {
354 auto status_it = availability_status_.find(url); 376 auto* listening_status = GetListeningStatus(url);
355 if (status_it == availability_status_.end()) 377 if (!listening_status)
356 return; 378 return;
357 AvailabilityStatus* status = status_it->second.get();
358 DCHECK(status);
359 379
360 if (status->listening_state == ListeningState::WAITING) 380 if (listening_status->listening_state == ListeningState::WAITING)
361 status->listening_state = ListeningState::ACTIVE; 381 listening_status->listening_state = ListeningState::ACTIVE;
362 382
363 for (auto* observer : status->availability_observers) 383 auto new_screen_availability = available ? ScreenAvailability::AVAILABLE
364 observer->availabilityChanged(available); 384 : ScreenAvailability::UNAVAILABLE;
385 if (listening_status->last_known_availability == new_screen_availability)
386 return;
365 387
366 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 388 listening_status->last_known_availability = new_screen_availability;
367 !iter.IsAtEnd(); iter.Advance()) { 389
368 iter.GetCurrentValue()->onSuccess(available); 390 for (auto& status : availability_set_) {
391 if (!base::ContainsValue(status->urls, url))
392 continue;
393 auto screen_availability = GetScreenAvailability(status->urls);
imcheng 2017/01/17 20:53:17 nit: blank line above this
zhaobin 2017/01/18 03:38:57 Done.
394 DCHECK(screen_availability == ScreenAvailability::AVAILABLE ||
395 screen_availability == ScreenAvailability::UNAVAILABLE);
396 bool is_available = (screen_availability == ScreenAvailability::AVAILABLE);
397
398 for (auto* observer : status->availability_observers)
399 observer->availabilityChanged(is_available);
400
401 for (AvailabilityCallbacksMap::iterator iter(
402 &status->availability_callbacks);
403 !iter.IsAtEnd(); iter.Advance()) {
404 iter.GetCurrentValue()->onSuccess(is_available);
405 }
406 status->availability_callbacks.Clear();
imcheng 2017/01/17 20:53:17 The original code had some logic to stop listening
zhaobin 2017/01/18 03:38:57 Done.
369 } 407 }
370 status->last_known_availability = available;
371 status->availability_callbacks.Clear();
372 UpdateListeningState(status);
373 } 408 }
374 409
375 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) { 410 void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) {
376 auto status_it = availability_status_.find(url); 411 auto* listening_status = GetListeningStatus(url);
377 if (status_it == availability_status_.end()) 412 if (!listening_status)
378 return; 413 return;
379 AvailabilityStatus* status = status_it->second.get();
380 DCHECK(status);
381 DCHECK(status->listening_state == ListeningState::WAITING);
382 414
383 const blink::WebString& not_supported_error = blink::WebString::fromUTF8( 415 if (listening_status->listening_state == ListeningState::WAITING)
384 "getAvailability() isn't supported at the moment. It can be due to " 416 listening_status->listening_state = ListeningState::ACTIVE;
385 "a permanent or temporary system limitation. It is recommended to " 417
386 "try to blindly start a session in that case."); 418 if (listening_status->last_known_availability ==
387 for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks); 419 ScreenAvailability::UNSUPPORTED)
388 !iter.IsAtEnd(); iter.Advance()) { 420 return;
389 iter.GetCurrentValue()->onError(blink::WebPresentationError( 421
390 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported, 422 listening_status->last_known_availability = ScreenAvailability::UNSUPPORTED;
391 not_supported_error)); 423
424 for (auto& status : availability_set_) {
425 if (!base::ContainsValue(status->urls, url))
426 continue;
427
428 // ScreenAvailabilityNotSupported should be a browser side setting, which
429 // means all urls in PresentationAvailability should report NotSupported.
430 // It is not possible to change listening status from Available or
431 // Unavailable to NotSupported. No need to update observer.
432 auto screen_availability = GetScreenAvailability(status->urls);
433 DCHECK_EQ(screen_availability, ScreenAvailability::UNSUPPORTED);
434
435 const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
imcheng 2017/01/17 20:53:17 nit: put this outside the for-loop.
zhaobin 2017/01/18 03:38:57 Done.
436 "getAvailability() isn't supported at the moment. It can be due to "
437 "a permanent or temporary system limitation. It is recommended to "
438 "try to blindly start a session in that case.");
439 for (AvailabilityCallbacksMap::iterator iter(
440 &status->availability_callbacks);
441 !iter.IsAtEnd(); iter.Advance()) {
442 iter.GetCurrentValue()->onError(blink::WebPresentationError(
443 blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
444 not_supported_error));
445 }
446 status->availability_callbacks.Clear();
447
448 for (const auto& availability_url : status->urls)
449 StopListeningToURL(availability_url);
392 } 450 }
393 status->availability_callbacks.Clear();
394 UpdateListeningState(status);
395 } 451 }
396 452
397 void PresentationDispatcher::OnDefaultSessionStarted( 453 void PresentationDispatcher::OnDefaultSessionStarted(
398 blink::mojom::PresentationSessionInfoPtr session_info) { 454 blink::mojom::PresentationSessionInfoPtr session_info) {
399 if (!controller_) 455 if (!controller_)
400 return; 456 return;
401 457
402 if (!session_info.is_null()) { 458 if (!session_info.is_null()) {
403 presentation_service_->ListenForConnectionMessages(session_info.Clone()); 459 presentation_service_->ListenForConnectionMessages(session_info.Clone());
404 controller_->didStartDefaultSession( 460 controller_->didStartDefaultSession(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 } 548 }
493 549
494 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { 550 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
495 if (presentation_service_.get()) 551 if (presentation_service_.get())
496 return; 552 return;
497 553
498 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_); 554 render_frame()->GetRemoteInterfaces()->GetInterface(&presentation_service_);
499 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind()); 555 presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind());
500 } 556 }
501 557
502 void PresentationDispatcher::UpdateListeningState(AvailabilityStatus* status) { 558 void PresentationDispatcher::StartListeningToURL(const GURL& url) {
503 bool should_listen = !status->availability_callbacks.IsEmpty() || 559 auto* listening_status = GetListeningStatus(url);
504 !status->availability_observers.empty(); 560 if (!listening_status) {
505 bool is_listening = status->listening_state != ListeningState::INACTIVE; 561 listening_status = new ListeningStatus(url);
562 listening_status_.insert(
563 std::make_pair(url, base::WrapUnique(listening_status)));
564 }
506 565
507 if (should_listen == is_listening) 566 // Already listening.
567 if (listening_status->listening_state != ListeningState::INACTIVE)
508 return; 568 return;
509 569
510 ConnectToPresentationServiceIfNeeded(); 570 ConnectToPresentationServiceIfNeeded();
511 if (should_listen) { 571 listening_status->listening_state = ListeningState::WAITING;
512 status->listening_state = ListeningState::WAITING; 572 presentation_service_->ListenForScreenAvailability(url);
513 presentation_service_->ListenForScreenAvailability(status->url); 573 }
514 } else { 574
515 status->listening_state = ListeningState::INACTIVE; 575 void PresentationDispatcher::StopListeningToURL(const GURL& url) {
516 presentation_service_->StopListeningForScreenAvailability(status->url); 576 for (const auto& status : availability_set_) {
577 if (!base::ContainsValue(status->urls, url))
578 continue;
579
580 // URL is still observed by some availability object.
581 if (!status->availability_callbacks.IsEmpty() ||
582 !status->availability_observers.empty())
583 return;
517 } 584 }
585
586 auto* listening_status = GetListeningStatus(url);
587 DCHECK(listening_status);
imcheng 2017/01/17 20:53:17 This will still blow up in release builds. Suggest
zhaobin 2017/01/18 03:38:57 Done.
588
589 if (listening_status->listening_state == ListeningState::INACTIVE)
590 return;
591
592 ConnectToPresentationServiceIfNeeded();
593 listening_status->listening_state = ListeningState::INACTIVE;
594 presentation_service_->StopListeningForScreenAvailability(url);
595 }
596
597 PresentationDispatcher::ListeningStatus*
598 PresentationDispatcher::GetListeningStatus(const GURL& url) {
599 ListeningStatus* status = nullptr;
600 auto status_it = listening_status_.find(url);
601 if (status_it != listening_status_.end())
602 status = status_it->second.get();
603 return status;
604 }
605
606 PresentationDispatcher::AvailabilityStatus*
607 PresentationDispatcher::GetAvailabilityStatus(const std::vector<GURL>& urls) {
608 auto status_it =
609 std::find_if(availability_set_.begin(), availability_set_.end(),
610 [&urls](const std::unique_ptr<AvailabilityStatus>& x) {
611 return x->urls == urls;
612 });
613
614 if (status_it == availability_set_.end())
imcheng 2017/01/17 20:53:17 nit: replace with: return status_it == availabili
zhaobin 2017/01/18 03:38:57 Done.
615 return nullptr;
616
617 return status_it->get();
618 }
619
620 PresentationDispatcher::ScreenAvailability
621 PresentationDispatcher::GetScreenAvailability(const std::vector<GURL>& urls) {
622 std::map<ScreenAvailability, size_t> counters;
623
624 for (const auto& url : urls) {
625 if (!base::ContainsKey(listening_status_, url)) {
626 counters[ScreenAvailability::UNKNOWN]++;
627 } else {
628 auto url_availability = listening_status_[url]->last_known_availability;
629 counters[url_availability]++;
630 }
631 }
632
633 if (counters[ScreenAvailability::AVAILABLE] > 0)
634 return ScreenAvailability::AVAILABLE;
635 if (counters[ScreenAvailability::UNSUPPORTED] > 0)
636 return ScreenAvailability::UNSUPPORTED;
637 if (counters[ScreenAvailability::UNAVAILABLE] > 0)
638 return ScreenAvailability::UNAVAILABLE;
639
640 DCHECK_EQ(counters[ScreenAvailability::UNKNOWN], urls.size());
imcheng 2017/01/17 20:53:17 nit: operator[] contains side effects so we avoid
zhaobin 2017/01/18 03:38:57 Done.
641 return ScreenAvailability::UNKNOWN;
518 } 642 }
519 643
520 PresentationDispatcher::SendMessageRequest::SendMessageRequest( 644 PresentationDispatcher::SendMessageRequest::SendMessageRequest(
521 blink::mojom::PresentationSessionInfoPtr session_info, 645 blink::mojom::PresentationSessionInfoPtr session_info,
522 blink::mojom::ConnectionMessagePtr message) 646 blink::mojom::ConnectionMessagePtr message)
523 : session_info(std::move(session_info)), message(std::move(message)) {} 647 : session_info(std::move(session_info)), message(std::move(message)) {}
524 648
525 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {} 649 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {}
526 650
527 // static 651 // static
(...skipping 30 matching lines...) Expand all
558 682
559 blink::mojom::ConnectionMessagePtr session_message = 683 blink::mojom::ConnectionMessagePtr session_message =
560 blink::mojom::ConnectionMessage::New(); 684 blink::mojom::ConnectionMessage::New();
561 session_message->type = type; 685 session_message->type = type;
562 session_message->data = std::vector<uint8_t>(data, data + length); 686 session_message->data = std::vector<uint8_t>(data, data + length);
563 return new SendMessageRequest(std::move(session_info), 687 return new SendMessageRequest(std::move(session_info),
564 std::move(session_message)); 688 std::move(session_message));
565 } 689 }
566 690
567 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus( 691 PresentationDispatcher::AvailabilityStatus::AvailabilityStatus(
692 const std::vector<GURL>& availability_urls)
693 : urls(availability_urls) {}
694
695 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() {}
696
697 PresentationDispatcher::ListeningStatus::ListeningStatus(
568 const GURL& availability_url) 698 const GURL& availability_url)
569 : url(availability_url), 699 : url(availability_url),
570 last_known_availability(false), 700 last_known_availability(ScreenAvailability::UNKNOWN),
571 listening_state(ListeningState::INACTIVE) {} 701 listening_state(ListeningState::INACTIVE) {}
572 702
573 PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() { 703 PresentationDispatcher::ListeningStatus::~ListeningStatus() {}
574 }
575 704
576 } // namespace content 705 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698