summaryrefslogtreecommitdiffstats
path: root/content/browser/geolocation/wifi_data_provider.cc
blob: 85595f927ab8b43b507eb628df471f7fff94624f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2013 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 "content/browser/geolocation/wifi_data_provider.h"

namespace content {

// static
WifiDataProvider* WifiDataProvider::instance_ = NULL;

// static
WifiDataProvider::ImplFactoryFunction WifiDataProvider::factory_function_ =
    DefaultFactoryFunction;

// static
void WifiDataProvider::SetFactory(ImplFactoryFunction factory_function_in) {
  factory_function_ = factory_function_in;
}

// static
void WifiDataProvider::ResetFactory() {
  factory_function_ = DefaultFactoryFunction;
}

// static
WifiDataProvider* WifiDataProvider::Register(WifiDataUpdateCallback* callback) {
  bool need_to_start_data_provider = false;
  if (!instance_) {
    instance_ = new WifiDataProvider();
    need_to_start_data_provider = true;
  }
  DCHECK(instance_);
  instance_->AddCallback(callback);
  // Start the provider after adding the callback, to avoid any race in
  // it running early.
  if (need_to_start_data_provider)
    instance_->StartDataProvider();
  return instance_;
}

// static
bool WifiDataProvider::Unregister(WifiDataUpdateCallback* callback) {
  DCHECK(instance_);
  DCHECK(instance_->has_callbacks());
  if (!instance_->RemoveCallback(callback)) {
    return false;
  }
  if (!instance_->has_callbacks()) {
    // Must stop the data provider (and any implementation threads) before
    // destroying to avoid any race conditions in access to the provider in
    // the destructor chain.
    instance_->StopDataProvider();
    delete instance_;
    instance_ = NULL;
  }
  return true;
}

WifiDataProviderImplBase::WifiDataProviderImplBase()
    : container_(NULL),
      client_loop_(base::MessageLoop::current()) {
  DCHECK(client_loop_);
}

WifiDataProviderImplBase::~WifiDataProviderImplBase() {
}

void WifiDataProviderImplBase::SetContainer(WifiDataProvider* container) {
  container_ = container;
}

void WifiDataProviderImplBase::AddCallback(WifiDataUpdateCallback* callback) {
  callbacks_.insert(callback);
}

bool WifiDataProviderImplBase::RemoveCallback(
    WifiDataUpdateCallback* callback) {
  return callbacks_.erase(callback) == 1;
}

bool WifiDataProviderImplBase::has_callbacks() const {
  return !callbacks_.empty();
}

void WifiDataProviderImplBase::RunCallbacks() {
  client_loop_->PostTask(FROM_HERE, base::Bind(
      &WifiDataProviderImplBase::DoRunCallbacks,
      this));
}

bool WifiDataProviderImplBase::CalledOnClientThread() const {
  return base::MessageLoop::current() == this->client_loop_;
}

base::MessageLoop* WifiDataProviderImplBase::client_loop() const {
  return client_loop_;
}

void WifiDataProviderImplBase::DoRunCallbacks() {
  // It's possible that all the callbacks (and the container) went away
  // whilst this task was pending. This is fine; the loop will be a no-op.
  CallbackSet::const_iterator iter = callbacks_.begin();
  while (iter != callbacks_.end()) {
    WifiDataUpdateCallback* callback = *iter;
    ++iter;  // Advance iter before running, in case callback unregisters.
    callback->Run(container_);
  }
}

WifiDataProvider::WifiDataProvider() {
  DCHECK(factory_function_);
  impl_ = (*factory_function_)();
  DCHECK(impl_.get());
  impl_->SetContainer(this);
}

WifiDataProvider::~WifiDataProvider() {
  DCHECK(impl_.get());
  impl_->SetContainer(NULL);
}

bool WifiDataProvider::GetData(WifiData* data) {
  return impl_->GetData(data);
}

void WifiDataProvider::AddCallback(WifiDataUpdateCallback* callback) {
  impl_->AddCallback(callback);
}

bool WifiDataProvider::RemoveCallback(WifiDataUpdateCallback* callback) {
  return impl_->RemoveCallback(callback);
}

bool WifiDataProvider::has_callbacks() const {
  return impl_->has_callbacks();
}

void WifiDataProvider::StartDataProvider() {
  impl_->StartDataProvider();
}

void WifiDataProvider::StopDataProvider() {
  impl_->StopDataProvider();
}

}  // namespace content