1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/renderer/geolocation_dispatcher.h" 6 7#include "content/common/geolocation_messages.h" 8#include "content/renderer/render_view_impl.h" 9#include "third_party/WebKit/public/platform/WebString.h" 10#include "third_party/WebKit/public/web/WebGeolocationPermissionRequest.h" 11#include "third_party/WebKit/public/web/WebGeolocationPermissionRequestManager.h" 12#include "third_party/WebKit/public/web/WebGeolocationClient.h" 13#include "third_party/WebKit/public/web/WebGeolocationPosition.h" 14#include "third_party/WebKit/public/web/WebGeolocationError.h" 15#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 16 17using blink::WebGeolocationController; 18using blink::WebGeolocationError; 19using blink::WebGeolocationPermissionRequest; 20using blink::WebGeolocationPermissionRequestManager; 21using blink::WebGeolocationPosition; 22 23namespace content { 24 25GeolocationDispatcher::GeolocationDispatcher(RenderFrame* render_frame) 26 : RenderFrameObserver(render_frame), 27 pending_permissions_(new WebGeolocationPermissionRequestManager()), 28 enable_high_accuracy_(false), 29 updating_(false) { 30} 31 32GeolocationDispatcher::~GeolocationDispatcher() {} 33 34bool GeolocationDispatcher::OnMessageReceived(const IPC::Message& message) { 35 bool handled = true; 36 IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcher, message) 37 IPC_MESSAGE_HANDLER(GeolocationMsg_PermissionSet, OnPermissionSet) 38 IPC_MESSAGE_HANDLER(GeolocationMsg_PositionUpdated, OnPositionUpdated) 39 IPC_MESSAGE_UNHANDLED(handled = false) 40 IPC_END_MESSAGE_MAP() 41 return handled; 42} 43 44void GeolocationDispatcher::startUpdating() { 45 GURL url; 46 Send(new GeolocationHostMsg_StartUpdating( 47 routing_id(), url, enable_high_accuracy_)); 48 updating_ = true; 49} 50 51void GeolocationDispatcher::stopUpdating() { 52 Send(new GeolocationHostMsg_StopUpdating(routing_id())); 53 updating_ = false; 54} 55 56void GeolocationDispatcher::setEnableHighAccuracy(bool enable_high_accuracy) { 57 // GeolocationController calls setEnableHighAccuracy(true) before 58 // startUpdating in response to the first high-accuracy Geolocation 59 // subscription. When the last high-accuracy Geolocation unsubscribes 60 // it calls setEnableHighAccuracy(false) after stopUpdating. 61 bool has_changed = enable_high_accuracy_ != enable_high_accuracy; 62 enable_high_accuracy_ = enable_high_accuracy; 63 // We have a different accuracy requirement. Request browser to update. 64 if (updating_ && has_changed) 65 startUpdating(); 66} 67 68void GeolocationDispatcher::setController( 69 WebGeolocationController* controller) { 70 controller_.reset(controller); 71} 72 73bool GeolocationDispatcher::lastPosition(WebGeolocationPosition&) { 74 // The latest position is stored in the browser, not the renderer, so we 75 // would have to fetch it synchronously to give a good value here. The 76 // WebCore::GeolocationController already caches the last position it 77 // receives, so there is not much benefit to more position caching here. 78 return false; 79} 80 81// TODO(jknotten): Change the messages to use a security origin, so no 82// conversion is necessary. 83void GeolocationDispatcher::requestPermission( 84 const WebGeolocationPermissionRequest& permissionRequest) { 85 int bridge_id = pending_permissions_->add(permissionRequest); 86 base::string16 origin = permissionRequest.securityOrigin().toString(); 87 Send(new GeolocationHostMsg_RequestPermission( 88 routing_id(), bridge_id, GURL(origin), 89 blink::WebUserGestureIndicator::isProcessingUserGesture())); 90} 91 92// TODO(jknotten): Change the messages to use a security origin, so no 93// conversion is necessary. 94void GeolocationDispatcher::cancelPermissionRequest( 95 const WebGeolocationPermissionRequest& permissionRequest) { 96 int bridge_id; 97 if (!pending_permissions_->remove(permissionRequest, bridge_id)) 98 return; 99 base::string16 origin = permissionRequest.securityOrigin().toString(); 100 Send(new GeolocationHostMsg_CancelPermissionRequest( 101 routing_id(), bridge_id, GURL(origin))); 102} 103 104// Permission for using geolocation has been set. 105void GeolocationDispatcher::OnPermissionSet(int bridge_id, bool is_allowed) { 106 WebGeolocationPermissionRequest permissionRequest; 107 if (!pending_permissions_->remove(bridge_id, permissionRequest)) 108 return; 109 permissionRequest.setIsAllowed(is_allowed); 110} 111 112// We have an updated geolocation position or error code. 113void GeolocationDispatcher::OnPositionUpdated( 114 const Geoposition& geoposition) { 115 // It is possible for the browser process to have queued an update message 116 // before receiving the stop updating message. 117 if (!updating_) 118 return; 119 120 if (geoposition.Validate()) { 121 controller_->positionChanged( 122 WebGeolocationPosition( 123 geoposition.timestamp.ToDoubleT(), 124 geoposition.latitude, geoposition.longitude, 125 geoposition.accuracy, 126 // Lowest point on land is at approximately -400 meters. 127 geoposition.altitude > -10000., 128 geoposition.altitude, 129 geoposition.altitude_accuracy >= 0., 130 geoposition.altitude_accuracy, 131 geoposition.heading >= 0. && geoposition.heading <= 360., 132 geoposition.heading, 133 geoposition.speed >= 0., 134 geoposition.speed)); 135 } else { 136 WebGeolocationError::Error code; 137 switch (geoposition.error_code) { 138 case Geoposition::ERROR_CODE_PERMISSION_DENIED: 139 code = WebGeolocationError::ErrorPermissionDenied; 140 break; 141 case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE: 142 code = WebGeolocationError::ErrorPositionUnavailable; 143 break; 144 default: 145 NOTREACHED() << geoposition.error_code; 146 return; 147 } 148 controller_->errorOccurred( 149 WebGeolocationError( 150 code, blink::WebString::fromUTF8(geoposition.error_message))); 151 } 152} 153 154} // namespace content 155