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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: content/renderer/presentation/presentation_dispatcher.cc
diff --git a/content/renderer/presentation/presentation_dispatcher.cc b/content/renderer/presentation/presentation_dispatcher.cc
index 29e0f0229ffd9ad023675ce58cdd24e3926d2cd4..63950ee76cad3d253e56aa48a80af41fa7a008ea 100644
--- a/content/renderer/presentation/presentation_dispatcher.cc
+++ b/content/renderer/presentation/presentation_dispatcher.cc
@@ -92,7 +92,6 @@ GetWebPresentationConnectionCloseReasonFromMojo(
return blink::WebPresentationConnectionCloseReason::Error;
}
}
-
} // namespace
namespace content {
@@ -262,57 +261,83 @@ void PresentationDispatcher::terminateSession(
void PresentationDispatcher::getAvailability(
const blink::WebVector<blink::WebURL>& availabilityUrls,
- std::unique_ptr<blink::WebPresentationAvailabilityCallbacks> callbacks) {
- // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655.
- const blink::WebURL& availabilityUrl = availabilityUrls[0];
+ std::unique_ptr<blink::WebPresentationAvailabilityCallbacks> callback) {
+ DCHECK(!availabilityUrls.isEmpty());
+
+ std::vector<GURL> urls;
+ for (const auto& availability_url : availabilityUrls)
+ urls.push_back(availability_url);
+
+ auto screen_availability = GetScreenAvailability(urls);
+ // 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.
+ if (screen_availability == ScreenAvailability::UNSUPPORTED) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &blink::WebPresentationAvailabilityCallbacks::onError,
+ base::Passed(&callback),
+ blink::WebPresentationError(
+ blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
+ "Screen availability monitoring not supported")));
+ // Do not listen to urls if we reject the promise.
+ return;
+ }
+
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.
- auto status_it = availability_status_.find(availabilityUrl);
- if (status_it == availability_status_.end()) {
- status = new AvailabilityStatus(availabilityUrl);
- availability_status_[availabilityUrl] = base::WrapUnique(status);
- } else {
- status = status_it->second.get();
+ for (const auto& availability : availability_set_) {
+ if (availability->urls == urls) {
+ status = availability.get();
+ break;
+ }
}
- DCHECK(status);
- if (status->listening_state == ListeningState::ACTIVE) {
+ if (!status) {
+ status = new AvailabilityStatus(urls);
+ 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
+ }
+
+ if (screen_availability != ScreenAvailability::UNKNOWN) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&blink::WebPresentationAvailabilityCallbacks::onSuccess,
- base::Passed(&callbacks), status->last_known_availability));
- return;
+ base::Passed(&callback),
+ screen_availability == ScreenAvailability::AVAILABLE));
+ } else {
+ status->availability_callbacks.Add(std::move(callback));
}
- status->availability_callbacks.Add(std::move(callbacks));
- UpdateListeningState(status);
+ for (const auto& availabilityUrl : urls)
+ StartListening(availabilityUrl);
}
void PresentationDispatcher::startListening(
blink::WebPresentationAvailabilityObserver* observer) {
- // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655.
- const blink::WebURL& availabilityUrl = observer->urls()[0];
- auto status_it = availability_status_.find(availabilityUrl);
- if (status_it == availability_status_.end()) {
- DLOG(WARNING) << "Start listening for availability for unknown URL "
- << GURL(availabilityUrl);
- return;
+ std::vector<GURL> urls;
+ for (const auto& url : observer->urls())
+ urls.push_back(url);
+
+ for (auto& status : availability_set_) {
+ if (status->urls == urls)
+ 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.
}
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.
- status_it->second->availability_observers.insert(observer);
- UpdateListeningState(status_it->second.get());
+
+ for (const auto& availabilityUrl : urls)
+ StartListening(availabilityUrl);
}
void PresentationDispatcher::stopListening(
blink::WebPresentationAvailabilityObserver* observer) {
- // TODO(mfoltz): Pass all URLs to PresentationService. See crbug.com/627655.
- const blink::WebURL& availabilityUrl = observer->urls()[0];
- auto status_it = availability_status_.find(availabilityUrl);
- if (status_it == availability_status_.end()) {
- DLOG(WARNING) << "Stop listening for availability for unknown URL "
- << GURL(availabilityUrl);
- return;
+ std::vector<GURL> urls;
+ for (const auto& url : observer->urls())
+ urls.push_back(url);
+
+ for (auto& status : availability_set_) {
+ if (status->urls == urls)
+ 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.
}
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.
- status_it->second->availability_observers.erase(observer);
- UpdateListeningState(status_it->second.get());
+
+ for (const auto& availabilityUrl : urls)
+ StopListening(availabilityUrl);
}
void PresentationDispatcher::setDefaultPresentationUrls(
@@ -351,47 +376,81 @@ void PresentationDispatcher::OnDestruct() {
void PresentationDispatcher::OnScreenAvailabilityUpdated(const GURL& url,
bool available) {
- auto status_it = availability_status_.find(url);
- if (status_it == availability_status_.end())
+ auto* listening_status = GetListeningStatus(url);
+ if (!listening_status)
return;
- AvailabilityStatus* status = status_it->second.get();
- DCHECK(status);
- if (status->listening_state == ListeningState::WAITING)
- status->listening_state = ListeningState::ACTIVE;
+ if (listening_status->listening_state == ListeningState::WAITING)
+ listening_status->listening_state = ListeningState::ACTIVE;
+
+ auto new_screen_availability = available ? ScreenAvailability::AVAILABLE
+ : ScreenAvailability::UNAVAILABLE;
+ if (listening_status->last_known_availability == new_screen_availability)
+ return;
- for (auto* observer : status->availability_observers)
- observer->availabilityChanged(available);
+ listening_status->last_known_availability = new_screen_availability;
- for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks);
- !iter.IsAtEnd(); iter.Advance()) {
- iter.GetCurrentValue()->onSuccess(available);
+ for (auto& status : availability_set_) {
+ if (!base::ContainsValue(status->urls, url))
+ continue;
+ auto screen_availability = GetScreenAvailability(status->urls);
+ // 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.
+ for (auto* observer : status->availability_observers) {
+ observer->availabilityChanged(screen_availability ==
+ ScreenAvailability::AVAILABLE);
+ }
+
+ for (AvailabilityCallbacksMap::iterator iter(
+ &status->availability_callbacks);
+ !iter.IsAtEnd(); iter.Advance()) {
+ iter.GetCurrentValue()->onSuccess(screen_availability ==
+ ScreenAvailability::AVAILABLE);
+ }
+ status->availability_callbacks.Clear();
}
- status->last_known_availability = available;
- status->availability_callbacks.Clear();
- UpdateListeningState(status);
}
void PresentationDispatcher::OnScreenAvailabilityNotSupported(const GURL& url) {
- auto status_it = availability_status_.find(url);
- if (status_it == availability_status_.end())
+ auto* listening_status = GetListeningStatus(url);
+ if (!listening_status)
return;
- AvailabilityStatus* status = status_it->second.get();
- DCHECK(status);
- DCHECK(status->listening_state == ListeningState::WAITING);
-
- const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
- "getAvailability() isn't supported at the moment. It can be due to "
- "a permanent or temporary system limitation. It is recommended to "
- "try to blindly start a session in that case.");
- for (AvailabilityCallbacksMap::iterator iter(&status->availability_callbacks);
- !iter.IsAtEnd(); iter.Advance()) {
- iter.GetCurrentValue()->onError(blink::WebPresentationError(
- blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
- not_supported_error));
+
+ if (listening_status->listening_state == ListeningState::WAITING)
+ listening_status->listening_state = ListeningState::ACTIVE;
+
+ if (listening_status->last_known_availability ==
+ ScreenAvailability::UNSUPPORTED)
+ return;
+
+ listening_status->last_known_availability = ScreenAvailability::UNSUPPORTED;
+
+ for (auto& status : availability_set_) {
+ if (!base::ContainsValue(status->urls, url))
+ continue;
+
+ // ScreenAvailabilityNotSupported should be a browser side setting, which
+ // means all urls in PresentationAvailability should report NotSupported.
+ // It is not possible to change listening status from Available or
+ // Unavailable to NotSupported. No need to update observer.
+ auto screen_availability = GetScreenAvailability(status->urls);
+ 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
+
+ const blink::WebString& not_supported_error = blink::WebString::fromUTF8(
+ "getAvailability() isn't supported at the moment. It can be due to "
+ "a permanent or temporary system limitation. It is recommended to "
+ "try to blindly start a session in that case.");
+ for (AvailabilityCallbacksMap::iterator iter(
+ &status->availability_callbacks);
+ !iter.IsAtEnd(); iter.Advance()) {
+ iter.GetCurrentValue()->onError(blink::WebPresentationError(
+ blink::WebPresentationError::ErrorTypeAvailabilityNotSupported,
+ not_supported_error));
+ }
+ status->availability_callbacks.Clear();
+
+ for (const auto& availability_url : status->urls)
+ StopListening(availability_url);
}
- status->availability_callbacks.Clear();
- UpdateListeningState(status);
}
void PresentationDispatcher::OnDefaultSessionStarted(
@@ -499,22 +558,80 @@ void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
presentation_service_->SetClient(binding_.CreateInterfacePtrAndBind());
}
-void PresentationDispatcher::UpdateListeningState(AvailabilityStatus* status) {
- bool should_listen = !status->availability_callbacks.IsEmpty() ||
- !status->availability_observers.empty();
- bool is_listening = status->listening_state != ListeningState::INACTIVE;
+void PresentationDispatcher::SetPresentationServiceForTest(
+ blink::mojom::PresentationServicePtr presentation_service) {
+ presentation_service_ = std::move(presentation_service);
+}
+
+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.
+ auto* listening_status = GetListeningStatus(url);
+ if (!listening_status) {
+ listening_status = new ListeningStatus(url);
+ 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.
+ }
- if (should_listen == is_listening)
+ // Already listening.
+ if (listening_status->listening_state != ListeningState::INACTIVE)
return;
ConnectToPresentationServiceIfNeeded();
- if (should_listen) {
- status->listening_state = ListeningState::WAITING;
- presentation_service_->ListenForScreenAvailability(status->url);
- } else {
- status->listening_state = ListeningState::INACTIVE;
- presentation_service_->StopListeningForScreenAvailability(status->url);
+ listening_status->listening_state = ListeningState::WAITING;
+ presentation_service_->ListenForScreenAvailability(url);
+}
+
+void PresentationDispatcher::StopListening(const GURL& url) {
+ for (const auto& status : availability_set_) {
+ if (!base::ContainsValue(status->urls, url))
+ continue;
+
+ // URL is still observed by some availability object.
+ if (!status->availability_callbacks.IsEmpty() ||
+ !status->availability_observers.empty())
+ return;
}
+
+ auto* listening_status = GetListeningStatus(url);
+ 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
+
+ if (listening_status->listening_state == ListeningState::INACTIVE)
+ return;
+
+ ConnectToPresentationServiceIfNeeded();
+ listening_status->listening_state = ListeningState::INACTIVE;
+ presentation_service_->StopListeningForScreenAvailability(url);
+}
+
+PresentationDispatcher::ListeningStatus*
+PresentationDispatcher::GetListeningStatus(const GURL& url) {
+ ListeningStatus* status = nullptr;
+ auto status_it = listening_status_.find(url);
+ if (status_it != listening_status_.end())
+ status = status_it->second.get();
+ return status;
+}
+
+PresentationDispatcher::ScreenAvailability
+PresentationDispatcher::GetScreenAvailability(const std::vector<GURL>& urls) {
+ 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.
+
+ for (const auto& url : urls) {
+ if (!base::ContainsKey(listening_status_, url)) {
+ counters[ScreenAvailability::UNKNOWN]++;
+ } else {
+ auto url_availability = listening_status_[url]->last_known_availability;
+ counters[url_availability]++;
+ }
+ }
+
+ if (counters[ScreenAvailability::AVAILABLE] > 0)
+ return ScreenAvailability::AVAILABLE;
+ if (counters[ScreenAvailability::UNSUPPORTED] > 0)
+ return ScreenAvailability::UNSUPPORTED;
+ if (counters[ScreenAvailability::UNAVAILABLE] > 0)
+ return ScreenAvailability::UNAVAILABLE;
+
+ DCHECK_EQ(counters[ScreenAvailability::UNKNOWN], urls.size());
+ return ScreenAvailability::UNKNOWN;
}
PresentationDispatcher::SendMessageRequest::SendMessageRequest(
@@ -565,12 +682,17 @@ PresentationDispatcher::CreateSendBinaryMessageRequest(
}
PresentationDispatcher::AvailabilityStatus::AvailabilityStatus(
+ const std::vector<GURL>& availability_urls)
+ : urls(availability_urls) {}
+
+PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() {}
+
+PresentationDispatcher::ListeningStatus::ListeningStatus(
const GURL& availability_url)
: url(availability_url),
- last_known_availability(false),
+ last_known_availability(ScreenAvailability::UNKNOWN),
listening_state(ListeningState::INACTIVE) {}
-PresentationDispatcher::AvailabilityStatus::~AvailabilityStatus() {
-}
+PresentationDispatcher::ListeningStatus::~ListeningStatus() {}
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698