| OLD | NEW | 
 | (Empty) | 
|    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 #include "device/geolocation/geolocation_provider_impl.h" |  | 
|    6  |  | 
|    7 #include "base/bind.h" |  | 
|    8 #include "base/bind_helpers.h" |  | 
|    9 #include "base/callback.h" |  | 
|   10 #include "base/lazy_instance.h" |  | 
|   11 #include "base/location.h" |  | 
|   12 #include "base/logging.h" |  | 
|   13 #include "base/memory/ptr_util.h" |  | 
|   14 #include "base/memory/singleton.h" |  | 
|   15 #include "base/single_thread_task_runner.h" |  | 
|   16 #include "base/threading/thread_task_runner_handle.h" |  | 
|   17 #include "device/geolocation/geolocation_delegate.h" |  | 
|   18 #include "device/geolocation/location_arbitrator_impl.h" |  | 
|   19  |  | 
|   20 namespace device { |  | 
|   21  |  | 
|   22 namespace { |  | 
|   23 base::LazyInstance<std::unique_ptr<GeolocationDelegate>>::Leaky g_delegate = |  | 
|   24     LAZY_INSTANCE_INITIALIZER; |  | 
|   25 }  // anonymous namespace |  | 
|   26  |  | 
|   27 // static |  | 
|   28 GeolocationProvider* GeolocationProvider::GetInstance() { |  | 
|   29   return GeolocationProviderImpl::GetInstance(); |  | 
|   30 } |  | 
|   31  |  | 
|   32 // static |  | 
|   33 void GeolocationProvider::SetGeolocationDelegate( |  | 
|   34     GeolocationDelegate* delegate) { |  | 
|   35   DCHECK(!g_delegate.Get()); |  | 
|   36   g_delegate.Get().reset(delegate); |  | 
|   37 } |  | 
|   38  |  | 
|   39 std::unique_ptr<GeolocationProvider::Subscription> |  | 
|   40 GeolocationProviderImpl::AddLocationUpdateCallback( |  | 
|   41     const LocationUpdateCallback& callback, |  | 
|   42     bool enable_high_accuracy) { |  | 
|   43   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|   44   std::unique_ptr<GeolocationProvider::Subscription> subscription; |  | 
|   45   if (enable_high_accuracy) { |  | 
|   46     subscription = high_accuracy_callbacks_.Add(callback); |  | 
|   47   } else { |  | 
|   48     subscription = low_accuracy_callbacks_.Add(callback); |  | 
|   49   } |  | 
|   50  |  | 
|   51   OnClientsChanged(); |  | 
|   52   if (position_.Validate() || |  | 
|   53       position_.error_code != Geoposition::ERROR_CODE_NONE) { |  | 
|   54     callback.Run(position_); |  | 
|   55   } |  | 
|   56  |  | 
|   57   return subscription; |  | 
|   58 } |  | 
|   59  |  | 
|   60 void GeolocationProviderImpl::UserDidOptIntoLocationServices() { |  | 
|   61   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|   62   bool was_permission_granted = user_did_opt_into_location_services_; |  | 
|   63   user_did_opt_into_location_services_ = true; |  | 
|   64   if (IsRunning() && !was_permission_granted) |  | 
|   65     InformProvidersPermissionGranted(); |  | 
|   66 } |  | 
|   67  |  | 
|   68 void GeolocationProviderImpl::OverrideLocationForTesting( |  | 
|   69     const Geoposition& position) { |  | 
|   70   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|   71   ignore_location_updates_ = true; |  | 
|   72   NotifyClients(position); |  | 
|   73 } |  | 
|   74  |  | 
|   75 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) { |  | 
|   76   DCHECK(OnGeolocationThread()); |  | 
|   77   // Will be true only in testing. |  | 
|   78   if (ignore_location_updates_) |  | 
|   79     return; |  | 
|   80   main_task_runner_->PostTask( |  | 
|   81       FROM_HERE, base::Bind(&GeolocationProviderImpl::NotifyClients, |  | 
|   82                             base::Unretained(this), position)); |  | 
|   83 } |  | 
|   84  |  | 
|   85 // static |  | 
|   86 GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() { |  | 
|   87   return base::Singleton<GeolocationProviderImpl>::get(); |  | 
|   88 } |  | 
|   89  |  | 
|   90 GeolocationProviderImpl::GeolocationProviderImpl() |  | 
|   91     : base::Thread("Geolocation"), |  | 
|   92       user_did_opt_into_location_services_(false), |  | 
|   93       ignore_location_updates_(false), |  | 
|   94       main_task_runner_(base::ThreadTaskRunnerHandle::Get()) { |  | 
|   95   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|   96   high_accuracy_callbacks_.set_removal_callback( |  | 
|   97       base::Bind(&GeolocationProviderImpl::OnClientsChanged, |  | 
|   98                  base::Unretained(this))); |  | 
|   99   low_accuracy_callbacks_.set_removal_callback( |  | 
|  100       base::Bind(&GeolocationProviderImpl::OnClientsChanged, |  | 
|  101                  base::Unretained(this))); |  | 
|  102 } |  | 
|  103  |  | 
|  104 GeolocationProviderImpl::~GeolocationProviderImpl() { |  | 
|  105   Stop(); |  | 
|  106   DCHECK(!arbitrator_); |  | 
|  107 } |  | 
|  108  |  | 
|  109 bool GeolocationProviderImpl::OnGeolocationThread() const { |  | 
|  110   return task_runner()->BelongsToCurrentThread(); |  | 
|  111 } |  | 
|  112  |  | 
|  113 void GeolocationProviderImpl::OnClientsChanged() { |  | 
|  114   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|  115   base::Closure task; |  | 
|  116   if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) { |  | 
|  117     DCHECK(IsRunning()); |  | 
|  118     if (!ignore_location_updates_) { |  | 
|  119       // We have no more observers, so we clear the cached geoposition so that |  | 
|  120       // when the next observer is added we will not provide a stale position. |  | 
|  121       position_ = Geoposition(); |  | 
|  122     } |  | 
|  123     task = base::Bind(&GeolocationProviderImpl::StopProviders, |  | 
|  124                       base::Unretained(this)); |  | 
|  125   } else { |  | 
|  126     if (!IsRunning()) { |  | 
|  127       Start(); |  | 
|  128       if (user_did_opt_into_location_services_) |  | 
|  129         InformProvidersPermissionGranted(); |  | 
|  130     } |  | 
|  131     // Determine a set of options that satisfies all clients. |  | 
|  132     bool enable_high_accuracy = !high_accuracy_callbacks_.empty(); |  | 
|  133  |  | 
|  134     // Send the current options to the providers as they may have changed. |  | 
|  135     task = base::Bind(&GeolocationProviderImpl::StartProviders, |  | 
|  136                       base::Unretained(this), enable_high_accuracy); |  | 
|  137   } |  | 
|  138  |  | 
|  139   task_runner()->PostTask(FROM_HERE, task); |  | 
|  140 } |  | 
|  141  |  | 
|  142 void GeolocationProviderImpl::StopProviders() { |  | 
|  143   DCHECK(OnGeolocationThread()); |  | 
|  144   DCHECK(arbitrator_); |  | 
|  145   arbitrator_->StopProviders(); |  | 
|  146 } |  | 
|  147  |  | 
|  148 void GeolocationProviderImpl::StartProviders(bool enable_high_accuracy) { |  | 
|  149   DCHECK(OnGeolocationThread()); |  | 
|  150   DCHECK(arbitrator_); |  | 
|  151   arbitrator_->StartProviders(enable_high_accuracy); |  | 
|  152 } |  | 
|  153  |  | 
|  154 void GeolocationProviderImpl::InformProvidersPermissionGranted() { |  | 
|  155   DCHECK(IsRunning()); |  | 
|  156   if (!OnGeolocationThread()) { |  | 
|  157     task_runner()->PostTask( |  | 
|  158         FROM_HERE, |  | 
|  159         base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted, |  | 
|  160                    base::Unretained(this))); |  | 
|  161     return; |  | 
|  162   } |  | 
|  163   DCHECK(OnGeolocationThread()); |  | 
|  164   DCHECK(arbitrator_); |  | 
|  165   arbitrator_->OnPermissionGranted(); |  | 
|  166 } |  | 
|  167  |  | 
|  168 void GeolocationProviderImpl::NotifyClients(const Geoposition& position) { |  | 
|  169   DCHECK(main_task_runner_->BelongsToCurrentThread()); |  | 
|  170   DCHECK(position.Validate() || |  | 
|  171          position.error_code != Geoposition::ERROR_CODE_NONE); |  | 
|  172   position_ = position; |  | 
|  173   high_accuracy_callbacks_.Notify(position_); |  | 
|  174   low_accuracy_callbacks_.Notify(position_); |  | 
|  175 } |  | 
|  176  |  | 
|  177 void GeolocationProviderImpl::Init() { |  | 
|  178   DCHECK(OnGeolocationThread()); |  | 
|  179   DCHECK(!arbitrator_); |  | 
|  180   arbitrator_ = CreateArbitrator(); |  | 
|  181 } |  | 
|  182  |  | 
|  183 void GeolocationProviderImpl::CleanUp() { |  | 
|  184   DCHECK(OnGeolocationThread()); |  | 
|  185   arbitrator_.reset(); |  | 
|  186 } |  | 
|  187  |  | 
|  188 std::unique_ptr<LocationArbitrator> |  | 
|  189 GeolocationProviderImpl::CreateArbitrator() { |  | 
|  190   LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind( |  | 
|  191       &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); |  | 
|  192   // Use the embedder's |g_delegate| or fall back to the default one. |  | 
|  193   if (!g_delegate.Get()) |  | 
|  194     g_delegate.Get().reset(new GeolocationDelegate); |  | 
|  195  |  | 
|  196   return base::WrapUnique( |  | 
|  197       new LocationArbitratorImpl(callback, g_delegate.Get().get())); |  | 
|  198 } |  | 
|  199  |  | 
|  200 }  // namespace device |  | 
| OLD | NEW |