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