Home | History | Annotate | Download | only in signed_in_devices
      1 // Copyright 2013 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 "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/lazy_instance.h"
     11 #include "base/memory/linked_ptr.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/memory/scoped_vector.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_system.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/sync/glue/device_info.h"
     21 #include "chrome/browser/sync/profile_sync_service.h"
     22 #include "chrome/browser/sync/profile_sync_service_factory.h"
     23 #include "chrome/common/extensions/api/signed_in_devices.h"
     24 #include "content/public/browser/notification_details.h"
     25 #include "content/public/browser/notification_observer.h"
     26 #include "content/public/browser/notification_registrar.h"
     27 #include "content/public/browser/notification_service.h"
     28 #include "content/public/browser/notification_source.h"
     29 #include "extensions/browser/event_router.h"
     30 #include "extensions/common/extension.h"
     31 
     32 using browser_sync::DeviceInfo;
     33 namespace extensions {
     34 
     35 namespace {
     36 void FillDeviceInfo(const DeviceInfo& device_info,
     37                     api::signed_in_devices::DeviceInfo* api_device_info) {
     38   api_device_info->id = device_info.public_id();
     39   api_device_info->name = device_info.client_name();
     40   api_device_info->os = api::signed_in_devices::ParseOS(
     41       device_info.GetOSString());
     42   api_device_info->type = api::signed_in_devices::ParseDeviceType(
     43       device_info.GetDeviceTypeString());
     44   api_device_info->chrome_version = device_info.chrome_version();
     45 }
     46 }  // namespace
     47 
     48 SignedInDevicesChangeObserver::SignedInDevicesChangeObserver(
     49     const std::string& extension_id,
     50     Profile* profile) : extension_id_(extension_id),
     51                         profile_(profile) {
     52   ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
     53   if (pss) {
     54     pss->AddObserverForDeviceInfoChange(this);
     55   }
     56 }
     57 
     58 SignedInDevicesChangeObserver::~SignedInDevicesChangeObserver() {
     59   ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
     60   if (pss) {
     61     pss->RemoveObserverForDeviceInfoChange(this);
     62   }
     63 
     64 }
     65 
     66 void SignedInDevicesChangeObserver::OnDeviceInfoChange() {
     67   // There is a change in the list of devices. Get all devices and send them to
     68   // the listener.
     69   ScopedVector<DeviceInfo> devices = GetAllSignedInDevices(extension_id_,
     70                                                            profile_);
     71 
     72   std::vector<linked_ptr<api::signed_in_devices::DeviceInfo> > args;
     73 
     74   for (ScopedVector<DeviceInfo>::const_iterator it = devices.begin();
     75        it != devices.end();
     76        ++it) {
     77     linked_ptr<api::signed_in_devices::DeviceInfo> api_device =
     78         make_linked_ptr(new api::signed_in_devices::DeviceInfo);
     79     FillDeviceInfo(*(*it), api_device.get());
     80     args.push_back(api_device);
     81   }
     82 
     83   scoped_ptr<base::ListValue> result =
     84       api::signed_in_devices::OnDeviceInfoChange::Create(args);
     85   scoped_ptr<Event> event(new Event(
     86       api::signed_in_devices::OnDeviceInfoChange::kEventName,
     87       result.Pass()));
     88 
     89   event->restrict_to_browser_context = profile_;
     90 
     91   ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
     92       extension_id_, event.Pass());
     93 }
     94 
     95 static base::LazyInstance<ProfileKeyedAPIFactory<SignedInDevicesManager> >
     96 g_factory = LAZY_INSTANCE_INITIALIZER;
     97 
     98 // static
     99 ProfileKeyedAPIFactory<SignedInDevicesManager>*
    100     SignedInDevicesManager::GetFactoryInstance() {
    101   return &g_factory.Get();
    102 }
    103 
    104 SignedInDevicesManager::SignedInDevicesManager()
    105     : profile_(NULL) {}
    106 
    107 SignedInDevicesManager::SignedInDevicesManager(Profile* profile)
    108     : profile_(profile) {
    109   extensions::EventRouter* router = extensions::ExtensionSystem::Get(
    110       profile_)->event_router();
    111 
    112   if (router) {
    113     router->RegisterObserver(
    114         this, api::signed_in_devices::OnDeviceInfoChange::kEventName);
    115   }
    116 
    117   // Register for unload event so we could clear all our listeners when
    118   // extensions have unloaded.
    119   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
    120                  content::Source<Profile>(profile_->GetOriginalProfile()));
    121 }
    122 
    123 SignedInDevicesManager::~SignedInDevicesManager() {}
    124 
    125 void SignedInDevicesManager::OnListenerAdded(
    126     const EventListenerInfo& details) {
    127   for (ScopedVector<SignedInDevicesChangeObserver>::const_iterator it =
    128            change_observers_.begin();
    129            it != change_observers_.end();
    130            ++it) {
    131     if ((*it)->extension_id() == details.extension_id) {
    132       DCHECK(false) <<"OnListenerAded fired twice for same extension";
    133       return;
    134     }
    135   }
    136 
    137   change_observers_.push_back(new SignedInDevicesChangeObserver(
    138       details.extension_id,
    139       profile_));
    140 }
    141 
    142 void SignedInDevicesManager::OnListenerRemoved(
    143     const EventListenerInfo& details) {
    144   RemoveChangeObserverForExtension(details.extension_id);
    145 }
    146 
    147 
    148 void SignedInDevicesManager::RemoveChangeObserverForExtension(
    149     const std::string& extension_id) {
    150   for (ScopedVector<SignedInDevicesChangeObserver>::iterator it =
    151            change_observers_.begin();
    152            it != change_observers_.end();
    153            ++it) {
    154     if ((*it)->extension_id() == extension_id) {
    155       change_observers_.erase(it);
    156       return;
    157     }
    158   }
    159 }
    160 
    161 void SignedInDevicesManager::Observe(
    162     int type,
    163     const content::NotificationSource& source,
    164     const content::NotificationDetails& details) {
    165   DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED);
    166   UnloadedExtensionInfo* reason =
    167       content::Details<UnloadedExtensionInfo>(details).ptr();
    168   RemoveChangeObserverForExtension(reason->extension->id());
    169 }
    170 
    171 }  // namespace extensions
    172 
    173