Home | History | Annotate | Download | only in renderer
      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 WebKit::WebGeolocationController;
     17 using WebKit::WebGeolocationError;
     18 using WebKit::WebGeolocationPermissionRequest;
     19 using WebKit::WebGeolocationPermissionRequestManager;
     20 using WebKit::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   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   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, WebKit::WebString::fromUTF8(geoposition.error_message)));
    154   }
    155 }
    156 
    157 }  // namespace content
    158