| 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..ac50a40d83621a05d4abd936a3078a186a9d9980 100644
|
| --- a/content/browser/geolocation/geolocation_dispatcher_host.cc
|
| +++ b/content/browser/geolocation/geolocation_dispatcher_host.cc
|
| @@ -66,26 +66,41 @@ 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_;
|
| +
|
| + // Used by Android WebView to support that case that a renderer is in the
|
| + // 'paused' state but not yet using geolocation. If the renderer does start
|
| + // using geolocation while paused, we move from this set into
|
| + // |geolocation_renderers_|. If the renderer doesn't end up wanting to use
|
| + // geolocation while 'paused' then we remove from this set. A renderer id
|
| + // can exist only in this set or |geolocation_renderers_|, never both.
|
| + std::set<int> pending_paused_geolocation_renderers_;
|
| +
|
| // Only set whilst we are registered with the geolocation provider.
|
| GeolocationProviderImpl* geolocation_provider_;
|
|
|
| @@ -108,8 +123,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 +153,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 +211,81 @@ 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 {
|
| + it->second.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;
|
| }
|
| }
|
| +
|
| } // namespace
|
|
|
|
|
|
|