Home | History | Annotate | Download | only in device_orientation
      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 "content/browser/device_orientation/provider_impl.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/threading/thread.h"
     14 #include "base/threading/worker_pool.h"
     15 
     16 namespace {
     17 
     18 void DeleteThread(base::Thread* thread) {
     19   delete thread;
     20 }
     21 
     22 }
     23 
     24 namespace content {
     25 
     26 class ProviderImpl::PollingThread : public base::Thread {
     27  public:
     28   PollingThread(const char* name,
     29                 base::WeakPtr<ProviderImpl> provider,
     30                 base::MessageLoop* creator_loop);
     31   virtual ~PollingThread();
     32 
     33   // Method for creating a DataFetcher and starting the polling, if the fetcher
     34   // can provide this type of data.
     35   void Initialize(DataFetcherFactory factory, DeviceData::Type type);
     36 
     37   // Method for adding a type of data to poll for.
     38   void DoAddPollingDataType(DeviceData::Type type);
     39 
     40  private:
     41   // Method for polling a DataFetcher.
     42   void DoPoll();
     43   void ScheduleDoPoll();
     44 
     45   // Schedule a notification to the |provider_| which lives on a different
     46   // thread (|creator_loop_| is its message loop).
     47   void ScheduleDoNotify(const scoped_refptr<const DeviceData>& device_data,
     48                         DeviceData::Type device_data_type);
     49 
     50   enum { kDesiredSamplingIntervalMs = 100 };
     51   base::TimeDelta SamplingInterval() const;
     52 
     53   // The Message Loop on which this object was created.
     54   // Typically the I/O loop, but may be something else during testing.
     55   base::MessageLoop* creator_loop_;
     56 
     57   scoped_ptr<DataFetcher> data_fetcher_;
     58   std::map<DeviceData::Type, scoped_refptr<const DeviceData> >
     59     last_device_data_map_;
     60   std::set<DeviceData::Type> polling_data_types_;
     61 
     62   base::WeakPtr<ProviderImpl> provider_;
     63 };
     64 
     65 ProviderImpl::PollingThread::PollingThread(const char* name,
     66                                            base::WeakPtr<ProviderImpl> provider,
     67                                            base::MessageLoop* creator_loop)
     68     : base::Thread(name), creator_loop_(creator_loop), provider_(provider) {}
     69 
     70 ProviderImpl::PollingThread::~PollingThread() {
     71   Stop();
     72 }
     73 
     74 void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type) {
     75   DCHECK(base::MessageLoop::current() == message_loop());
     76 
     77   polling_data_types_.insert(type);
     78 }
     79 
     80 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory,
     81                                              DeviceData::Type type) {
     82   DCHECK(base::MessageLoop::current() == message_loop());
     83 
     84   if (factory != NULL) {
     85     // Try to use factory to create a fetcher that can provide this type of
     86     // data. If factory creates a fetcher that provides this type of data,
     87     // start polling.
     88     scoped_ptr<DataFetcher> fetcher(factory());
     89 
     90     if (fetcher) {
     91       scoped_refptr<const DeviceData> device_data(fetcher->GetDeviceData(type));
     92       if (device_data.get() != NULL) {
     93         // Pass ownership of fetcher to provider_.
     94         data_fetcher_.swap(fetcher);
     95         last_device_data_map_[type] = device_data;
     96 
     97         // Notify observers.
     98         ScheduleDoNotify(device_data, type);
     99 
    100         // Start polling.
    101         ScheduleDoPoll();
    102         return;
    103       }
    104     }
    105   }
    106 
    107   // When no device data can be provided.
    108   ScheduleDoNotify(NULL, type);
    109 }
    110 
    111 void ProviderImpl::PollingThread::ScheduleDoNotify(
    112     const scoped_refptr<const DeviceData>& device_data,
    113     DeviceData::Type device_data_type) {
    114   DCHECK(base::MessageLoop::current() == message_loop());
    115 
    116   creator_loop_->PostTask(FROM_HERE,
    117                           base::Bind(&ProviderImpl::DoNotify, provider_,
    118                                      device_data, device_data_type));
    119 }
    120 
    121 void ProviderImpl::PollingThread::DoPoll() {
    122   DCHECK(base::MessageLoop::current() == message_loop());
    123 
    124   // Poll the fetcher for each type of data.
    125   typedef std::set<DeviceData::Type>::const_iterator SetIterator;
    126   for (SetIterator i = polling_data_types_.begin();
    127        i != polling_data_types_.end(); ++i) {
    128     DeviceData::Type device_data_type = *i;
    129     scoped_refptr<const DeviceData> device_data(data_fetcher_->GetDeviceData(
    130         device_data_type));
    131 
    132     if (device_data.get() == NULL) {
    133       LOG(ERROR) << "Failed to poll device data fetcher.";
    134       ScheduleDoNotify(NULL, device_data_type);
    135       continue;
    136     }
    137 
    138     const DeviceData* old_data = last_device_data_map_[device_data_type].get();
    139     if (old_data != NULL && !device_data->ShouldFireEvent(old_data))
    140       continue;
    141 
    142     // Update the last device data of this type and notify observers.
    143     last_device_data_map_[device_data_type] = device_data;
    144     ScheduleDoNotify(device_data, device_data_type);
    145   }
    146 
    147   ScheduleDoPoll();
    148 }
    149 
    150 void ProviderImpl::PollingThread::ScheduleDoPoll() {
    151   DCHECK(base::MessageLoop::current() == message_loop());
    152 
    153   message_loop()->PostDelayedTask(
    154       FROM_HERE,
    155       base::Bind(&PollingThread::DoPoll, base::Unretained(this)),
    156       SamplingInterval());
    157 }
    158 
    159 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
    160   DCHECK(base::MessageLoop::current() == message_loop());
    161   DCHECK(data_fetcher_.get());
    162 
    163   // TODO(erg): There used to be unused code here, that called a default
    164   // implementation on the DataFetcherInterface that was never defined. I'm
    165   // removing unused methods from headers.
    166   return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
    167 }
    168 
    169 ProviderImpl::ProviderImpl(DataFetcherFactory factory)
    170     : creator_loop_(base::MessageLoop::current()),
    171       factory_(factory),
    172       weak_factory_(this),
    173       polling_thread_(NULL) {
    174 }
    175 
    176 ProviderImpl::~ProviderImpl() {
    177   Stop();
    178 }
    179 
    180 void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type) {
    181   DCHECK(base::MessageLoop::current() == creator_loop_);
    182 
    183   base::MessageLoop* polling_loop = polling_thread_->message_loop();
    184   polling_loop->PostTask(FROM_HERE,
    185                          base::Bind(&PollingThread::DoAddPollingDataType,
    186                                     base::Unretained(polling_thread_),
    187                                     type));
    188 }
    189 
    190 void ProviderImpl::AddObserver(Observer* observer) {
    191   DCHECK(base::MessageLoop::current() == creator_loop_);
    192 
    193   DeviceData::Type type = observer->device_data_type();
    194 
    195   observers_.insert(observer);
    196   if (observers_.size() == 1)
    197     Start(type);
    198   else {
    199     // Notify observer of most recent notification if one exists.
    200     const DeviceData* last_notification = last_notifications_map_[type].get();
    201     if (last_notification != NULL)
    202       observer->OnDeviceDataUpdate(last_notification, type);
    203   }
    204 
    205   ScheduleDoAddPollingDataType(type);
    206 }
    207 
    208 void ProviderImpl::RemoveObserver(Observer* observer) {
    209   DCHECK(base::MessageLoop::current() == creator_loop_);
    210 
    211   observers_.erase(observer);
    212   if (observers_.empty())
    213     Stop();
    214 }
    215 
    216 void ProviderImpl::Start(DeviceData::Type type) {
    217   DCHECK(base::MessageLoop::current() == creator_loop_);
    218   DCHECK(!polling_thread_);
    219 
    220   polling_thread_ = new PollingThread("Device data polling thread",
    221                                       weak_factory_.GetWeakPtr(),
    222                                       creator_loop_);
    223 #if defined(OS_WIN)
    224   polling_thread_->init_com_with_mta(true);
    225 #endif
    226   if (!polling_thread_->Start()) {
    227     LOG(ERROR) << "Failed to start device data polling thread";
    228     delete polling_thread_;
    229     polling_thread_ = NULL;
    230     return;
    231   }
    232   ScheduleInitializePollingThread(type);
    233 }
    234 
    235 void ProviderImpl::Stop() {
    236   DCHECK(base::MessageLoop::current() == creator_loop_);
    237 
    238   weak_factory_.InvalidateWeakPtrs();
    239   if (polling_thread_) {
    240     polling_thread_->StopSoon();
    241     bool posted = base::WorkerPool::PostTask(
    242         FROM_HERE,
    243         base::Bind(&DeleteThread, base::Unretained(polling_thread_)),
    244         true /* task is slow */);
    245     DCHECK(posted);
    246     polling_thread_ = NULL;
    247   }
    248 }
    249 
    250 void ProviderImpl::ScheduleInitializePollingThread(
    251     DeviceData::Type device_data_type) {
    252   DCHECK(base::MessageLoop::current() == creator_loop_);
    253 
    254   base::MessageLoop* polling_loop = polling_thread_->message_loop();
    255   polling_loop->PostTask(FROM_HERE,
    256                          base::Bind(&PollingThread::Initialize,
    257                                     base::Unretained(polling_thread_),
    258                                     factory_,
    259                                     device_data_type));
    260 }
    261 
    262 void ProviderImpl::DoNotify(const scoped_refptr<const DeviceData>& data,
    263     DeviceData::Type device_data_type) {
    264   DCHECK(base::MessageLoop::current() == creator_loop_);
    265 
    266   // Update last notification of this type.
    267   last_notifications_map_[device_data_type] = data;
    268 
    269   // Notify observers of this type of the new data.
    270   typedef std::set<Observer*>::const_iterator ConstIterator;
    271   for (ConstIterator i = observers_.begin(); i != observers_.end(); ++i) {
    272     if ((*i)->device_data_type() == device_data_type)
    273       (*i)->OnDeviceDataUpdate(data.get(), device_data_type);
    274   }
    275 
    276   if (data.get() == NULL) {
    277     // Notify observers exactly once about failure to provide data.
    278     typedef std::set<Observer*>::iterator Iterator;
    279     Iterator i = observers_.begin();
    280     while (i != observers_.end()) {
    281       Iterator current = i++;
    282       if ((*current)->device_data_type() == device_data_type)
    283         observers_.erase(current);
    284     }
    285 
    286     if (observers_.empty())
    287       Stop();
    288   }
    289 }
    290 
    291 
    292 }  // namespace content
    293