OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "content/renderer/usb/web_usb_client_impl.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <memory> | |
10 #include <utility> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/callback.h" | |
14 #include "base/memory/ptr_util.h" | |
15 #include "base/move.h" | |
16 #include "base/stl_util.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "content/child/mojo/type_converters.h" | |
19 #include "content/child/scoped_web_callbacks.h" | |
20 #include "content/public/common/service_registry.h" | |
21 #include "content/renderer/usb/type_converters.h" | |
22 #include "content/renderer/usb/web_usb_device_impl.h" | |
23 #include "mojo/public/cpp/bindings/array.h" | |
24 #include "mojo/public/cpp/bindings/interface_request.h" | |
25 #include "third_party/WebKit/public/platform/WebCallbacks.h" | |
26 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceFilter.h
" | |
27 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceInfo.h" | |
28 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBDeviceRequestO
ptions.h" | |
29 #include "third_party/WebKit/public/platform/modules/webusb/WebUSBError.h" | |
30 | |
31 namespace content { | |
32 | |
33 namespace { | |
34 | |
35 const char kNoServiceError[] = "USB service unavailable."; | |
36 | |
37 // Generic default rejection handler for any WebUSB callbacks type. Assumes | |
38 // |CallbacksType| is a blink::WebCallbacks<T, const blink::WebUSBError&> | |
39 // for any type |T|. | |
40 template <typename CallbacksType> | |
41 void RejectCallbacksWithError(const blink::WebUSBError& error, | |
42 std::unique_ptr<CallbacksType> callbacks) { | |
43 callbacks->onError(error); | |
44 } | |
45 | |
46 // Create a new ScopedWebCallbacks for WebUSB client callbacks, defaulting to | |
47 // a "no service" rejection. | |
48 template <typename CallbacksType> | |
49 ScopedWebCallbacks<CallbacksType> MakeScopedUSBCallbacks( | |
50 CallbacksType* callbacks) { | |
51 return make_scoped_web_callbacks( | |
52 callbacks, | |
53 base::Bind(&RejectCallbacksWithError<CallbacksType>, | |
54 blink::WebUSBError(blink::WebUSBError::Error::NotFound, | |
55 base::ASCIIToUTF16(kNoServiceError)))); | |
56 } | |
57 | |
58 void OnGetDevicesComplete( | |
59 ScopedWebCallbacks<blink::WebUSBClientGetDevicesCallbacks> scoped_callbacks, | |
60 device::usb::DeviceManager* device_manager, | |
61 mojo::Array<device::usb::DeviceInfoPtr> results) { | |
62 // TODO(dcheng): This WebVector should hold smart pointers. | |
63 std::unique_ptr<blink::WebVector<blink::WebUSBDevice*>> devices( | |
64 new blink::WebVector<blink::WebUSBDevice*>(results.size())); | |
65 for (size_t i = 0; i < results.size(); ++i) { | |
66 device::usb::DevicePtr device; | |
67 device_manager->GetDevice(results[i]->guid, mojo::GetProxy(&device)); | |
68 (*devices)[i] = new WebUSBDeviceImpl( | |
69 std::move(device), | |
70 mojo::ConvertTo<blink::WebUSBDeviceInfo>(results[i])); | |
71 } | |
72 scoped_callbacks.PassCallbacks()->onSuccess(std::move(devices)); | |
73 } | |
74 | |
75 void OnRequestDevicesComplete( | |
76 ScopedWebCallbacks<blink::WebUSBClientRequestDeviceCallbacks> callbacks, | |
77 device::usb::DeviceManager* device_manager, | |
78 device::usb::DeviceInfoPtr result) { | |
79 auto scoped_callbacks = callbacks.PassCallbacks(); | |
80 if (result) { | |
81 device::usb::DevicePtr device; | |
82 device_manager->GetDevice(result->guid, mojo::GetProxy(&device)); | |
83 std::unique_ptr<blink::WebUSBDevice> web_usb_device(new WebUSBDeviceImpl( | |
84 std::move(device), mojo::ConvertTo<blink::WebUSBDeviceInfo>(result))); | |
85 | |
86 scoped_callbacks->onSuccess(std::move(web_usb_device)); | |
87 } else { | |
88 scoped_callbacks->onError( | |
89 blink::WebUSBError(blink::WebUSBError::Error::NotFound, | |
90 base::ASCIIToUTF16("No device selected."))); | |
91 } | |
92 } | |
93 | |
94 } // namespace | |
95 | |
96 WebUSBClientImpl::WebUSBClientImpl(content::ServiceRegistry* service_registry) | |
97 : service_registry_(service_registry) {} | |
98 | |
99 WebUSBClientImpl::~WebUSBClientImpl() {} | |
100 | |
101 void WebUSBClientImpl::getDevices( | |
102 blink::WebUSBClientGetDevicesCallbacks* callbacks) { | |
103 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks); | |
104 GetDeviceManager()->GetDevices( | |
105 nullptr, | |
106 base::Bind(&OnGetDevicesComplete, base::Passed(&scoped_callbacks), | |
107 base::Unretained(device_manager_.get()))); | |
108 } | |
109 | |
110 void WebUSBClientImpl::requestDevice( | |
111 const blink::WebUSBDeviceRequestOptions& options, | |
112 blink::WebUSBClientRequestDeviceCallbacks* callbacks) { | |
113 if (!chooser_service_) { | |
114 service_registry_->ConnectToRemoteService( | |
115 mojo::GetProxy(&chooser_service_)); | |
116 } | |
117 | |
118 auto scoped_callbacks = MakeScopedUSBCallbacks(callbacks); | |
119 | |
120 mojo::Array<device::usb::DeviceFilterPtr> device_filters = | |
121 mojo::Array<device::usb::DeviceFilterPtr>::From(options.filters); | |
122 | |
123 chooser_service_->GetPermission( | |
124 std::move(device_filters), | |
125 base::Bind(&OnRequestDevicesComplete, base::Passed(&scoped_callbacks), | |
126 base::Unretained(device_manager_.get()))); | |
127 } | |
128 | |
129 void WebUSBClientImpl::addObserver(Observer* observer) { | |
130 if (observers_.empty()) { | |
131 // Set up two sequential calls to GetDeviceChanges to avoid latency. | |
132 device::usb::DeviceManager* device_manager = GetDeviceManager(); | |
133 device_manager->GetDeviceChanges(base::Bind( | |
134 &WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this))); | |
135 device_manager->GetDeviceChanges(base::Bind( | |
136 &WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this))); | |
137 } | |
138 | |
139 observers_.insert(observer); | |
140 } | |
141 | |
142 void WebUSBClientImpl::removeObserver(Observer* observer) { | |
143 DCHECK(ContainsKey(observers_, observer)); | |
144 observers_.erase(observer); | |
145 } | |
146 | |
147 device::usb::DeviceManager* WebUSBClientImpl::GetDeviceManager() { | |
148 if (!device_manager_) | |
149 service_registry_->ConnectToRemoteService(mojo::GetProxy(&device_manager_)); | |
150 return device_manager_.get(); | |
151 } | |
152 | |
153 void WebUSBClientImpl::OnDeviceChangeNotification( | |
154 device::usb::DeviceChangeNotificationPtr notification) { | |
155 if (observers_.empty()) | |
156 return; | |
157 | |
158 device_manager_->GetDeviceChanges(base::Bind( | |
159 &WebUSBClientImpl::OnDeviceChangeNotification, base::Unretained(this))); | |
160 for (size_t i = 0; i < notification->devices_added.size(); ++i) { | |
161 const device::usb::DeviceInfoPtr& device_info = | |
162 notification->devices_added[i]; | |
163 for (auto observer : observers_) { | |
164 device::usb::DevicePtr device; | |
165 device_manager_->GetDevice(device_info->guid, mojo::GetProxy(&device)); | |
166 observer->onDeviceConnected(base::WrapUnique(new WebUSBDeviceImpl( | |
167 std::move(device), | |
168 mojo::ConvertTo<blink::WebUSBDeviceInfo>(device_info)))); | |
169 } | |
170 } | |
171 for (size_t i = 0; i < notification->devices_removed.size(); ++i) { | |
172 const device::usb::DeviceInfoPtr& device_info = | |
173 notification->devices_removed[i]; | |
174 for (auto observer : observers_) | |
175 observer->onDeviceDisconnected(base::WrapUnique(new WebUSBDeviceImpl( | |
176 nullptr, mojo::ConvertTo<blink::WebUSBDeviceInfo>(device_info)))); | |
177 } | |
178 } | |
179 | |
180 } // namespace content | |
OLD | NEW |