// 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/public/common/geoposition.h" #include "content/renderer/render_view_impl.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebGeolocationPermissionRequest.h" #include "third_party/WebKit/public/web/WebGeolocationPermissionRequestManager.h" #include "third_party/WebKit/public/web/WebGeolocationClient.h" #include "third_party/WebKit/public/web/WebGeolocationPosition.h" #include "third_party/WebKit/public/web/WebGeolocationError.h" #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" using blink::WebGeolocationController; using blink::WebGeolocationError; using blink::WebGeolocationPermissionRequest; using blink::WebGeolocationPermissionRequestManager; using blink::WebGeolocationPosition; namespace content { GeolocationDispatcher::GeolocationDispatcher(RenderFrame* render_frame) : RenderFrameObserver(render_frame), pending_permissions_(new WebGeolocationPermissionRequestManager()), enable_high_accuracy_(false) { } GeolocationDispatcher::~GeolocationDispatcher() {} void GeolocationDispatcher::startUpdating() { if (!geolocation_service_) { render_frame()->GetServiceRegistry()->ConnectToRemoteService( &geolocation_service_); } if (enable_high_accuracy_) geolocation_service_->SetHighAccuracy(true); QueryNextPosition(); } void GeolocationDispatcher::stopUpdating() { geolocation_service_.reset(); } 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 (geolocation_service_ && has_changed) geolocation_service_->SetHighAccuracy(enable_high_accuracy_); } 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) { if (!permission_service_.get()) { render_frame()->GetServiceRegistry()->ConnectToRemoteService( &permission_service_); } int permission_request_id = pending_permissions_->add(permissionRequest); permission_service_->RequestPermission( PERMISSION_NAME_GEOLOCATION, permissionRequest.securityOrigin().toString().utf8(), blink::WebUserGestureIndicator::isProcessingUserGesture(), base::Bind(&GeolocationDispatcher::OnPermissionSet, base::Unretained(this), permission_request_id)); } void GeolocationDispatcher::cancelPermissionRequest( const blink::WebGeolocationPermissionRequest& permissionRequest) { int permission_request_id; pending_permissions_->remove(permissionRequest, permission_request_id); } // Permission for using geolocation has been set. void GeolocationDispatcher::OnPermissionSet( int permission_request_id, PermissionStatus status) { WebGeolocationPermissionRequest permissionRequest; if (!pending_permissions_->remove(permission_request_id, permissionRequest)) return; permissionRequest.setIsAllowed(status == PERMISSION_STATUS_GRANTED); } void GeolocationDispatcher::QueryNextPosition() { DCHECK(geolocation_service_); geolocation_service_->QueryNextPosition( base::Bind(&GeolocationDispatcher::OnPositionUpdate, base::Unretained(this))); } void GeolocationDispatcher::OnPositionUpdate(MojoGeopositionPtr geoposition) { QueryNextPosition(); if (geoposition->valid) { controller_->positionChanged(WebGeolocationPosition( geoposition->timestamp, 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, blink::WebString::fromUTF8(geoposition->error_message))); } } } // namespace content