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/extensions/api/signed_in_devices/signed_in_devices_api.h"
16#include "chrome/browser/extensions/extension_service.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/sync/profile_sync_service.h"
19#include "chrome/browser/sync/profile_sync_service_factory.h"
20#include "chrome/common/extensions/api/signed_in_devices.h"
21#include "components/sync_driver/device_info.h"
22#include "extensions/browser/event_router.h"
23#include "extensions/browser/extension_registry.h"
24#include "extensions/common/extension.h"
25
26using sync_driver::DeviceInfo;
27namespace extensions {
28
29namespace {
30void FillDeviceInfo(const DeviceInfo& device_info,
31                    api::signed_in_devices::DeviceInfo* api_device_info) {
32  api_device_info->id = device_info.public_id();
33  api_device_info->name = device_info.client_name();
34  api_device_info->os = api::signed_in_devices::ParseOS(
35      device_info.GetOSString());
36  api_device_info->type = api::signed_in_devices::ParseDeviceType(
37      device_info.GetDeviceTypeString());
38  api_device_info->chrome_version = device_info.chrome_version();
39}
40}  // namespace
41
42SignedInDevicesChangeObserver::SignedInDevicesChangeObserver(
43    const std::string& extension_id,
44    Profile* profile) : extension_id_(extension_id),
45                        profile_(profile) {
46  ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
47  if (pss && pss->GetDeviceInfoTracker()) {
48    pss->GetDeviceInfoTracker()->AddObserver(this);
49  }
50}
51
52SignedInDevicesChangeObserver::~SignedInDevicesChangeObserver() {
53  ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
54  if (pss && pss->GetDeviceInfoTracker()) {
55    pss->GetDeviceInfoTracker()->RemoveObserver(this);
56  }
57}
58
59void SignedInDevicesChangeObserver::OnDeviceInfoChange() {
60  // There is a change in the list of devices. Get all devices and send them to
61  // the listener.
62  ScopedVector<DeviceInfo> devices = GetAllSignedInDevices(extension_id_,
63                                                           profile_);
64
65  std::vector<linked_ptr<api::signed_in_devices::DeviceInfo> > args;
66
67  for (ScopedVector<DeviceInfo>::const_iterator it = devices.begin();
68       it != devices.end();
69       ++it) {
70    linked_ptr<api::signed_in_devices::DeviceInfo> api_device =
71        make_linked_ptr(new api::signed_in_devices::DeviceInfo);
72    FillDeviceInfo(*(*it), api_device.get());
73    args.push_back(api_device);
74  }
75
76  scoped_ptr<base::ListValue> result =
77      api::signed_in_devices::OnDeviceInfoChange::Create(args);
78  scoped_ptr<Event> event(new Event(
79      api::signed_in_devices::OnDeviceInfoChange::kEventName,
80      result.Pass()));
81
82  event->restrict_to_browser_context = profile_;
83
84  EventRouter::Get(profile_)->DispatchEventToExtension(
85      extension_id_, event.Pass());
86}
87
88static base::LazyInstance<
89    BrowserContextKeyedAPIFactory<SignedInDevicesManager> > g_factory =
90    LAZY_INSTANCE_INITIALIZER;
91
92// static
93BrowserContextKeyedAPIFactory<SignedInDevicesManager>*
94SignedInDevicesManager::GetFactoryInstance() {
95  return g_factory.Pointer();
96}
97
98SignedInDevicesManager::SignedInDevicesManager()
99    : profile_(NULL), extension_registry_observer_(this) {
100}
101
102SignedInDevicesManager::SignedInDevicesManager(content::BrowserContext* context)
103    : profile_(Profile::FromBrowserContext(context)),
104      extension_registry_observer_(this) {
105  extensions::EventRouter* router = extensions::EventRouter::Get(profile_);
106  if (router) {
107    router->RegisterObserver(
108        this, api::signed_in_devices::OnDeviceInfoChange::kEventName);
109  }
110
111  // Register for unload event so we could clear all our listeners when
112  // extensions have unloaded.
113  extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
114}
115
116SignedInDevicesManager::~SignedInDevicesManager() {}
117
118void SignedInDevicesManager::OnListenerAdded(
119    const EventListenerInfo& details) {
120  for (ScopedVector<SignedInDevicesChangeObserver>::const_iterator it =
121           change_observers_.begin();
122           it != change_observers_.end();
123           ++it) {
124    if ((*it)->extension_id() == details.extension_id) {
125      DCHECK(false) <<"OnListenerAded fired twice for same extension";
126      return;
127    }
128  }
129
130  change_observers_.push_back(new SignedInDevicesChangeObserver(
131      details.extension_id,
132      profile_));
133}
134
135void SignedInDevicesManager::OnListenerRemoved(
136    const EventListenerInfo& details) {
137  RemoveChangeObserverForExtension(details.extension_id);
138}
139
140void SignedInDevicesManager::RemoveChangeObserverForExtension(
141    const std::string& extension_id) {
142  for (ScopedVector<SignedInDevicesChangeObserver>::iterator it =
143           change_observers_.begin();
144           it != change_observers_.end();
145           ++it) {
146    if ((*it)->extension_id() == extension_id) {
147      change_observers_.erase(it);
148      return;
149    }
150  }
151}
152
153void SignedInDevicesManager::OnExtensionUnloaded(
154    content::BrowserContext* browser_context,
155    const Extension* extension,
156    UnloadedExtensionInfo::Reason reason) {
157  RemoveChangeObserverForExtension(extension->id());
158}
159
160}  // namespace extensions
161