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