Index: content/browser/geolocation/geolocation_dispatcher_host.cc |
diff --git a/content/browser/geolocation/geolocation_dispatcher_host.cc b/content/browser/geolocation/geolocation_dispatcher_host.cc |
index 96071c748f5e72d5e00dce006be77a7ee903e730..2f4be16430a2b7788151814d8631953270dfd4ad 100644 |
--- a/content/browser/geolocation/geolocation_dispatcher_host.cc |
+++ b/content/browser/geolocation/geolocation_dispatcher_host.cc |
@@ -54,6 +54,7 @@ class GeolocationDispatcherHostImpl : public GeolocationDispatcherHost { |
// GeolocationDispatcherHost |
virtual bool OnMessageReceived(const IPC::Message& msg, |
bool* msg_was_ok) OVERRIDE; |
+ virtual bool IsGeolocationActive() OVERRIDE; |
private: |
virtual ~GeolocationDispatcherHostImpl(); |
@@ -66,26 +67,34 @@ class GeolocationDispatcherHostImpl : public GeolocationDispatcherHost { |
const GURL& requesting_frame); |
void OnStartUpdating(int render_view_id, |
const GURL& requesting_frame, |
- bool enable_high_accuracy); |
+ bool enable_high_accuracy); |
void OnStopUpdating(int render_view_id); |
+ |
+ virtual void PauseOrResume(int render_view_id, bool should_pause) OVERRIDE; |
+ |
// Updates the |geolocation_provider_| with the currently required update |
- // options, based on |renderer_high_accuracy_|. |
- void RefreshHighAccuracy(); |
+ // options. |
+ void RefreshGeolocationOptions(); |
void OnLocationUpdate(const Geoposition& position); |
int render_process_id_; |
scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; |
- // Iterated when sending location updates to renderer processes. The fan out |
- // to individual bridge IDs happens renderer side, in order to minimize |
- // context switches. |
+ struct RendererGeolocationOptions { |
+ bool high_accuracy; |
+ bool is_paused; |
+ }; |
+ |
+ // Used to keep track of the renderers in this process that are using |
+ // geolocation and the options associated with them. The map is iterated |
+ // when a location update is available and the fan out to individual bridge |
+ // IDs happens renderer side, in order to minimize context switches. |
// Only used on the IO thread. |
- std::set<int> geolocation_renderer_ids_; |
- // Maps renderer_id to whether high accuracy is requested for this particular |
- // bridge. |
- std::map<int, bool> renderer_high_accuracy_; |
+ std::map<int, RendererGeolocationOptions> geolocation_renderers_; |
+ std::set<int> pending_paused_geolocation_renderers_; |
+ |
// Only set whilst we are registered with the geolocation provider. |
GeolocationProviderImpl* geolocation_provider_; |
@@ -108,8 +117,14 @@ GeolocationDispatcherHostImpl::GeolocationDispatcherHostImpl( |
} |
GeolocationDispatcherHostImpl::~GeolocationDispatcherHostImpl() { |
- if (geolocation_provider_) |
- geolocation_provider_->RemoveLocationUpdateCallback(callback_); |
+ if (geolocation_provider_) { |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult( |
+ &GeolocationProvider::RemoveLocationUpdateCallback), |
+ base::Unretained(geolocation_provider_), callback_)); |
+ } |
} |
bool GeolocationDispatcherHostImpl::OnMessageReceived( |
@@ -132,9 +147,11 @@ bool GeolocationDispatcherHostImpl::OnMessageReceived( |
void GeolocationDispatcherHostImpl::OnLocationUpdate( |
const Geoposition& geoposition) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- for (std::set<int>::iterator it = geolocation_renderer_ids_.begin(); |
- it != geolocation_renderer_ids_.end(); ++it) { |
- Send(new GeolocationMsg_PositionUpdated(*it, geoposition)); |
+ for (std::map<int, RendererGeolocationOptions>::iterator it = |
+ geolocation_renderers_.begin(); |
+ it != geolocation_renderers_.end(); ++it) { |
+ if (!(it->second.is_paused)) |
+ Send(new GeolocationMsg_PositionUpdated(it->first, geoposition)); |
} |
} |
@@ -188,47 +205,93 @@ void GeolocationDispatcherHostImpl::OnStartUpdating( |
UMA_HISTOGRAM_BOOLEAN( |
"Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy", |
enable_high_accuracy); |
- if (!geolocation_renderer_ids_.count(render_view_id)) |
- geolocation_renderer_ids_.insert(render_view_id); |
- renderer_high_accuracy_[render_view_id] = enable_high_accuracy; |
- RefreshHighAccuracy(); |
+ std::map<int, RendererGeolocationOptions>::iterator it = |
+ geolocation_renderers_.find(render_view_id); |
+ if (it == geolocation_renderers_.end()) { |
+ bool should_start_paused = false; |
+ if (pending_paused_geolocation_renderers_.erase(render_view_id) == 1) { |
+ should_start_paused = true; |
+ } |
+ RendererGeolocationOptions opts = { |
+ enable_high_accuracy, |
+ should_start_paused |
+ }; |
+ geolocation_renderers_[render_view_id] = opts; |
+ } else { |
+ RendererGeolocationOptions* opts = &(it->second); |
+ opts->high_accuracy = enable_high_accuracy; |
+ } |
+ RefreshGeolocationOptions(); |
} |
void GeolocationDispatcherHostImpl::OnStopUpdating(int render_view_id) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" |
<< render_view_id; |
- if (renderer_high_accuracy_.erase(render_view_id)) |
- RefreshHighAccuracy(); |
- |
- DCHECK_EQ(1U, geolocation_renderer_ids_.count(render_view_id)); |
- geolocation_renderer_ids_.erase(render_view_id); |
+ DCHECK_EQ(1U, geolocation_renderers_.count(render_view_id)); |
+ geolocation_renderers_.erase(render_view_id); |
+ RefreshGeolocationOptions(); |
} |
-void GeolocationDispatcherHostImpl::RefreshHighAccuracy() { |
+void GeolocationDispatcherHostImpl::PauseOrResume(int render_view_id, |
+ bool should_pause) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- if (renderer_high_accuracy_.empty()) { |
- if (geolocation_provider_) { |
- geolocation_provider_->RemoveLocationUpdateCallback(callback_); |
- geolocation_provider_ = NULL; |
+ std::map<int, RendererGeolocationOptions>::iterator it = |
+ geolocation_renderers_.find(render_view_id); |
+ if (it == geolocation_renderers_.end()) { |
+ // This renderer is not using geolocation yet, but if it does before |
+ // we get a call to resume, we should start it up in the paused state. |
+ if (should_pause) { |
+ pending_paused_geolocation_renderers_.insert(render_view_id); |
+ } else { |
+ pending_paused_geolocation_renderers_.erase(render_view_id); |
} |
} else { |
+ RendererGeolocationOptions* opts = &(it->second); |
+ if (opts->is_paused != should_pause) |
+ opts->is_paused = should_pause; |
+ RefreshGeolocationOptions(); |
+ } |
+} |
+ |
+void GeolocationDispatcherHostImpl::RefreshGeolocationOptions() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ |
+ bool needs_updates = false; |
+ bool use_high_accuracy = false; |
+ std::map<int, RendererGeolocationOptions>::const_iterator i = |
+ geolocation_renderers_.begin(); |
+ for (; i != geolocation_renderers_.end(); ++i) { |
+ needs_updates |= !(i->second.is_paused); |
+ use_high_accuracy |= i->second.high_accuracy; |
+ if (needs_updates && use_high_accuracy) |
+ break; |
+ } |
+ if (needs_updates) { |
if (!geolocation_provider_) |
geolocation_provider_ = GeolocationProviderImpl::GetInstance(); |
// Re-add to re-establish our options, in case they changed. |
- bool use_high_accuracy = false; |
- std::map<int, bool>::iterator i = renderer_high_accuracy_.begin(); |
- for (; i != renderer_high_accuracy_.end(); ++i) { |
- if (i->second) { |
- use_high_accuracy = true; |
- break; |
- } |
- } |
geolocation_provider_->AddLocationUpdateCallback( |
callback_, use_high_accuracy); |
+ } else { |
+ if (geolocation_provider_) |
+ geolocation_provider_->RemoveLocationUpdateCallback(callback_); |
+ geolocation_provider_ = NULL; |
} |
} |
+ |
+bool GeolocationDispatcherHostImpl::IsGeolocationActive() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ std::map<int, RendererGeolocationOptions>::const_iterator i = |
+ geolocation_renderers_.begin(); |
+ if (i == geolocation_renderers_.end()) |
+ return false; |
+ |
+ for (; i != geolocation_renderers_.end(); ++i) |
+ if (!(i->second.is_paused)) return true; |
+ return false; |
+} |
} // namespace |