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// This file implements a mock location provider and the factory functions for
6// various ways of creating it.
7
8#include "content/browser/geolocation/mock_location_provider.h"
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/compiler_specific.h"
13#include "base/logging.h"
14#include "base/memory/weak_ptr.h"
15#include "base/message_loop/message_loop.h"
16#include "base/message_loop/message_loop_proxy.h"
17
18namespace content {
19MockLocationProvider* MockLocationProvider::instance_ = NULL;
20
21MockLocationProvider::MockLocationProvider(MockLocationProvider** self_ref)
22    : state_(STOPPED),
23      is_permission_granted_(false),
24      self_ref_(self_ref),
25      provider_loop_(base::MessageLoopProxy::current()) {
26  CHECK(self_ref_);
27  CHECK(*self_ref_ == NULL);
28  *self_ref_ = this;
29}
30
31MockLocationProvider::~MockLocationProvider() {
32  CHECK(*self_ref_ == this);
33  *self_ref_ = NULL;
34}
35
36void MockLocationProvider::HandlePositionChanged(const Geoposition& position) {
37  if (provider_loop_->BelongsToCurrentThread()) {
38    // The location arbitrator unit tests rely on this method running
39    // synchronously.
40    position_ = position;
41    NotifyCallback(position_);
42  } else {
43    provider_loop_->PostTask(
44        FROM_HERE,
45        base::Bind(&MockLocationProvider::HandlePositionChanged,
46                   base::Unretained(this), position));
47  }
48}
49
50bool MockLocationProvider::StartProvider(bool high_accuracy) {
51  state_ = high_accuracy ? HIGH_ACCURACY : LOW_ACCURACY;
52  return true;
53}
54
55void MockLocationProvider::StopProvider() {
56  state_ = STOPPED;
57}
58
59void MockLocationProvider::GetPosition(Geoposition* position) {
60  *position = position_;
61}
62
63void MockLocationProvider::OnPermissionGranted() {
64  is_permission_granted_ = true;
65}
66
67// Mock location provider that automatically calls back its client at most
68// once, when StartProvider or OnPermissionGranted is called. Use
69// |requires_permission_to_start| to select which event triggers the callback.
70class AutoMockLocationProvider : public MockLocationProvider {
71 public:
72  AutoMockLocationProvider(bool has_valid_location,
73                           bool requires_permission_to_start)
74      : MockLocationProvider(&instance_),
75        weak_factory_(this),
76        requires_permission_to_start_(requires_permission_to_start),
77        listeners_updated_(false) {
78    if (has_valid_location) {
79      position_.accuracy = 3;
80      position_.latitude = 4.3;
81      position_.longitude = -7.8;
82      // Webkit compares the timestamp to wall clock time, so we need it to be
83      // contemporary.
84      position_.timestamp = base::Time::Now();
85    } else {
86      position_.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
87    }
88  }
89  virtual bool StartProvider(bool high_accuracy) OVERRIDE {
90    MockLocationProvider::StartProvider(high_accuracy);
91    if (!requires_permission_to_start_) {
92      UpdateListenersIfNeeded();
93    }
94    return true;
95  }
96
97  virtual void OnPermissionGranted() OVERRIDE {
98    MockLocationProvider::OnPermissionGranted();
99    if (requires_permission_to_start_) {
100      UpdateListenersIfNeeded();
101    }
102  }
103
104  void UpdateListenersIfNeeded() {
105    if (!listeners_updated_) {
106      listeners_updated_ = true;
107      base::MessageLoop::current()->PostTask(
108          FROM_HERE,
109          base::Bind(&MockLocationProvider::HandlePositionChanged,
110                     weak_factory_.GetWeakPtr(),
111                     position_));
112    }
113  }
114
115  base::WeakPtrFactory<MockLocationProvider> weak_factory_;
116  const bool requires_permission_to_start_;
117  bool listeners_updated_;
118};
119
120LocationProvider* NewMockLocationProvider() {
121  return new MockLocationProvider(&MockLocationProvider::instance_);
122}
123
124LocationProvider* NewAutoSuccessMockLocationProvider() {
125  return new AutoMockLocationProvider(true, false);
126}
127
128LocationProvider* NewAutoFailMockLocationProvider() {
129  return new AutoMockLocationProvider(false, false);
130}
131
132LocationProvider* NewAutoSuccessMockNetworkLocationProvider() {
133  return new AutoMockLocationProvider(true, true);
134}
135
136}  // namespace content
137