| 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..28123b26759f9c8365bd1af480ff4a260d19badf
|
| --- /dev/null
|
| +++ b/chrome/browser/policy/device_status_location_helper.cc
|
| @@ -0,0 +1,192 @@
|
| +// 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 <string>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/location.h"
|
| +#include "base/logging.h"
|
| +#include "base/string_number_conversions.h"
|
| +#include "base/time.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/prefs/pref_service.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "content/browser/geolocation/geolocation_observer.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;
|
| + int64 timestamp;
|
| + const base::DictionaryValue* location =
|
| + local_state_->GetDictionary(prefs::kDeviceLocation);
|
| + if (location->GetDouble("latitude", &position.latitude) &&
|
| + 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. DestructInternal() reaches the IO thread after any updates queued up for
|
| + // 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) {
|
| + 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
|
|
|