Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: device/bluetooth/bluetooth_remote_gatt_service_bluez.cc

Issue 1872943002: Add support for local services/characteristics/descriptors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/bluetooth/bluetooth_remote_gatt_service_bluez.h" 5 #include "device/bluetooth/bluetooth_remote_gatt_service_bluez.h"
6 6
7 #include <iostream>
8 #include <iterator>
9
10 #include "base/callback.h"
11 #include "base/callback_forward.h"
7 #include "base/logging.h" 12 #include "base/logging.h"
8 #include "base/strings/stringprintf.h" 13 #include "dbus/property.h"
9 #include "device/bluetooth/bluetooth_adapter_bluez.h" 14 #include "device/bluetooth/bluetooth_adapter_bluez.h"
10 #include "device/bluetooth/bluetooth_device_bluez.h" 15 #include "device/bluetooth/bluetooth_device_bluez.h"
16 #include "device/bluetooth/bluetooth_gatt_characteristic_bluez.h"
17 #include "device/bluetooth/bluetooth_gatt_descriptor_bluez.h"
18 #include "device/bluetooth/bluetooth_gatt_service.h"
11 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_bluez.h" 19 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_bluez.h"
12 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_bluez.h"
13 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h"
14 #include "device/bluetooth/dbus/bluez_dbus_manager.h" 20 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
15 21
16 namespace bluez { 22 namespace bluez {
17 23
18 namespace {
19
20 // TODO(jamuraa) move these to cros_system_api later
21 const char kErrorFailed[] = "org.bluez.Error.Failed";
22 const char kErrorInProgress[] = "org.bluez.Error.InProgress";
23 const char kErrorInvalidValueLength[] = "org.bluez.Error.InvalidValueLength";
24 const char kErrorNotAuthorized[] = "org.bluez.Error.NotAuthorized";
25 const char kErrorNotPaired[] = "org.bluez.Error.NotPaired";
26 const char kErrorNotSupported[] = "org.bluez.Error.NotSupported";
27 const char kErrorNotPermitted[] = "org.bluez.Error.NotPermitted";
28
29 } // namespace
30
31 BluetoothRemoteGattServiceBlueZ::BluetoothRemoteGattServiceBlueZ( 24 BluetoothRemoteGattServiceBlueZ::BluetoothRemoteGattServiceBlueZ(
32 BluetoothAdapterBlueZ* adapter, 25 BluetoothAdapterBlueZ* adapter,
33 BluetoothDeviceBlueZ* device, 26 BluetoothDeviceBlueZ* device,
34 const dbus::ObjectPath& object_path) 27 const dbus::ObjectPath& object_path)
35 : object_path_(object_path), 28 : BluetoothGattServiceBlueZ(adapter, object_path),
36 adapter_(adapter),
37 device_(device), 29 device_(device),
38 discovery_complete_(false), 30 discovery_complete_(false),
39 weak_ptr_factory_(this) { 31 weak_ptr_factory_(this) {
40 VLOG(1) << "Creating remote GATT service with identifier: " 32 VLOG(1) << "Creating remote GATT service with identifier: "
41 << object_path.value() << ", UUID: " << GetUUID().canonical_value(); 33 << object_path.value();
42 DCHECK(adapter_); 34 DCHECK(GetAdapter());
43 35
44 bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver( 36 bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver(
45 this); 37 this);
46 bluez::BluezDBusManager::Get() 38 bluez::BluezDBusManager::Get()
47 ->GetBluetoothGattCharacteristicClient() 39 ->GetBluetoothGattCharacteristicClient()
48 ->AddObserver(this); 40 ->AddObserver(this);
49 41
50 // Add all known GATT characteristics. 42 // Add all known GATT characteristics.
51 const std::vector<dbus::ObjectPath>& gatt_chars = 43 const std::vector<dbus::ObjectPath>& gatt_chars =
52 bluez::BluezDBusManager::Get() 44 bluez::BluezDBusManager::Get()
(...skipping 12 matching lines...) Expand all
65 ->GetBluetoothGattCharacteristicClient() 57 ->GetBluetoothGattCharacteristicClient()
66 ->RemoveObserver(this); 58 ->RemoveObserver(this);
67 59
68 // Clean up all the characteristics. Copy the characteristics list here and 60 // Clean up all the characteristics. Copy the characteristics list here and
69 // clear the original so that when we send GattCharacteristicRemoved(), 61 // clear the original so that when we send GattCharacteristicRemoved(),
70 // GetCharacteristics() returns no characteristics. 62 // GetCharacteristics() returns no characteristics.
71 CharacteristicMap characteristics = characteristics_; 63 CharacteristicMap characteristics = characteristics_;
72 characteristics_.clear(); 64 characteristics_.clear();
73 for (CharacteristicMap::iterator iter = characteristics.begin(); 65 for (CharacteristicMap::iterator iter = characteristics.begin();
74 iter != characteristics.end(); ++iter) { 66 iter != characteristics.end(); ++iter) {
75 DCHECK(adapter_); 67 DCHECK(GetAdapter());
76 adapter_->NotifyGattCharacteristicRemoved(iter->second); 68 GetAdapter()->NotifyGattCharacteristicRemoved(iter->second);
77 69
78 delete iter->second; 70 delete iter->second;
79 } 71 }
80 } 72 }
81 73
82 std::string BluetoothRemoteGattServiceBlueZ::GetIdentifier() const {
83 return object_path_.value();
84 }
85
86 device::BluetoothUUID BluetoothRemoteGattServiceBlueZ::GetUUID() const { 74 device::BluetoothUUID BluetoothRemoteGattServiceBlueZ::GetUUID() const {
87 bluez::BluetoothGattServiceClient::Properties* properties = 75 bluez::BluetoothGattServiceClient::Properties* properties =
88 bluez::BluezDBusManager::Get() 76 bluez::BluezDBusManager::Get()
89 ->GetBluetoothGattServiceClient() 77 ->GetBluetoothGattServiceClient()
90 ->GetProperties(object_path_); 78 ->GetProperties(object_path());
91 DCHECK(properties); 79 DCHECK(properties);
92 return device::BluetoothUUID(properties->uuid.value()); 80 return device::BluetoothUUID(properties->uuid.value());
93 } 81 }
94 82
95 bool BluetoothRemoteGattServiceBlueZ::IsLocal() const { 83 bool BluetoothRemoteGattServiceBlueZ::IsLocal() const {
96 return false; 84 return false;
97 } 85 }
98 86
99 bool BluetoothRemoteGattServiceBlueZ::IsPrimary() const { 87 bool BluetoothRemoteGattServiceBlueZ::IsPrimary() const {
100 bluez::BluetoothGattServiceClient::Properties* properties = 88 bluez::BluetoothGattServiceClient::Properties* properties =
101 bluez::BluezDBusManager::Get() 89 bluez::BluezDBusManager::Get()
102 ->GetBluetoothGattServiceClient() 90 ->GetBluetoothGattServiceClient()
103 ->GetProperties(object_path_); 91 ->GetProperties(object_path());
104 DCHECK(properties); 92 DCHECK(properties);
105 return properties->primary.value(); 93 return properties->primary.value();
106 } 94 }
107 95
108 device::BluetoothDevice* BluetoothRemoteGattServiceBlueZ::GetDevice() const { 96 device::BluetoothDevice* BluetoothRemoteGattServiceBlueZ::GetDevice() const {
109 return device_; 97 return device_;
110 } 98 }
111 99
112 std::vector<device::BluetoothGattCharacteristic*>
113 BluetoothRemoteGattServiceBlueZ::GetCharacteristics() const {
114 std::vector<device::BluetoothGattCharacteristic*> characteristics;
115 for (CharacteristicMap::const_iterator iter = characteristics_.begin();
116 iter != characteristics_.end(); ++iter) {
117 characteristics.push_back(iter->second);
118 }
119 return characteristics;
120 }
121
122 std::vector<device::BluetoothGattService*>
123 BluetoothRemoteGattServiceBlueZ::GetIncludedServices() const {
124 // TODO(armansito): Return the actual included services here.
125 return std::vector<device::BluetoothGattService*>();
126 }
127
128 device::BluetoothGattCharacteristic*
129 BluetoothRemoteGattServiceBlueZ::GetCharacteristic(
130 const std::string& identifier) const {
131 CharacteristicMap::const_iterator iter =
132 characteristics_.find(dbus::ObjectPath(identifier));
133 if (iter == characteristics_.end())
134 return NULL;
135 return iter->second;
136 }
137
138 bool BluetoothRemoteGattServiceBlueZ::AddCharacteristic( 100 bool BluetoothRemoteGattServiceBlueZ::AddCharacteristic(
139 device::BluetoothGattCharacteristic* characteristic) { 101 device::BluetoothGattCharacteristic* characteristic) {
140 VLOG(1) << "Characteristics cannot be added to a remote GATT service."; 102 VLOG(1) << "Characteristics cannot be added to a remote GATT service.";
141 return false; 103 return false;
142 } 104 }
143 105
144 bool BluetoothRemoteGattServiceBlueZ::AddIncludedService( 106 bool BluetoothRemoteGattServiceBlueZ::AddIncludedService(
145 device::BluetoothGattService* service) { 107 device::BluetoothGattService* service) {
146 VLOG(1) << "Included services cannot be added to a remote GATT service."; 108 VLOG(1) << "Included services cannot be added to a remote GATT service.";
147 return false; 109 return false;
148 } 110 }
149 111
150 void BluetoothRemoteGattServiceBlueZ::Register( 112 void BluetoothRemoteGattServiceBlueZ::Register(
151 const base::Closure& callback, 113 const base::Closure& callback,
152 const ErrorCallback& error_callback) { 114 const ErrorCallback& error_callback) {
153 VLOG(1) << "A remote GATT service cannot be registered."; 115 VLOG(1) << "A remote GATT service cannot be registered.";
154 error_callback.Run(); 116 error_callback.Run(GATT_ERROR_NOT_SUPPORTED);
155 } 117 }
156 118
157 void BluetoothRemoteGattServiceBlueZ::Unregister( 119 void BluetoothRemoteGattServiceBlueZ::Unregister(
158 const base::Closure& callback, 120 const base::Closure& callback,
159 const ErrorCallback& error_callback) { 121 const ErrorCallback& error_callback) {
160 VLOG(1) << "A remote GATT service cannot be unregistered."; 122 VLOG(1) << "A remote GATT service cannot be unregistered.";
161 error_callback.Run(); 123 error_callback.Run(GATT_ERROR_NOT_SUPPORTED);
162 }
163
164 // static
165 device::BluetoothGattService::GattErrorCode
166 BluetoothRemoteGattServiceBlueZ::DBusErrorToServiceError(
167 std::string error_name) {
168 device::BluetoothGattService::GattErrorCode code = GATT_ERROR_UNKNOWN;
169 if (error_name == kErrorFailed) {
170 code = GATT_ERROR_FAILED;
171 } else if (error_name == kErrorInProgress) {
172 code = GATT_ERROR_IN_PROGRESS;
173 } else if (error_name == kErrorInvalidValueLength) {
174 code = GATT_ERROR_INVALID_LENGTH;
175 } else if (error_name == kErrorNotPermitted) {
176 code = GATT_ERROR_NOT_PERMITTED;
177 } else if (error_name == kErrorNotAuthorized) {
178 code = GATT_ERROR_NOT_AUTHORIZED;
179 } else if (error_name == kErrorNotPaired) {
180 code = GATT_ERROR_NOT_PAIRED;
181 } else if (error_name == kErrorNotSupported) {
182 code = GATT_ERROR_NOT_SUPPORTED;
183 }
184 return code;
185 }
186
187 BluetoothAdapterBlueZ* BluetoothRemoteGattServiceBlueZ::GetAdapter() const {
188 return adapter_;
189 } 124 }
190 125
191 void BluetoothRemoteGattServiceBlueZ::NotifyServiceChanged() { 126 void BluetoothRemoteGattServiceBlueZ::NotifyServiceChanged() {
192 // Don't send service changed unless we know that all characteristics have 127 // Don't send service changed unless we know that all characteristics have
193 // already been discovered. This is to prevent spammy events before sending 128 // already been discovered. This is to prevent spammy events before sending
194 // out the first Gatt 129 // out the first Gatt
195 if (!discovery_complete_) 130 if (!discovery_complete_)
196 return; 131 return;
197 132
198 DCHECK(adapter_); 133 DCHECK(GetAdapter());
199 adapter_->NotifyGattServiceChanged(this); 134 GetAdapter()->NotifyGattServiceChanged(this);
200 } 135 }
201 136
202 void BluetoothRemoteGattServiceBlueZ::NotifyDescriptorAddedOrRemoved( 137 void BluetoothRemoteGattServiceBlueZ::NotifyDescriptorAddedOrRemoved(
203 BluetoothRemoteGattCharacteristicBlueZ* characteristic, 138 BluetoothRemoteGattCharacteristicBlueZ* characteristic,
204 BluetoothRemoteGattDescriptorBlueZ* descriptor, 139 BluetoothGattDescriptorBlueZ* descriptor,
205 bool added) { 140 bool added) {
206 DCHECK(characteristic->GetService() == this); 141 DCHECK(characteristic->GetService() == this);
207 DCHECK(descriptor->GetCharacteristic() == characteristic); 142 DCHECK(descriptor->GetCharacteristic() == characteristic);
208 DCHECK(adapter_); 143 DCHECK(GetAdapter());
209 144
210 if (added) { 145 if (added) {
211 adapter_->NotifyGattDescriptorAdded(descriptor); 146 GetAdapter()->NotifyGattDescriptorAdded(descriptor);
212 return; 147 return;
213 } 148 }
214 149
215 adapter_->NotifyGattDescriptorRemoved(descriptor); 150 GetAdapter()->NotifyGattDescriptorRemoved(descriptor);
216 } 151 }
217 152
218 void BluetoothRemoteGattServiceBlueZ::NotifyDescriptorValueChanged( 153 void BluetoothRemoteGattServiceBlueZ::NotifyDescriptorValueChanged(
219 BluetoothRemoteGattCharacteristicBlueZ* characteristic, 154 BluetoothRemoteGattCharacteristicBlueZ* characteristic,
220 BluetoothRemoteGattDescriptorBlueZ* descriptor, 155 BluetoothGattDescriptorBlueZ* descriptor,
221 const std::vector<uint8_t>& value) { 156 const std::vector<uint8_t>& value) {
222 DCHECK(characteristic->GetService() == this); 157 DCHECK(characteristic->GetService() == this);
223 DCHECK(descriptor->GetCharacteristic() == characteristic); 158 DCHECK(descriptor->GetCharacteristic() == characteristic);
224 DCHECK(adapter_); 159 DCHECK(GetAdapter());
225 adapter_->NotifyGattDescriptorValueChanged(descriptor, value); 160 GetAdapter()->NotifyGattDescriptorValueChanged(descriptor, value);
226 } 161 }
227 162
228 void BluetoothRemoteGattServiceBlueZ::GattServicePropertyChanged( 163 void BluetoothRemoteGattServiceBlueZ::GattServicePropertyChanged(
229 const dbus::ObjectPath& object_path, 164 const dbus::ObjectPath& object_path,
230 const std::string& property_name) { 165 const std::string& property_name) {
231 if (object_path != object_path_) 166 if (object_path != this->object_path())
232 return; 167 return;
233 168
234 VLOG(1) << "Service property changed: \"" << property_name << "\", " 169 VLOG(1) << "Service property changed: \"" << property_name << "\", "
235 << object_path.value(); 170 << object_path.value();
236 bluez::BluetoothGattServiceClient::Properties* properties = 171 bluez::BluetoothGattServiceClient::Properties* properties =
237 bluez::BluezDBusManager::Get() 172 bluez::BluezDBusManager::Get()
238 ->GetBluetoothGattServiceClient() 173 ->GetBluetoothGattServiceClient()
239 ->GetProperties(object_path); 174 ->GetProperties(object_path);
240 DCHECK(properties); 175 DCHECK(properties);
241 176
242 if (property_name != properties->characteristics.name()) { 177 if (property_name != properties->characteristics.name()) {
243 NotifyServiceChanged(); 178 NotifyServiceChanged();
244 return; 179 return;
245 } 180 }
246 181
247 if (discovery_complete_) 182 if (discovery_complete_)
248 return; 183 return;
249 184
250 VLOG(1) << "All characteristics were discovered for service: " 185 VLOG(1) << "All characteristics were discovered for service: "
251 << object_path.value(); 186 << object_path.value();
252 discovery_complete_ = true; 187 discovery_complete_ = true;
253 DCHECK(adapter_); 188 DCHECK(GetAdapter());
254 adapter_->NotifyGattDiscoveryComplete(this); 189 GetAdapter()->NotifyGattDiscoveryComplete(this);
255 } 190 }
256 191
257 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicAdded( 192 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicAdded(
258 const dbus::ObjectPath& object_path) { 193 const dbus::ObjectPath& object_path) {
259 if (characteristics_.find(object_path) != characteristics_.end()) { 194 if (characteristics_.find(object_path) != characteristics_.end()) {
260 VLOG(1) << "Remote GATT characteristic already exists: " 195 VLOG(1) << "Remote GATT characteristic already exists: "
261 << object_path.value(); 196 << object_path.value();
262 return; 197 return;
263 } 198 }
264 199
265 bluez::BluetoothGattCharacteristicClient::Properties* properties = 200 bluez::BluetoothGattCharacteristicClient::Properties* properties =
266 bluez::BluezDBusManager::Get() 201 bluez::BluezDBusManager::Get()
267 ->GetBluetoothGattCharacteristicClient() 202 ->GetBluetoothGattCharacteristicClient()
268 ->GetProperties(object_path); 203 ->GetProperties(object_path);
269 DCHECK(properties); 204 DCHECK(properties);
270 if (properties->service.value() != object_path_) { 205 if (properties->service.value() != this->object_path()) {
271 VLOG(2) << "Remote GATT characteristic does not belong to this service."; 206 VLOG(2) << "Remote GATT characteristic does not belong to this service.";
272 return; 207 return;
273 } 208 }
274 209
275 VLOG(1) << "Adding new remote GATT characteristic for GATT service: " 210 VLOG(1) << "Adding new remote GATT characteristic for GATT service: "
276 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 211 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
277 212
278 BluetoothRemoteGattCharacteristicBlueZ* characteristic = 213 BluetoothRemoteGattCharacteristicBlueZ* characteristic =
279 new BluetoothRemoteGattCharacteristicBlueZ(this, object_path); 214 new BluetoothRemoteGattCharacteristicBlueZ(this, object_path);
280 characteristics_[object_path] = characteristic; 215 characteristics_[object_path] = characteristic;
281 DCHECK(characteristic->GetIdentifier() == object_path.value()); 216 DCHECK(characteristic->GetIdentifier() == object_path.value());
282 DCHECK(characteristic->GetUUID().IsValid()); 217 DCHECK(characteristic->GetUUID().IsValid());
283 218
284 DCHECK(adapter_); 219 DCHECK(GetAdapter());
285 adapter_->NotifyGattCharacteristicAdded(characteristic); 220 GetAdapter()->NotifyGattCharacteristicAdded(characteristic);
286 } 221 }
287 222
288 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicRemoved( 223 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicRemoved(
289 const dbus::ObjectPath& object_path) { 224 const dbus::ObjectPath& object_path) {
290 CharacteristicMap::iterator iter = characteristics_.find(object_path); 225 CharacteristicMap::iterator iter = characteristics_.find(object_path);
291 if (iter == characteristics_.end()) { 226 if (iter == characteristics_.end()) {
292 VLOG(2) << "Unknown GATT characteristic removed: " << object_path.value(); 227 VLOG(2) << "Unknown GATT characteristic removed: " << object_path.value();
293 return; 228 return;
294 } 229 }
295 230
296 VLOG(1) << "Removing remote GATT characteristic from service: " 231 VLOG(1) << "Removing remote GATT characteristic from service: "
297 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); 232 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
298 233
299 BluetoothRemoteGattCharacteristicBlueZ* characteristic = iter->second; 234 BluetoothGattCharacteristicBlueZ* characteristic = iter->second;
300 DCHECK(characteristic->object_path() == object_path); 235 DCHECK(characteristic->object_path() == object_path);
301 characteristics_.erase(iter); 236 characteristics_.erase(iter);
302 237
303 DCHECK(adapter_); 238 DCHECK(GetAdapter());
304 adapter_->NotifyGattCharacteristicRemoved(characteristic); 239 GetAdapter()->NotifyGattCharacteristicRemoved(characteristic);
305 240
306 delete characteristic; 241 delete characteristic;
307 } 242 }
308 243
309 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicPropertyChanged( 244 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicPropertyChanged(
310 const dbus::ObjectPath& object_path, 245 const dbus::ObjectPath& object_path,
311 const std::string& property_name) { 246 const std::string& property_name) {
312 CharacteristicMap::iterator iter = characteristics_.find(object_path); 247 CharacteristicMap::iterator iter = characteristics_.find(object_path);
313 if (iter == characteristics_.end()) { 248 if (iter == characteristics_.end()) {
314 VLOG(3) << "Properties of unknown characteristic changed"; 249 VLOG(3) << "Properties of unknown characteristic changed";
315 return; 250 return;
316 } 251 }
317 252
318 // We may receive a property changed event in certain cases, e.g. when the 253 // We may receive a property changed event in certain cases, e.g. when the
319 // characteristic "Flags" property has been updated with values from the 254 // characteristic "Flags" property has been updated with values from the
320 // "Characteristic Extended Properties" descriptor. In this case, kick off 255 // "Characteristic Extended Properties" descriptor. In this case, kick off
321 // a service changed observer event to let observers refresh the 256 // a service changed observer event to let observers refresh the
322 // characteristics. 257 // characteristics.
323 bluez::BluetoothGattCharacteristicClient::Properties* properties = 258 bluez::BluetoothGattCharacteristicClient::Properties* properties =
324 bluez::BluezDBusManager::Get() 259 bluez::BluezDBusManager::Get()
325 ->GetBluetoothGattCharacteristicClient() 260 ->GetBluetoothGattCharacteristicClient()
326 ->GetProperties(object_path); 261 ->GetProperties(object_path);
327 262
328 DCHECK(properties); 263 DCHECK(properties);
329 DCHECK(adapter_); 264 DCHECK(GetAdapter());
330 265
331 if (property_name == properties->flags.name()) 266 if (property_name == properties->flags.name())
332 NotifyServiceChanged(); 267 NotifyServiceChanged();
333 else if (property_name == properties->value.name()) 268 else if (property_name == properties->value.name())
334 adapter_->NotifyGattCharacteristicValueChanged(iter->second, 269 GetAdapter()->NotifyGattCharacteristicValueChanged(
335 properties->value.value()); 270 iter->second, properties->value.value());
336 } 271 }
337 272
338 } // namespace bluez 273 } // namespace bluez
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_remote_gatt_service_bluez.h ('k') | device/bluetooth/bluetooth_remote_gatt_service_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698