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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_
12 #include "base/basictypes.h"
13 #include "base/containers/hash_tables.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/threading/thread_checker.h"
18 #include "base/time/time.h"
19 #include "base/timer/timer.h"
20 #include "chrome/browser/extensions/api/dial/dial_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "net/base/network_change_notifier.h"
24 namespace extensions
{
26 // Keeps track of devices that have responded to discovery requests and notifies
27 // the observer with an updated, complete set of active devices. The registry's
28 // observer (i.e., the Dial API) owns the registry instance.
29 class DialRegistry
: public DialService::Observer
,
30 public net::NetworkChangeNotifier::NetworkChangeObserver
{
32 typedef std::vector
<DialDeviceData
> DeviceList
;
35 DIAL_NO_LISTENERS
= 0,
37 DIAL_NETWORK_DISCONNECTED
,
38 DIAL_CELLULAR_NETWORK
,
45 // Methods invoked on the IO thread when a new device is discovered, an
46 // update is triggered by dial.discoverNow or an error occured.
47 virtual void OnDialDeviceEvent(const DeviceList
& devices
) = 0;
48 virtual void OnDialError(DialErrorCode type
) = 0;
51 virtual ~Observer() {}
54 // Create the DIAL registry and pass a reference to allow it to notify on
55 // DIAL device events.
56 DialRegistry(Observer
* dial_api
,
57 const base::TimeDelta
& refresh_interval
,
58 const base::TimeDelta
& expiration
,
59 const size_t max_devices
);
61 ~DialRegistry() override
;
63 // Called by the DIAL API when event listeners are added or removed. The dial
64 // service is started after the first listener is added and stopped after the
65 // last listener is removed.
66 void OnListenerAdded();
67 void OnListenerRemoved();
69 // Called by the DIAL API to try to kickoff a discovery if there is not one
74 // Returns a new instance of the DIAL service. Overridden by tests.
75 virtual DialService
* CreateDialService();
76 virtual void ClearDialService();
78 // Returns the current time. Overridden by tests.
79 virtual base::Time
Now() const;
82 // The DIAL service. Periodic discovery is active when this is not NULL.
83 scoped_ptr
<DialService
> dial_
;
86 typedef base::hash_map
<std::string
, linked_ptr
<DialDeviceData
> >
88 typedef std::map
<std::string
, linked_ptr
<DialDeviceData
> > DeviceByLabelMap
;
90 // DialService::Observer:
91 void OnDiscoveryRequest(DialService
* service
) override
;
92 void OnDeviceDiscovered(DialService
* service
,
93 const DialDeviceData
& device
) override
;
94 void OnDiscoveryFinished(DialService
* service
) override
;
95 void OnError(DialService
* service
,
96 const DialService::DialServiceErrorCode
& code
) override
;
98 // net::NetworkChangeObserver:
99 void OnNetworkChanged(
100 net::NetworkChangeNotifier::ConnectionType type
) override
;
102 // Starts and stops periodic discovery. Periodic discovery is done when there
103 // are registered event listeners.
104 void StartPeriodicDiscovery();
105 void StopPeriodicDiscovery();
107 // Check whether we are in a state ready to discover and dispatch error
108 // notifications if not.
109 bool ReadyToDiscover();
111 // Purge our whole registry. We may need to do this occasionally, e.g. when
112 // the network status changes. Increments the registry generation.
115 // The repeating timer schedules discoveries with this method.
118 // Attempts to add a newly discovered device to the registry. Returns true if
120 bool MaybeAddDevice(const linked_ptr
<DialDeviceData
>& device_data
);
122 // Remove devices from the registry that have expired, i.e. not responded
123 // after some time. Returns true if the registry was modified.
124 bool PruneExpiredDevices();
126 // Returns true if the device has expired and should be removed from the
128 bool IsDeviceExpired(const DialDeviceData
& device
) const;
130 // Notify clients with the current device list if necessary.
131 void MaybeSendEvent();
133 // Returns the next label to use for a newly-seen device.
134 std::string
NextLabel();
136 // The current number of event listeners attached to this registry.
139 // Incremented each time we DoDiscovery().
140 int discovery_generation_
;
142 // Incremented each time we modify the registry of active devices.
143 int registry_generation_
;
145 // The discovery generation associated with the last time we sent an event.
146 // Used to ensure that we generate at least one event per round of discovery.
147 int last_event_discovery_generation_
;
149 // The registry generation associated with the last time we sent an event.
150 // Used to suppress events with duplicate device lists.
151 int last_event_registry_generation_
;
153 // Counter to generate device labels.
156 // Registry parameters
157 base::TimeDelta refresh_interval_delta_
;
158 base::TimeDelta expiration_delta_
;
161 // A map used to track known devices by their device_id.
162 DeviceByIdMap device_by_id_map_
;
164 // A map used to track known devices sorted by label. We iterate over this to
165 // construct the device list sent to API clients.
166 DeviceByLabelMap device_by_label_map_
;
168 // Timer used to manage periodic discovery requests.
169 base::RepeatingTimer
<DialRegistry
> repeating_timer_
;
171 // Interface from which the DIAL API is notified of DIAL device events. the
172 // DIAL API owns this DIAL registry.
173 Observer
* const dial_api_
;
176 base::ThreadChecker thread_checker_
;
178 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestAddRemoveListeners
);
179 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestNoDevicesDiscovered
);
180 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestDevicesDiscovered
);
181 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestDeviceExpires
);
182 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestExpiredDeviceIsRediscovered
);
183 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
,
184 TestRemovingListenerDoesNotClearList
);
185 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
, TestNetworkEventConnectionLost
);
186 FRIEND_TEST_ALL_PREFIXES(DialRegistryTest
,
187 TestNetworkEventConnectionRestored
);
188 DISALLOW_COPY_AND_ASSIGN(DialRegistry
);
191 } // namespace extensions
193 #endif // CHROME_BROWSER_EXTENSIONS_API_DIAL_DIAL_REGISTRY_H_