// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/renderer/geolocation_dispatcher.h" #include "content/common/geolocation_messages.h" #include "content/renderer/render_view_impl.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPermissionRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPermissionRequestManager.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPosition.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" using WebKit::WebGeolocationController; using WebKit::WebGeolocationError; using WebKit::WebGeolocationPermissionRequest; using WebKit::WebGeolocationPermissionRequestManager; using WebKit::WebGeolocationPosition; namespace content { GeolocationDispatcher::GeolocationDispatcher(RenderViewImpl* render_view) : RenderViewObserver(render_view), pending_permissions_(new WebGeolocationPermissionRequestManager()), enable_high_accuracy_(false), updating_(false) { } GeolocationDispatcher::~GeolocationDispatcher() {} bool GeolocationDispatcher::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcher, message) IPC_MESSAGE_HANDLER(GeolocationMsg_PermissionSet, OnPermissionSet) IPC_MESSAGE_HANDLER(GeolocationMsg_PositionUpdated, OnPositionUpdated) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void GeolocationDispatcher::geolocationDestroyed() { controller_.reset(); DCHECK(!updating_); } void GeolocationDispatcher::startUpdating() { GURL url; Send(new GeolocationHostMsg_StartUpdating( routing_id(), url, enable_high_accuracy_)); updating_ = true; } void GeolocationDispatcher::stopUpdating() { Send(new GeolocationHostMsg_StopUpdating(routing_id())); updating_ = false; } void GeolocationDispatcher::setEnableHighAccuracy(bool enable_high_accuracy) { // GeolocationController calls setEnableHighAccuracy(true) before // startUpdating in response to the first high-accuracy Geolocation // subscription. When the last high-accuracy Geolocation unsubscribes // it calls setEnableHighAccuracy(false) after stopUpdating. bool has_changed = enable_high_accuracy_ != enable_high_accuracy; enable_high_accuracy_ = enable_high_accuracy; // We have a different accuracy requirement. Request browser to update. if (updating_ && has_changed) startUpdating(); } void GeolocationDispatcher::setController( WebGeolocationController* controller) { controller_.reset(controller); } bool GeolocationDispatcher::lastPosition(WebGeolocationPosition&) { // The latest position is stored in the browser, not the renderer, so we // would have to fetch it synchronously to give a good value here. The // WebCore::GeolocationController already caches the last position it // receives, so there is not much benefit to more position caching here. return false; } // TODO(jknotten): Change the messages to use a security origin, so no // conversion is necessary. void GeolocationDispatcher::requestPermission( const WebGeolocationPermissionRequest& permissionRequest) { int bridge_id = pending_permissions_->add(permissionRequest); string16 origin = permissionRequest.securityOrigin().toString(); Send(new GeolocationHostMsg_RequestPermission( routing_id(), bridge_id, GURL(origin))); } // TODO(jknotten): Change the messages to use a security origin, so no // conversion is necessary. void GeolocationDispatcher::cancelPermissionRequest( const WebGeolocationPermissionRequest& permissionRequest) { int bridge_id; if (!pending_permissions_->remove(permissionRequest, bridge_id)) return; string16 origin = permissionRequest.securityOrigin().toString(); Send(new GeolocationHostMsg_CancelPermissionRequest( routing_id(), bridge_id, GURL(origin))); } // Permission for using geolocation has been set. void GeolocationDispatcher::OnPermissionSet(int bridge_id, bool is_allowed) { WebGeolocationPermissionRequest permissionRequest; if (!pending_permissions_->remove(bridge_id, permissionRequest)) return; permissionRequest.setIsAllowed(is_allowed); } // We have an updated geolocation position or error code. void GeolocationDispatcher::OnPositionUpdated( const Geoposition& geoposition) { // It is possible for the browser process to have queued an update message // before receiving the stop updating message. if (!updating_) return; if (geoposition.Validate()) { controller_->positionChanged( WebGeolocationPosition( geoposition.timestamp.ToDoubleT(), geoposition.latitude, geoposition.longitude, geoposition.accuracy, // Lowest point on land is at approximately -400 meters. geoposition.altitude > -10000., geoposition.altitude, geoposition.altitude_accuracy >= 0., geoposition.altitude_accuracy, geoposition.heading >= 0. && geoposition.heading <= 360., geoposition.heading, geoposition.speed >= 0., geoposition.speed)); } else { WebGeolocationError::Error code; switch (geoposition.error_code) { case Geoposition::ERROR_CODE_PERMISSION_DENIED: code = WebGeolocationError::ErrorPermissionDenied; break; case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE: code = WebGeolocationError::ErrorPositionUnavailable; break; default: NOTREACHED() << geoposition.error_code; return; } controller_->errorOccurred( WebGeolocationError( code, WebKit::WebString::fromUTF8(geoposition.error_message))); } } } // namespace content