************************* G4 reminder *************************
These new files:

        
c:\MyDocs\Gears1\googleclient\gears\opensource\gears\geolocation\gps_device_wince.cc
        
c:\MyDocs\Gears1\googleclient\gears\opensource\gears\geolocation\gps_location_provider.cc

are missing unit tests.
***************************************************************

Hello andreip,

I'd like you to do a code review.  Please execute
        g4 diff -c 8529424

or point your web browser to
        http://mondrian/8529424

to review the following code:

Change 8529424 by [EMAIL PROTECTED] on 2008/10/08 18:20:50 *pending*

        Factors out callback and reverse geocoding logic from WinCE GPS 
location provider.
        This will allow easier porting to Android and easier testing.
        
        R=andreip
        [EMAIL PROTECTED]
        DELTA=1431  (791 added, 639 deleted, 1 changed)
        OCL=8529424

Affected files ...

... //depot/googleclient/gears/opensource/gears/Makefile#191 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.h#1 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.cc#1
 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.h#1
 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_android.cc#3
 delete
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#12
 delete
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#6
 delete

1431 delta lines: 791 added, 639 deleted, 1 changed

Also consider running:
        g4 lint -c 8529424

which verifies that the changelist doesn't introduce new style violations.

If you can't do the review, please let me know as soon as possible.  During
your review, please ensure that all new code has corresponding unit tests and
that existing unit tests are updated appropriately.  Visit
http://www/eng/code_review.html for more information.

This is a semiautomated message from "g4 mail".  Complaints or suggestions?
Mail [EMAIL PROTECTED]
Change 8529424 by [EMAIL PROTECTED] on 2008/10/08 18:20:50 *pending*

        Factors out callback and reverse geocoding logic from WinCE GPS 
location provider.
        This will allow easier porting to Android and easier testing.

Affected files ...

... //depot/googleclient/gears/opensource/gears/Makefile#191 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.h#1 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.cc#1
 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.h#1
 add
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_android.cc#3
 delete
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#12
 delete
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#6
 delete

==== //depot/googleclient/gears/opensource/gears/Makefile#191 - 
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/Makefile ====
# action=edit type=text
--- googleclient/gears/opensource/gears/Makefile        2008-10-09 
16:55:45.000000000 +0100
+++ googleclient/gears/opensource/gears/Makefile        2008-10-08 
14:54:18.000000000 +0100
@@ -2403,7 +2403,8 @@
                geolocation_db.cc \
                geolocation_db_test.cc \
                geolocation_test.cc \
