forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevice_capabilities.h
257 lines (222 loc) · 12 KB
/
device_capabilities.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_BASE_DEVICE_CAPABILITIES_H_
#define CHROMECAST_BASE_DEVICE_CAPABILITIES_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/values.h"
namespace chromecast {
// Device capabilities are a set of features used to determine what operations
// are available on the device. They are identified by a key (string) and a
// value (base::Value). The class serves 2 main purposes:
//
// 1) Provide an interface for updating default capabilities and querying their
// current value. Default capabilities are known to the system beforehand
// and used by modules throughout Chromecast to control behavior of operations.
//
// 2) Store dynamic capabilities. Dynamic capabilities are not known to the
// system beforehand and are introduced by external parties. These capabilites
// are stored and then forwarded to app servers that use them to determine how
// to interact with the device.
//
// Capabilities can be classified as either "public" or "private". Capabilities
// of both types can be used by the Chromecast platform to control internal
// behaviors, but only public capabilities will be advertised to app servers.
// Once a capability is set, it retains its privacy classification permanently;
// attempting to change the privacy of a capability results in an error.
// Private capabilities can only be added by Validators. Calling SetCapability()
// on a path without a Validator will default to setting the capability as
// public.
//
// Thread Safety:
// Observers can be added from any thread. Each Observer is guaranteed to be
// notified on same thread that it was added on and must be removed on the same
// thread that it was added on.
//
// Validators can be registered from any thread. Each Validator's Validate()
// method is guaranteed to be called on same thread that the Validator was
// registered on. The Validator must be unregistered on the same thread
// that it was registered on.
//
// All other methods can be called safely from any thread.
// TODO(esum):
// 1) Add WifiSupported, HotspotSupported, and MultizoneSupported capabilities.
// 2) It's not ideal to have the accessors (BluetoothSupported(), etc.) not
// be valid initially until the capability gets registered. We might want
// to use some kind of builder class to solve this.
class DeviceCapabilities {
public:
class Observer {
public:
// Called when DeviceCapabilities gets written to in any way. |path|
// is full path to capability that has been updated.
virtual void OnCapabilitiesChanged(const std::string& path) = 0;
protected:
virtual ~Observer() {}
};
// When another module attempts to update the value for a capability,
// a manager may want to validate the change or even modify the new value.
// Managers that wish to perform this validation should inherit from the
// Validator class and implement its interface.
class Validator {
public:
Validator(const Validator&) = delete;
Validator& operator=(const Validator&) = delete;
// |path| is full path to capability, which could include paths expanded on
// the capability key that gets registered through the Register() method.
// For example, if a key of "foo" is registered for a Validator, |path|
// could be "foo", "foo.bar", "foo.bar.what", etc. |proposed_value| is new
// value being proposed for |path|. Determines if |proposed_value| is valid
// change for |path|. This method may be asynchronous, but multiple calls
// to it must be handled serially. Returns response through
// SetPublicValidatedValue() or SetPrivateValidatedValue().
virtual void Validate(const std::string& path,
base::Value proposed_value) = 0;
protected:
explicit Validator(DeviceCapabilities* capabilities);
virtual ~Validator() {}
DeviceCapabilities* capabilities() const { return capabilities_; }
// Meant to be called when Validate() has finished. |path| is full path to
// capability. |new_value| is new validated value to be used in
// DeviceCapabilities. This method passes these parameters to
// DeviceCapabilities, where |path| is updated internally to |new_value|.
// TODO(seantopping): Change this interface so that Validators are not the
// only means of accessing private capabilities.
void SetPublicValidatedValue(const std::string& path,
base::Value new_value) const;
void SetPrivateValidatedValue(const std::string& path,
base::Value new_value) const;
private:
DeviceCapabilities* const capabilities_;
};
// Class used to store/own capabilities-related data. It is immutable and
// RefCountedThreadSafe, so client code can freely query it throughout its
// lifetime without worrying about the data getting invalidated in any way.
class Data : public base::RefCountedThreadSafe<Data> {
public:
Data(const Data&) = delete;
Data& operator=(const Data&) = delete;
// Accessor for complete capabilities in dictionary format.
const base::Value& dictionary() const { return dictionary_; }
// Accessor for complete capabilities string in JSON format.
const std::string& json_string() const { return json_string_; }
private:
friend class base::RefCountedThreadSafe<Data>;
// DeviceCapabilities should be the only one responsible for Data
// construction. See CreateData() methods.
friend class DeviceCapabilities;
// Constructs empty dictionary with no capabilities.
Data();
// Uses |dictionary| as capabilities dictionary.
explicit Data(base::Value dictionary);
~Data();
const base::Value dictionary_;
std::string json_string_;
};
// Default Capability keys
static const char kKeyAssistantSupported[];
static const char kKeyBluetoothSupported[];
static const char kKeyDisplaySupported[];
static const char kKeyHiResAudioSupported[];
DeviceCapabilities(const DeviceCapabilities&) = delete;
DeviceCapabilities& operator=(const DeviceCapabilities&) = delete;
// This class should get destroyed after all Validators have been
// unregistered, all Observers have been removed, and the class is no longer
// being accessed.
virtual ~DeviceCapabilities() {}
// Create empty instance with no capabilities. Although the class is not
// singleton, there is meant to be a single instance owned by another module.
// The instance should be created early enough for all managers to register
// themselves, and then live long enough for all managers to unregister.
static std::unique_ptr<DeviceCapabilities> Create();
// Creates an instance where all the default capabilities are initialized
// to a predefined default value, and no Validators are registered. For use
// only in unit tests.
static std::unique_ptr<DeviceCapabilities> CreateForTesting();
// Registers a Validator for a capability. A given key must only be
// registered once, and must be unregistered before calling Register() again.
// If the capability has a value of Dictionary type, |key| must be just
// the capability's top-level key and not include path expansions to levels
// farther down. For example, "foo" is a valid value for |key|, but "foo.bar"
// is not. Note that if "foo.bar" is updated in SetCapability(), the
// Validate() method for "foo"'s Validator will be called, with a |path| of
// "foo.bar". Note that this method does not add or modify the capability.
// To do this, SetCapability() should be called, or Validators can call
// SetPublicValidatedValue() or SetPrivateValidatedValue(). This method is
// synchronous to ensure Validators know exactly when they may start receiving
// validation requests.
virtual void Register(const std::string& key,
Validator* validator) = 0;
// Unregisters Validator for |key|. |validator| argument must match
// |validator| argument that was passed in to Register() for |key|. Note that
// the capability and its value remain untouched. This method is synchronous
// to ensure Validators know exactly when they will stop receiving validation
// requests.
virtual void Unregister(const std::string& key,
const Validator* validator) = 0;
// Gets the Validator currently registered for |key|. Returns nullptr if
// no Validator is registered.
virtual Validator* GetValidator(const std::string& key) const = 0;
// Accessors for default capabilities. Note that the capability must be added
// through SetCapability() (or Set[Private]ValidatedValue() for Validators)
// before accessors are called.
virtual bool AssistantSupported() const = 0;
virtual bool BluetoothSupported() const = 0;
virtual bool DisplaySupported() const = 0;
virtual bool HiResAudioSupported() const = 0;
// Returns a deep copy of the value at |path|. If the capability at |path|
// does not exist, a null scoped_ptr is returned.
virtual base::Value GetCapability(const std::string& path) const = 0;
// Use this method to access dictionary and JSON string. No deep copying is
// performed, so this method is inexpensive. Note that any capability updates
// that occur after GetAllData() has been called will not be reflected in the
// returned scoped_refptr. You can think of this method as taking a snapshot
// of the capabilities when it gets called. All capabilities (those set by
// SetPrivateValidatedValue() and SetPublicValidatedValue()) will be present
// in the returned Data object.
virtual scoped_refptr<Data> GetAllData() const = 0;
// Similar to GetAllData(), but this only returns public capabilities.
virtual scoped_refptr<Data> GetPublicData() const = 0;
// Updates the value at |path| to |proposed_value| if |path| already exists
// and adds new capability if |path| doesn't. Note that if a key has been
// registered that is at the beginning of |path|, then the Validator will be
// used to determine if |proposed_value| is accepted.
// Ex: If "foo" has a Validator registered, a |path| of "foo.bar"
// will cause |proposed_value| to go through the Validator's Validate()
// method. Client code may use the Observer interface to determine the
// ultimate value used.
// This method is asynchronous. By default, this method will classify the new
// value at |path| as a public capability; if a Validator is present, it may
// classify the value as public or private via SetPublicValidatedValue() or
// SetPrivateValidatedValue() respectively.
virtual void SetCapability(const std::string& path,
base::Value proposed_value) = 0;
// Iterates through entries in |dict_value| and calls SetCapability() for
// each one. This method is asynchronous.
virtual void MergeDictionary(const base::Value& dict_value) = 0;
// Adds/removes an observer. It doesn't take the ownership of |observer|.
virtual void AddCapabilitiesObserver(Observer* observer) = 0;
virtual void RemoveCapabilitiesObserver(Observer* observer) = 0;
protected:
DeviceCapabilities() {}
// For derived implementation classes to create Data instances since they do
// not have access to Data constructors.
// Creates empty dictionary with no capabilities.
static scoped_refptr<Data> CreateData();
// Uses |dictionary| as capabilities dictionary.
static scoped_refptr<Data> CreateData(base::Value dictionary);
private:
// Internally update the capability residing at |path| to |new_value|. This
// capability will be visible in GetAllData() and GetPublicData().
virtual void SetPublicValidatedValue(const std::string& path,
base::Value new_value) = 0;
// Similar to SetPublicValidatedValue(), but this capability will only be
// visible in GetAllData().
virtual void SetPrivateValidatedValue(const std::string& path,
base::Value new_value) = 0;
};
} // namespace chromecast
#endif // CHROMECAST_BASE_DEVICE_CAPABILITIES_H_