• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
FillDeviceInfo(const DeviceInfo & device_info,api::signed_in_devices::DeviceInfo * api_device_info)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 
SignedInDevicesChangeObserver(const std::string & extension_id,Profile * profile)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 
~SignedInDevicesChangeObserver()58 SignedInDevicesChangeObserver::~SignedInDevicesChangeObserver() {
59   ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
60   if (pss) {
61     pss->RemoveObserverForDeviceInfoChange(this);
62   }
63 
64 }
65 
OnDeviceInfoChange()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>*
GetFactoryInstance()100     SignedInDevicesManager::GetFactoryInstance() {
101   return &g_factory.Get();
102 }
103 
SignedInDevicesManager()104 SignedInDevicesManager::SignedInDevicesManager()
105     : profile_(NULL) {}
106 
SignedInDevicesManager(Profile * profile)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 
~SignedInDevicesManager()123 SignedInDevicesManager::~SignedInDevicesManager() {}
124 
OnListenerAdded(const EventListenerInfo & details)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 
OnListenerRemoved(const EventListenerInfo & details)142 void SignedInDevicesManager::OnListenerRemoved(
143     const EventListenerInfo& details) {
144   RemoveChangeObserverForExtension(details.extension_id);
145 }
146 
147 
RemoveChangeObserverForExtension(const std::string & extension_id)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 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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