-               gps_location_provider_wince.cc \
+               gps_device_wince.cc \
+               gps_location_provider.cc \
                location_provider.cc \
                location_provider_pool.cc \
                network_location_provider.cc \
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.cc#1 - 
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/geolocation/gps_device_wince.cc
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/gps_device_wince.cc 
2008-10-09 16:55:29.000000000 +0100
@@ -0,0 +1,281 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// We use the GPS Intermediate Driver to access the GPS. See
+// http://msdn.microsoft.com/en-us/library/ms850332.aspx.
+//
+// Note that the GPS driver may not be enabled by default. To enable it on a
+// WinMo 6 device, you must set the virtual port to be used by the driver.
+// - Go to Start -> Settings.
+// - In the System tab, go to External GPS.
+// - In the Programs tab, set 'GPS Program port' to any unused port.
+// See http://blogs.msdn.com/windowsmobile/archive/2006/06/07/620387.aspx
+// and http://www.expansys-usa.com/ft.aspx?k=100176&page=3.
+//
+// TODO(steveblock): consider adding this information to the Geolocation API
+// documentation so that developers can communicate it to users if appropriate.
+
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#ifdef WINCE
+
+#include "gears/geolocation/gps_device_wince.h"
+
+#include <gpsapi.h>
+#include <service.h>  // For SERVICE_STATE constants
+#include "gears/base/common/stopwatch.h"
+#include "gears/base/common/time_utils_win32.h"  // For 
FiletimeToMilliseconds()
+
+
+// Maximum age of GPS data we'll accept.
+static const int kGpsDataMaximumAgeMilliseconds = 5 * 1000;
+// Maximum time we'll wait to connect to the GPS.
+static const int kMaximumConnectionTimeMilliseconds = 45 * 1000;
+// Maximum time we'll wait for the GPS to acquire a fix.
+static const int kMaximumAcquistionTimeMilliseconds = 5 * 60 *1000;
+
+static const char16 *kFailedToConnectErrorMessage =
+    STRING16(L"Failed to connect to GPS.");
+static const char16 *kFailedToGetFixErrorMessage =
+    STRING16(L"GPS failed to get a position fix.");
+
+// Local function
+// This assumes that position_2 is a good fix.
+static bool PositionsDiffer(const Position &position_1,
+                             const Position &position_2);
+
+GpsDeviceBase *NewGpsDevice(GpsDeviceBase::ListenerInterface *listener) {
+  return new WinceGpsDevice(listener);
+}
+
+WinceGpsDevice::WinceGpsDevice(GpsDeviceBase::ListenerInterface *listener)
+    : GpsDeviceBase(listener) {
+  assert(listener_);
+
+  // Initialise member events.
+  stop_event_.Create(NULL, FALSE, FALSE, NULL);
+
+  // Start the worker thread.
+  Start();
+}
+
+WinceGpsDevice::~WinceGpsDevice() {
+  // Shut down the worker thread.
+  stop_event_.Set();
+  Join();
+}
+
+// Thread implementation
+void WinceGpsDevice::Run() {
+  // Initialise events.
+  CEvent position_update_event;
+  CEvent state_change_event;
+  position_update_event.Create(NULL, FALSE, FALSE, NULL);
+  state_change_event.Create(NULL, FALSE, FALSE, NULL);
+  HANDLE events[] = {stop_event_,
+                     position_update_event,
+                     state_change_event};
+
+  // Connect to GPS.
+  gps_handle_ = GPSOpenDevice(position_update_event,
+                              state_change_event,
+                              NULL,  // Reserved
+                              0);  // Reserved
+  if (gps_handle_ == NULL) {
+    LOG(("WinceGpsDevice::Run() : Failed to open handle to GPS device.\n"));
+    listener_->GpsFatalError(kGeolocationLocationAcquisitionErrorCode,
+                             kFailedToConnectErrorMessage);
+    return;
+  }
+
+  // Wait for updates from the GPS driver. It seems that if GPS is not present
+  // or the driver is disabled we still get callbacks. This isn't very useful
+  // for detecting the fact that there's no GPS available, so we must rely on
+  // timeouts.
+  state_ = STATE_CONNECTING;
+  int64 start_time = GetCurrentTimeMillis();
+  bool shutting_down = false;
+  while (!shutting_down) {
+    DWORD wait_milliseconds;
+    switch (state_) {
+      case STATE_CONNECTING:
+        wait_milliseconds =
+            kMaximumConnectionTimeMilliseconds -
+            static_cast<DWORD>(GetCurrentTimeMillis() - start_time);
+        break;
+      case STATE_ACQUIRING_FIX:
+        wait_milliseconds =
+            kMaximumConnectionTimeMilliseconds +
+            kMaximumAcquistionTimeMilliseconds -
+            static_cast<DWORD>(GetCurrentTimeMillis() - start_time);
+        break;
+      case STATE_FIX_ACQUIRED:
+        wait_milliseconds = INFINITE;
+        break;
+      default:
+        assert(false);
+    }
+ 
+    // It's possible that we were woken up just before the timer expired, in
+    // which case the wait time may now be negative. In this case, set the
+    // timeout to zero so that we wake up immediately and continue as normal.
+    if (wait_milliseconds != INFINITE && wait_milliseconds < 0) {
+      wait_milliseconds = 0;
+    }
+
+    DWORD event_index = WaitForMultipleObjects(ARRAYSIZE(events),
+                                               events,
+                                               false,
+                                               wait_milliseconds);
+    switch (event_index) {
+      case WAIT_OBJECT_0:  // stop_event_
+        shutting_down = true;
+        break;
+      case WAIT_OBJECT_0 + 1:  // position_update_event
+        HandlePositionUpdate();
+        break;
+      case WAIT_OBJECT_0 + 2:  // state_change_event
+        HandleStateChange();
+        break;
+      default:
+        // Wait timed out.
+        assert(wait_milliseconds != INFINITE);
+        switch (state_) {
+          case STATE_CONNECTING:
+            listener_->GpsFatalError(kGeolocationLocationAcquisitionErrorCode,
+                                     kFailedToConnectErrorMessage);
+            break;
+          case STATE_ACQUIRING_FIX:
+            listener_->GpsFatalError(kGeolocationLocationNotFoundErrorCode,
+                                     kFailedToGetFixErrorMessage);
+            break;
+          default:
+            assert(false);
+        }
+        shutting_down = true;
+        break;
+    }
+  }
+
+  if (GPSCloseDevice(gps_handle_) != ERROR_SUCCESS) {
+    LOG(("Failed to close connection to GPS.\n"));
+  }
+}
+
+void WinceGpsDevice::HandlePositionUpdate() {
+  Position new_position;
+
+  GPS_POSITION gps_position = {0};
+  gps_position.dwSize = sizeof(gps_position);
+  gps_position.dwVersion = GPS_VERSION_1;  // The only valid value
+  if (GPSGetPosition(gps_handle_,
+                     &gps_position,
+                     kGpsDataMaximumAgeMilliseconds,
+                     0) == ERROR_SUCCESS) {  // Reserved
+    if ((gps_position.dwValidFields & GPS_VALID_LATITUDE) &&
+        (gps_position.dwValidFields & GPS_VALID_LONGITUDE)) {
+      new_position.latitude = gps_position.dblLatitude;
+      new_position.longitude = gps_position.dblLongitude;
+    }
+
+    if (gps_position.dwValidFields & GPS_VALID_ALTITUDE_WRT_ELLIPSOID) {
+      new_position.altitude = gps_position.flAltitudeWRTEllipsoid;
+    }
+
+    // The GPS Intermediate Driver API does not provide a numerical value for
+    // the postition accuracy. However, we can estimate the accuracy from the
+    // Position Dilution of Precision (PDOP), which describes how well the
+    // geometric configuration of the satellites currently in view lends itself
+    // to getting a high accuracy fix (see
+    // http://en.wikipedia.org/wiki/Dilution_of_precision_(GPS) and
+    // http://www.cgrer.uiowa.edu/cgrer_lab/gps/gpsdefs.html).
+    if (gps_position.dwValidFields & GPS_VALID_POSITION_DILUTION_OF_PRECISION) 
{
+      if (gps_position.flPositionDilutionOfPrecision <= 3) {
+        new_position.accuracy = 1;
+      } else if (gps_position.flPositionDilutionOfPrecision <= 6) {
+        new_position.accuracy = 10;
+      } else if (gps_position.flPositionDilutionOfPrecision <= 8) {
+        new_position.accuracy = 20;
+      } else {
+        new_position.accuracy = 50;
+      }
+    }
+  }
+
+  GPS_DEVICE device_state = {0};
+  device_state.dwSize = sizeof(device_state);
+  device_state.dwVersion = GPS_VERSION_1;  // The only valid value
+  if (GPSGetDeviceState(&device_state) == ERROR_SUCCESS) {
+    if (device_state.ftLastDataReceived.dwHighDateTime != 0 ||
+        device_state.ftLastDataReceived.dwLowDateTime != 0) {
+      new_position.timestamp =
+          FiletimeToMilliseconds(device_state.ftLastDataReceived);
+    }
+  }
+
+  if (!new_position.IsGoodFix()) {
+    return;
+  }
+
+  state_ = STATE_FIX_ACQUIRED;
+
+  MutexLock lock(&position_mutex_);
+  if (PositionsDiffer(position_, new_position)) {
+    position_ = new_position;
+    listener_->GpsPositionUpdateAvailable(position_);
+  }
+}
+
+void WinceGpsDevice::HandleStateChange() {
+  // It seems that if GPS is not present, or the GPS driver is disabled, we get
+  // this callback exactly once, with hardware and driver states
+  // SERVICE_STATE_ON.
+  GPS_DEVICE device_state = {0};
+  device_state.dwSize = sizeof(device_state);
+  device_state.dwVersion = GPS_VERSION_1;  // The only valid value
+  if (GPSGetDeviceState(&device_state) == ERROR_SUCCESS) {
+    if (state_ == STATE_CONNECTING &&
+        (device_state.dwDeviceState == SERVICE_STATE_STARTING_UP ||
+         device_state.dwDeviceState == SERVICE_STATE_ON)) {
+      state_ = STATE_ACQUIRING_FIX;
+    }
+  }
+}
+
+// Local function
+// static
+bool PositionsDiffer(const Position &position_1, const Position &position_2) {
+  assert(position_2.IsGoodFix());
+
+  if (!position_1.IsGoodFix()) {
+    return true;
+  }
+  return position_1.latitude != position_2.latitude ||
+         position_1.longitude != position_2.longitude ||
+         position_1.accuracy != position_2.accuracy ||
+         position_1.altitude != position_2.altitude;
+}
+
+#endif  // WINCE
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_device_wince.h#1 - 
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/geolocation/gps_device_wince.h
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/gps_device_wince.h  
2008-10-09 16:54:00.000000000 +0100
@@ -0,0 +1,76 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines the WinceGpsDevice class, which implements a 
representation
+// of a GPS device on WinCE.
+
+#ifndef GEARS_GEOLOCATION_GPS_DEVICE_WINCE_H__
+#define GEARS_GEOLOCATION_GPS_DEVICE_WINCE_H__
+
+#include "gears/geolocation/gps_location_provider.h"
+
+#include <atlsync.h>  // For CEvent.
+#include "gears/base/common/common.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/thread.h"
+
+class WinceGpsDevice
+    : public GpsDeviceBase,
+      public Thread {
+ public:
+  WinceGpsDevice(GpsDeviceBase::ListenerInterface *listener);
+  virtual ~WinceGpsDevice();
+
+ private:
+  // Thread implementation
+  virtual void Run();
+
+  // Callbacks used to handle updates from the GPS Intermediate Driver library.
+  void HandlePositionUpdate();
+  void HandleStateChange();
+
+  // The current best position estimate and its mutex.
+  Position position_;
+  Mutex position_mutex_;
+
+  // Hanlde to the GPS Intermediate Driver library.
+  HANDLE gps_handle_;
+
+  // Events signalled to the thread that waits for events from the GPS API.
+  CEvent stop_event_;
+
+  // The state of the attempt to get a fix from the GPS. Used for determining
+  // timeouts.
+  typedef enum {
+    STATE_CONNECTING,
+    STATE_ACQUIRING_FIX,
+    STATE_FIX_ACQUIRED,
+  } State;
+  State state_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WinceGpsDevice);
+};
+
+#endif  // GEARS_GEOLOCATION_GPS_DEVICE_WINCE_H__
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.cc#1
 - 
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/geolocation/gps_location_provider.cc
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/gps_location_provider.cc    
2008-10-09 16:18:31.000000000 +0100
@@ -0,0 +1,299 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GPS is only available on WinCE and Android.
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#if defined(WINCE) || defined(ANDROID)
+
+#include "gears/geolocation/gps_location_provider.h"
+
+#include <math.h>  // For fabs()
+#include "gears/base/common/stopwatch.h"
+#include "gears/geolocation/backoff_manager.h"
+
+// Local function
+// This assumes that position_2 is a good fix.
+static bool PositionsDifferSiginificantly(const Position &position_1,
+                                          const Position &position_2);
+
+LocationProviderBase *NewGpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language) {
+  return new GpsLocationProvider(reverse_geocode_url,
+                                 host_name,
+                                 address_language);
+}
+
+
+GpsLocationProvider::GpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language)
+    : reverse_geocode_url_(reverse_geocode_url),
+      host_name_(host_name),
+      address_language_(address_language),
+      is_shutting_down_(false),
+      is_new_reverse_geocode_required_(false),
+      is_reverse_geocode_in_progress_(false),
+      is_listener_update_needed_(false),
+      is_address_requested_(false),
+      reverse_geocoder_(NULL),
+      earliest_geocode_time_(0),
+      gps_device_(NULL) {
+  // Start the worker thread.
+  Start();
+}
+
+GpsLocationProvider::~GpsLocationProvider() {
+  // Shut down the worker thread.
+  status_mutex_.Lock();
+  is_shutting_down_ = true;
+  worker_event_.Signal();
+  status_mutex_.Unlock();
+  Join();
+}
+
+void GpsLocationProvider::RegisterListener(
+    LocationProviderBase::ListenerInterface *listener,
+    bool request_address) {
+  LocationProviderBase::RegisterListener(listener, request_address);
+
+  // Update whether or not we need to request an address.
+  MutexLock status_lock(&status_mutex_);
+  if (request_address) {
+    // Lazily create the reverse geocoder if possible.
+    if (reverse_geocoder_ == NULL && !reverse_geocode_url_.empty()) {
+      reverse_geocoder_.reset(new ReverseGeocoder(reverse_geocode_url_,
+                                                  host_name_,
+                                                  address_language_,
+                                                  this));
+    }
+    // Update the flag only if we have a reverse geocoder.
+    if (reverse_geocoder_.get()) {
+      is_address_requested_ = true;
+    }
+  }
+
+  // Register the listener.
+  LocationProviderBase::RegisterListener(listener, is_address_requested_);
+
+  // If we have a good position but no address and we need one, we should start
+  // a new reverse geocode, unless one is already in progress. If we have a 
good
+  // position and it includes an address if required, we should call back. In
+  // all other cases, do nothing, as the listener will be updated once we have 
a
+  // good position fix or when the current reverse geocode completes.
+  MutexLock position_lock(&position_mutex_);
+  if (position_.IsGoodFix()) {
+    if (is_address_requested_ && !position_.IncludesAddress()) {
+      if (!is_reverse_geocode_in_progress_) {
+        position_to_reverse_geocode_ = position_;
+        is_new_reverse_geocode_required_ = true;
+        worker_event_.Signal();
+      }
+    } else {
+      // We have to use an event so that we call back from a different thread.
+      is_listener_update_needed_ = true;
+      worker_event_.Signal();
+    }
+  }
+}
+
+void GpsLocationProvider::UnregisterListener(
+    LocationProviderBase::ListenerInterface *listener) {
+  assert(listener);
+
+  LocationProviderBase::UnregisterListener(listener);
+
+  // Update whether or not we need to request an address.
+  MutexLock status_lock(&status_mutex_);
+  if (is_address_requested_) {
+    MutexLock listeners_lock(GetListenersMutex());
+    ListenerMap *listeners = GetListeners();
+    for (ListenerMap::const_iterator iter = listeners->begin();
+         iter != listeners->end();
+         iter++) {
+      if (iter->second.first == true) {
+        return;
+      }
+    }
+    is_address_requested_ = false;
+  }
+}
+
+// LocationProviderBase implementation
+void GpsLocationProvider::GetPosition(Position *position) {
+  assert(position);
+  MutexLock lock(&position_mutex_);
+  *position = position_;
+}
+
+// Thread implementation
+void GpsLocationProvider::Run() {
+  // Open the device
+  gps_device_.reset(NewGpsDevice(this));
+
+  int geocode_wait_time;
+  bool is_reverse_geocode_wait_expired;
+
+  while (true) {
+    // Update the minimum wait time for a reverse geocode request.
+    geocode_wait_time =
+        static_cast<int>(earliest_geocode_time_ - GetCurrentTimeMillis());
+
+    // Wait for an event.
+    if (geocode_wait_time > 0) {
+      if (!worker_event_.WaitWithTimeout(geocode_wait_time)) {
+        // Wait timed out.
+        is_reverse_geocode_wait_expired = true;
+      }
+    } else {
+      worker_event_.Wait();
+    }
+
+    MutexLock lock(&status_mutex_);
+
+    if (is_listener_update_needed_) {
+      is_listener_update_needed_ = false;
+      UpdateListeners();
+    }
+
+    // This must come after call to UpdateListeners to handle case of fatal
+    // error.
+    if (is_shutting_down_) {
+      break;
+    }
+
+    if (is_new_reverse_geocode_required_ &&
+        !is_reverse_geocode_in_progress_ &&
+        is_reverse_geocode_wait_expired) {
+      MakeReverseGeocodeRequest();
+    }
+  }
+}
+
+// ReverseGeocoder::ListenerInterface implementation
+void GpsLocationProvider::ReverseGeocodeAvailable(const Position &position,
+                                                  bool server_error) {
+  // Update the earliest next request time for a reverse geocode request.
+  earliest_geocode_time_ =
+      BackoffManager::ReportResponse(reverse_geocode_url_, server_error);
+
+  // Copy only the address, so at to preserve the position if an update has 
been
+  // made since the reverse geocode started.
+  position_mutex_.Lock();
+  position_.address = position.address;
+  position_mutex_.Unlock();
+
+  MutexLock lock(&status_mutex_);
+  is_listener_update_needed_ = true;
+  is_reverse_geocode_in_progress_ = false;
+  worker_event_.Signal();
+}
+
+// GpsDeviceBase::ListenerInterface implementation
+void GpsLocationProvider::GpsFatalError(int code,
+                                        const std::string16 &message) {
+  assert(code > 0);
+
+  // Update the listeners then terminate the worker thread.
+  position_mutex_.Lock();
+  position_.error_code = code;
+  position_.error_message = message;
+  position_mutex_.Unlock();
+
+  MutexLock lock(&status_mutex_);
+  is_listener_update_needed_ = true;
+  is_shutting_down_ = true;
+  worker_event_.Signal();
+}
+
+void GpsLocationProvider::GpsPositionUpdateAvailable(const Position &position) 
{
+  // This should only be called with a new, good position.
+  assert(position.IsGoodFix());
+
+  MutexLock status_lock(&status_mutex_);
+  MutexLock position_lock(&position_mutex_);
+
+  if (PositionsDifferSiginificantly(position_, position) &&
+      is_address_requested_) {
+    // The positions differ significantly and an address was requested. Signal
+    // to the worker that a new reverse geocode is required. Don't update our
+    // best position estimate, because we don't want to change it if we're
+    // currently waiting on a reverse geocode.
+    position_to_reverse_geocode_ = position;
+    is_new_reverse_geocode_required_ = true;
+    worker_event_.Signal();
+  } else {
+    // The position changed, but we don't need a new reverse geocode, so update
+    // our best position estimate but use the exisiting address.
+    Address address = position_.address;
+    position_ = position;
+    position_.address = address;
+    is_listener_update_needed_ = true;
+    worker_event_.Signal();
+  }
+}
+
+void GpsLocationProvider::MakeReverseGeocodeRequest() {
+  BackoffManager::ReportRequest(reverse_geocode_url_);
+
+  // Update the status flags and update our current best position estimate to
+  // the position to be geocoded.
+  // status_mutex_ should already be locked.
+  MutexLock position_lock(&position_mutex_);
+  assert(!is_reverse_geocode_in_progress_);
+  is_new_reverse_geocode_required_ = false;
+  is_reverse_geocode_in_progress_ = true;
+  position_ = position_to_reverse_geocode_;
+  assert(position_.IsGoodFix());
+
+  // We must make all request from the same thread - the run loop.
+  // Note that this will fail if a request is already in progress.
+  assert(reverse_geocoder_.get());
+  if (!reverse_geocoder_->MakeRequest(position_)) {
+    assert(false);
+  }
+}
+
+// Local function
+// static
+bool PositionsDifferSiginificantly(const Position &position_1,
+                                   const Position &position_2) {
+  assert(position_2.IsGoodFix());
+
+  if (!position_1.IsGoodFix()) {
+    return true;
+  }
+  double delta = fabs(position_1.latitude - position_2.latitude) +
+                 fabs(position_1.longitude - position_2.longitude);
+  // Convert to metres. 1 second of arc of latitude (or longitude at the
+  // equator) is 1 nautical mile or 1852m.
+  delta *= 60 * 1852;
+  return delta > 100;
+}
+
+#endif  // defined(WINCE) || defined(ANDROID)
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider.h#1
 - 
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/geolocation/gps_location_provider.h
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/gps_location_provider.h     
2008-10-09 16:55:15.000000000 +0100
@@ -0,0 +1,134 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines the GpsLocationProvider class. This class gets position
+// information from a GPS and uses a network location provider to obtain a
+// reverse-geocoded address where required.
+//
+// It also defines the GpsDeviceBase class, from which the platform-specific
+// GPS device classes inherit.
+
+#ifndef GEARS_GEOLOCATION_GPS_LOCATION_PROVIDER_H__
+#define GEARS_GEOLOCATION_GPS_LOCATION_PROVIDER_H__
+
+#include "gears/base/common/common.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/thread.h"
+#include "gears/geolocation/location_provider.h"
+#include "gears/geolocation/geolocation.h"
+#include "gears/geolocation/reverse_geocoder.h"
+
+class GpsDeviceBase {
+ public:
+  class ListenerInterface {
+   public:
+     // Implmentations should call this method when a fatal error occurs, such
+     // that no further location updates will be possible.
+     virtual void GpsFatalError(int code, const std::string16 &message) = 0;
+     // Implementations should call this method when good position is first
+     // available, and again whenever an updated position is available.
+     virtual void GpsPositionUpdateAvailable(const Position &position) = 0;
+  };
+
+  GpsDeviceBase(ListenerInterface *listener) : listener_(listener) {}
+  virtual ~GpsDeviceBase() {}
+
+ protected:
+  ListenerInterface *listener_;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(GpsDeviceBase);
+};
+
+// GpsDevice factory method.
+GpsDeviceBase *NewGpsDevice(GpsDeviceBase::ListenerInterface *listener);
+
+class GpsLocationProvider
+    : public LocationProviderBase,
+      public Thread,
+      public ReverseGeocoder::ReverseGeocoderListenerInterface,
+      public GpsDeviceBase::ListenerInterface {
+ public:
+   GpsLocationProvider(const std::string16 &reverse_geocode_url,
+                       const std::string16 &host_name,
+                       const std::string16 &address_language);
+  virtual ~GpsLocationProvider();
+
+  // Override LocationProviderBase implementation.
+  virtual void RegisterListener(
+      LocationProviderBase::ListenerInterface *listener,
+      bool request_address);
+  virtual void UnregisterListener(
+      LocationProviderBase::ListenerInterface *listener);
+
+  // LocationProviderBase implementation.
+  virtual void GetPosition(Position *position);
+
+ private:
+  // Thread implementation
+  virtual void Run();
+
+  // ReverseGeocoder::ListenerInterface implementation
+  virtual void ReverseGeocodeAvailable(const Position &position,
+                                       bool server_error);
+
+  // GpsDeviceBase::ListenerInterface implementation
+  virtual void GpsFatalError(int code, const std::string16 &message);
+  virtual void GpsPositionUpdateAvailable(const Position &position);
+
+  void MakeReverseGeocodeRequest();
+
+  // Properties of the GPS location provider.
+  std::string16 reverse_geocode_url_;
+  std::string16 host_name_;
+  std::string16 address_language_;
+
+  // The current best position estimate and its mutex.
+  Position position_;
+  Position position_to_reverse_geocode_;
+
+  Mutex position_mutex_;
+
+  // Event used to signal to the worker thread.
+  Event worker_event_;
+
+  // Status flags
+  bool is_shutting_down_;
+  bool is_new_reverse_geocode_required_;
+  bool is_reverse_geocode_in_progress_;
+  bool is_listener_update_needed_;
+  bool is_address_requested_;
+  Mutex status_mutex_;
+
+  scoped_ptr<ReverseGeocoder> reverse_geocoder_;
+  int64 earliest_geocode_time_;
+
+  // The GPS device itself.
+  scoped_ptr<GpsDeviceBase> gps_device_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GpsLocationProvider);
+};
+
+#endif  // GEARS_GEOLOCATION_GPS_LOCATION_PROVIDER_H__
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_android.cc#3
 - None ====
# action=delete type=text
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#12
 - None ====
# action=delete type=text
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#6
 - None ====
# action=delete type=text

Reply via email to