Index: chrome/browser/policy/device_status_location_helper.cc |
diff --git a/chrome/browser/policy/device_status_location_helper.cc b/chrome/browser/policy/device_status_location_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..99fac1098a7224a7daa5585dbb4d08a2fa1c9821 |
--- /dev/null |
+++ b/chrome/browser/policy/device_status_location_helper.cc |
@@ -0,0 +1,182 @@ |
+// 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 "chrome/browser/policy/device_status_location_helper.h" |
+ |
+#include "base/string_number_conversions.h" |
+#include "base/time.h" |
+#include "chrome/browser/prefs/pref_service.h" |
+#include "chrome/common/pref_names.h" |
+#include "content/browser/geolocation/geolocation_provider.h" |
+#include "content/public/browser/browser_thread.h" |
+ |
+namespace policy { |
+ |
+DeviceStatusLocationHelper::DeviceStatusLocationHelper( |
+ PrefService* local_state) |
+ : local_state_(local_state), |
+ timer_(NULL), |
+ provider_(NULL), |
+ observing_(false) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ Geoposition position; |
+ std::string timestamp_str; |
Joao da Silva
2012/04/20 14:21:09
#include <string>
bartfab (slow)
2012/04/23 09:48:54
Done.
|
+ int64 timestamp; |
+ const base::DictionaryValue* location = |
Joao da Silva
2012/04/20 14:21:09
#include "base/values.h"
bartfab (slow)
2012/04/23 09:48:54
Done.
|
+ local_state_->GetDictionary(prefs::kDeviceLocation); |
+ if (location->GetDouble("latitude", &position.latitude) && |
joth
2012/04/23 10:05:14
a comment would be useful - explaining why the loc
bartfab (slow)
2012/04/23 12:21:28
Done.
|
+ location->GetDouble("longitude", &position.longitude) && |
+ location->GetDouble("altitude", &position.altitude) && |
+ location->GetDouble("accuracy", &position.accuracy) && |
+ location->GetDouble("altitude_accuracy", |
+ &position.altitude_accuracy) && |
+ location->GetDouble("heading", &position.heading) && |
+ location->GetDouble("speed", &position.speed) && |
+ location->GetString("timestamp", ×tamp_str) && |
+ base::StringToInt64(timestamp_str, ×tamp)) { |
+ position.timestamp = base::Time::FromInternalValue(timestamp); |
+ position_ = position; |
+ } |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&DeviceStatusLocationHelper::Init, |
+ base::Unretained(this), |
+ position_)); |
+} |
+ |
+void DeviceStatusLocationHelper::Destruct() { |
+ // This class has a specific shutdown sequence that ensures all classes it |
+ // interfaces with are notified on the appropriate threads and any tasks |
+ // posted to it are processed before destruction. |
+ // |
+ // The shutdown sequence is initiated by calling Destruct() on the UI thread: |
+ // |
+ // 1. Destruct() makes the UI thread ignore any further updates it receives, |
+ // then posts DestructInternal() to the IO thread. |
+ // 2. DestructInteral() reaches the IO thread after any updates queued up for |
Joao da Silva
2012/04/20 14:21:09
nit: DestructInteral -> DestructInternal
bartfab (slow)
2012/04/23 09:48:54
Done.
|
+ // it have been processed. This function destroys the poll timer and |
+ // detaches from the GeolocationProvider so that no further updates can be |
+ // received by the IO thread. Then, it posts DeleteSoon() back to the UI |
+ // thread. |
+ // 3. DeleteSoon() reaches the UI thread after any updates queued for it have |
+ // been processed. At this point, there are no more tasks queued up for |
+ // either of the threads and it is safe for the object to be deleted. |
+ // 4. ~DeviceStatusLocationHelper() is run by DeleteSoon() and the object RIP. |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ local_state_ = NULL; |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&DeviceStatusLocationHelper::DestructInternal, |
+ base::Unretained(this))); |
+} |
+ |
+const Geoposition& DeviceStatusLocationHelper::GetPosition() const { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ return position_; |
+} |
+ |
+// static |
+void DeviceStatusLocationHelper::RegisterPrefs(PrefService* local_state) { |
+ local_state->RegisterDictionaryPref(prefs::kDeviceLocation, |
+ new DictionaryValue); |
+} |
+ |
+void DeviceStatusLocationHelper::OnLocationUpdate(const Geoposition& position) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ if (!position.IsValidFix()) |
+ return; |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&DeviceStatusLocationHelper::ReceiveUpdate, |
+ base::Unretained(this), position)); |
+ StopObserving(); |
+ ScheduleUpdate(position); |
+} |
+ |
+void DeviceStatusLocationHelper::SetGeolocationProviderForTest( |
+ GeolocationProvider* provider) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ DCHECK(!provider_); |
+ provider_ = provider; |
+} |
+ |
+DeviceStatusLocationHelper::~DeviceStatusLocationHelper() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ DCHECK(local_state_ == NULL); |
+ DCHECK(timer_ == NULL); |
+} |
+ |
+void DeviceStatusLocationHelper::Init(const Geoposition& position) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ if (!provider_) |
+ provider_ = GeolocationProvider::GetInstance(); |
+ timer_ = new base::OneShotTimer<DeviceStatusLocationHelper>(); |
+ provider_->OnPermissionGranted(); |
+ ScheduleUpdate(position); |
+} |
+ |
+void DeviceStatusLocationHelper::DestructInternal() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ delete timer_; |
+ timer_ = 0; |
+ StopObserving(); |
+ content::BrowserThread::DeleteSoon(content::BrowserThread::UI, |
+ FROM_HERE, |
+ this); |
+} |
+ |
+void DeviceStatusLocationHelper::ScheduleUpdate(const Geoposition& position) { |
joth
2012/04/23 10:05:14
comment explaining why the timer is needed here wo
bartfab (slow)
2012/04/23 12:21:28
Done.
|
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ if (position.IsValidFix()) { |
+ base::TimeDelta elapsed = base::Time::Now() - position.timestamp; |
+ base::TimeDelta interval = |
+ base::TimeDelta::FromSeconds(kPollIntervalSeconds); |
+ if (elapsed > interval) { |
+ StartObserving(); |
+ } else { |
+ timer_->Start(FROM_HERE, interval - elapsed, this, |
+ &DeviceStatusLocationHelper::StartObserving); |
+ } |
+ } else { |
+ StartObserving(); |
+ } |
+} |
+ |
+void DeviceStatusLocationHelper::StartObserving() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ timer_->Stop(); |
+ provider_->AddObserver(this, GeolocationObserverOptions(true)); |
+ observing_ = true; |
+} |
+ |
+void DeviceStatusLocationHelper::StopObserving() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
+ if (!observing_) |
+ return; |
+ provider_->RemoveObserver(this); |
+ observing_ = false; |
+} |
+ |
+void DeviceStatusLocationHelper::ReceiveUpdate(const Geoposition& position) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ if (!local_state_) |
+ return; |
+ position_ = position; |
+ DictionaryValue location; |
+ location.SetDouble("latitude", position.latitude); |
+ location.SetDouble("longitude", position.longitude); |
+ location.SetDouble("altitude", position.altitude); |
+ location.SetDouble("accuracy", position.accuracy); |
+ location.SetDouble("altitude_accuracy", position.altitude_accuracy); |
+ location.SetDouble("heading", position.heading); |
+ location.SetDouble("speed", position.speed); |
+ location.SetString("timestamp", |
+ base::Int64ToString(position.timestamp.ToInternalValue())); |
+ local_state_->Set(prefs::kDeviceLocation, location); |
+} |
+ |
+} // namespace policy |