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

Side by Side Diff: chrome/browser/chromeos/printer_detector/cups_printer_detector.cc

Issue 2790603003: Make CUPS USB printing play better with the settings page. This change does several things: (Closed)
Patch Set: Pre-review cleanups Created 3 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 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 <stdint.h> 5 #include <stdint.h>
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/observer_list_threadsafe.h"
15 #include "base/scoped_observer.h" 16 #include "base/scoped_observer.h"
16 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/lock.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
17 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chromeos/printer_detector/printer_detector.h" 21 #include "chrome/browser/chromeos/printer_detector/printer_detector.h"
19 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" 22 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
20 #include "chrome/browser/chromeos/printing/printer_configurer.h" 23 #include "chrome/browser/chromeos/printing/printer_configurer.h"
21 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" 24 #include "chrome/browser/chromeos/printing/printers_manager_factory.h"
22 #include "chrome/browser/chromeos/printing/usb_printer_util.h" 25 #include "chrome/browser/chromeos/printing/usb_printer_util.h"
23 #include "chrome/browser/chromeos/profiles/profile_helper.h" 26 #include "chrome/browser/chromeos/profiles/profile_helper.h"
24 #include "chromeos/dbus/dbus_thread_manager.h" 27 #include "chromeos/dbus/dbus_thread_manager.h"
25 #include "chromeos/dbus/debug_daemon_client.h" 28 #include "chromeos/dbus/debug_daemon_client.h"
26 #include "chromeos/printing/ppd_provider.h" 29 #include "chromeos/printing/ppd_provider.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 return base::UTF16ToUTF8(device.manufacturer_string()) + " " + 68 return base::UTF16ToUTF8(device.manufacturer_string()) + " " +
66 base::UTF16ToUTF8(device.product_string()); 69 base::UTF16ToUTF8(device.product_string());
67 } 70 }
68 71
69 // The PrinterDetector that drives the flow for setting up a USB printer to use 72 // The PrinterDetector that drives the flow for setting up a USB printer to use
70 // CUPS backend. 73 // CUPS backend.
71 class CupsPrinterDetectorImpl : public PrinterDetector, 74 class CupsPrinterDetectorImpl : public PrinterDetector,
72 public device::UsbService::Observer { 75 public device::UsbService::Observer {
73 public: 76 public:
74 explicit CupsPrinterDetectorImpl(Profile* profile) 77 explicit CupsPrinterDetectorImpl(Profile* profile)
75 : profile_(profile), observer_(this), weak_ptr_factory_(this) { 78 : profile_(profile),
79 usb_observer_(this),
80 observer_list_(
81 new base::ObserverListThreadSafe<PrinterDetector::Observer>),
82 weak_ptr_factory_(this) {
76 device::UsbService* usb_service = 83 device::UsbService* usb_service =
77 device::DeviceClient::Get()->GetUsbService(); 84 device::DeviceClient::Get()->GetUsbService();
78 if (usb_service) { 85 if (usb_service) {
79 observer_.Add(usb_service); 86 usb_observer_.Add(usb_service);
80 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices, 87 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices,
81 weak_ptr_factory_.GetWeakPtr())); 88 weak_ptr_factory_.GetWeakPtr()));
82 } 89 }
83 } 90 }
84 ~CupsPrinterDetectorImpl() override = default; 91 ~CupsPrinterDetectorImpl() override = default;
85 92
93 // PrinterDetector interface function.
94 void AddObserver(PrinterDetector::Observer* observer) override {
95 observer_list_->AddObserver(observer);
96 }
97
98 // PrinterDetector interface function.
99 void RemoveObserver(PrinterDetector::Observer* observer) override {
100 observer_list_->RemoveObserver(observer);
101 }
102
103 // PrinterDetector interface function.
104 std::vector<Printer> GetPrinters() override {
105 base::AutoLock auto_lock(pp_lock_);
106 auto ret = GetPrintersLocked();
107 return ret;
108 }
109
86 private: 110 private:
111 std::vector<Printer> GetPrintersLocked() {
112 pp_lock_.AssertAcquired();
113 std::vector<Printer> printers;
114 printers.reserve(present_printers_.size());
115 for (const auto& entry : present_printers_) {
116 printers.push_back(*entry.second);
117 }
118 return printers;
119 }
120
87 // Callback for initial enumeration of usb devices. 121 // Callback for initial enumeration of usb devices.
88 void OnGetDevices( 122 void OnGetDevices(
89 const std::vector<scoped_refptr<device::UsbDevice>>& devices) { 123 const std::vector<scoped_refptr<device::UsbDevice>>& devices) {
90 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 124 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
91 for (const auto& device : devices) { 125 for (const auto& device : devices) {
92 MaybeSetUpDevice(device, false); 126 MaybeSetUpDevice(device, false);
93 } 127 }
94 } 128 }
95 129
96 // UsbService::observer override. 130 // UsbService::observer override.
97 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { 131 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 132 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
99 MaybeSetUpDevice(device, true); 133 MaybeSetUpDevice(device, true);
100 } 134 }
101 135
102 // UsbService::observer override. 136 // UsbService::observer override.
103 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override { 137 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override {
104 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
105 if (!UsbDeviceIsPrinter(*device)) { 139 if (!UsbDeviceIsPrinter(*device)) {
106 return; 140 return;
107 } 141 }
108 known_printers_.erase(device->guid());
109 // TODO(justincarlson): Update failed printers.
110 }
111 142
112 // Returns the existing printer using this URI, if one exists, or 143 base::AutoLock auto_lock(pp_lock_);
113 // null otherwise. 144 if (base::ContainsKey(present_printers_, device->guid())) {
114 std::unique_ptr<Printer> FindExistingPrinter(const std::string& uri) { 145 present_printers_.erase(device->guid());
115 // TODO(justincarlson): add a GetPrinterByURI to PrintersManager. 146 observer_list_->Notify(
116 // https://crbug.com/700602 147 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged,
skau 2017/03/31 17:50:11 Add a note to this method that calling GetPrinters
Carlson 2017/03/31 18:20:06 Done. (I really, really wish we had lock annotati
117 auto existing_printers = 148 GetPrintersLocked());
118 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinters(); 149 } else {
119 for (std::unique_ptr<Printer>& printer : existing_printers) { 150 // If the device has been removed but it's not in present_printers_, it
120 if (printer->uri() == uri) { 151 // must still be in the setup flow.
121 // Found a match, so use the existing configuration. 152 deferred_printer_removals_.insert(device->guid());
122 return std::move(printer);
123 }
124 } 153 }
125 return nullptr;
126 } 154 }
127 155
128 // If this device is a printer and we haven't already tried to set it up, 156 // If this device is a printer and we haven't already tried to set it up,
129 // starts the process of setting the printer up. |hotplugged| 157 // starts the process of setting the printer up. |hotplugged|
130 // should be true if this was plugged in during the session. 158 // should be true if this was plugged in during the session.
131 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device, 159 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device,
132 bool hotplugged) { 160 bool hotplugged) {
133 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 161 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
134 162
135 if (!UsbDeviceIsPrinter(*device) || 163 if (!UsbDeviceIsPrinter(*device)) {
136 base::ContainsKey(known_printers_, device->guid())) {
137 return; 164 return;
138 } 165 }
139 known_printers_.insert(device->guid());
140 166
167 // If we got this far, we want to try to auto-configure this printer.
141 auto data = base::MakeUnique<SetUpPrinterData>(); 168 auto data = base::MakeUnique<SetUpPrinterData>();
142 data->configurer = PrinterConfigurer::Create(profile_); 169 data->configurer = PrinterConfigurer::Create(profile_);
143 data->device = device; 170 data->device = device;
144 data->hotplugged = hotplugged; 171 data->hotplugged = hotplugged;
145 172
146 data->printer = FindExistingPrinter(UsbPrinterUri(*device)); 173 data->printer = UsbDeviceToPrinter(*device);
147 if (data->printer != nullptr) { 174 if (data->printer == nullptr) {
175 // We've failed to understand this printer device, an error will already
176 // have been logged, so just bail.
177 return;
178 }
179
180 // If the user already has a configuration for this device, substitute that
181 // one for the one we generated automatically and skip the parts where we
182 // try to automagically figure out the driver.
183 auto existing_printer_configuration =
184 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
185 data->printer->id());
186 if (existing_printer_configuration != nullptr) {
148 data->is_new = false; 187 data->is_new = false;
188 data->printer = std::move(existing_printer_configuration);
149 OnPrinterResolved(std::move(data)); 189 OnPrinterResolved(std::move(data));
150 return; 190 return;
151 } 191 }
152 192
153 // It's not a device we have configured previously. 193 // It's not a device we have configured previously.
154 // 194 //
155 // TODO(justincarlson): Add a notification that we are attempting to set up 195 // TODO(justincarlson): Add a notification that we are attempting to set up
156 // this printer at this point. 196 // this printer at this point.
157 data->is_new = true; 197 data->is_new = true;
158 data->printer = UsbDeviceToPrinter(*device);
159 if (data->printer == nullptr) {
160 return;
161 }
162 198
163 // Look for an exact match based on USB ids. 199 // Look for an exact match based on USB ids.
164 scoped_refptr<PpdProvider> ppd_provider = 200 scoped_refptr<PpdProvider> ppd_provider =
165 printing::CreateProvider(profile_); 201 printing::CreateProvider(profile_);
166 ppd_provider->ResolveUsbIds( 202 ppd_provider->ResolveUsbIds(
167 device->vendor_id(), device->product_id(), 203 device->vendor_id(), device->product_id(),
168 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone, 204 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone,
169 weak_ptr_factory_.GetWeakPtr(), ppd_provider, 205 weak_ptr_factory_.GetWeakPtr(), ppd_provider,
170 base::Passed(std::move(data)))); 206 base::Passed(std::move(data))));
171 } 207 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 } 243 }
208 244
209 // Called with the result of asking to have a printer configured for CUPS. If 245 // Called with the result of asking to have a printer configured for CUPS. If
210 // |printer_to_register| is non-null and we successfully configured, then the 246 // |printer_to_register| is non-null and we successfully configured, then the
211 // printer is registered with the printers manager. 247 // printer is registered with the printers manager.
212 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data, 248 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data,
213 PrinterSetupResult result) { 249 PrinterSetupResult result) {
214 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 250 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
215 if (result == PrinterSetupResult::SUCCESS) { 251 if (result == PrinterSetupResult::SUCCESS) {
216 if (data->is_new) { 252 if (data->is_new) {
253 // We aren't done with data->printer yet, so we have to copy it instead
254 // of moving it.
255 auto printer_copy = base::MakeUnique<Printer>();
256 *printer_copy = *data->printer;
217 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter( 257 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
218 std::move(data->printer)); 258 std::move(printer_copy));
219 } 259 }
220 // TODO(justincarlson): If the device was hotplugged, pop a timed 260 // TODO(justincarlson): If the device was hotplugged, pop a timed
221 // notification that says the printer is now available for printing. 261 // notification that says the printer is now available for printing.
222 } 262 }
223 // TODO(justincarlson): If this doesn't succeed, Pop a notification that 263 // TODO(justincarlson): If this doesn't succeed, pop a notification that
224 // tells the user automatic setup failed and offers to open the CUPS printer 264 // tells the user automatic setup failed and offers to open the CUPS printer
225 // configuration settings. 265 // configuration settings.
226 // 266
227 // TODO(justincarlson): If this doesn't succeed, Update the list of printers 267 if (base::ContainsKey(deferred_printer_removals_, data->device->guid())) {
228 // that failed to set up. 268 // The device was removed before we finished the flow, so just don't add
269 // it to present_printers_;
270 deferred_printer_removals_.erase(data->device->guid());
271 } else {
272 base::AutoLock auto_lock(pp_lock_);
273 present_printers_.emplace(data->device->guid(), std::move(data->printer));
274 observer_list_->Notify(
275 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged,
276 GetPrintersLocked());
277 }
229 } 278 }
230 279
231 void SetNotificationUIManagerForTesting( 280 void SetNotificationUIManagerForTesting(
232 NotificationUIManager* manager) override { 281 NotificationUIManager* manager) override {
233 LOG(FATAL) << "Not implemented for CUPS"; 282 LOG(FATAL) << "Not implemented for CUPS";
234 } 283 }
235 284
236 // USB GUIDs of printers we've already dealt with. There's an inherent race 285 // Map from USB GUID to Printer that we have detected as being currently
237 // between initially querying all usb devices and receiving a notification 286 // plugged in and have finished processing. Note present_printers_ may be
238 // about a new device, so this set lets us guarantee that we handle a given 287 // accessed from multiple threads, so is protected by pp_lock_.
239 // printer exactly once. 288 std::map<std::string, std::unique_ptr<Printer>> present_printers_;
240 std::set<std::string> known_printers_; 289 base::Lock pp_lock_;
290
291 // If the usb device is removed before we've finished processing it, we'll
292 // defer the cleanup until the setup flow finishes. This is the set of
293 // guids which have been removed before the flow finished.
294 std::set<std::string> deferred_printer_removals_;
241 295
242 Profile* profile_; 296 Profile* profile_;
243 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; 297 ScopedObserver<device::UsbService, device::UsbService::Observer>
298 usb_observer_;
299 scoped_refptr<base::ObserverListThreadSafe<PrinterDetector::Observer>>
300 observer_list_;
244 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; 301 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_;
245 }; 302 };
246 303
247 } // namespace 304 } // namespace
248 305
249 // static 306 // static
250 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { 307 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) {
251 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); 308 return base::MakeUnique<CupsPrinterDetectorImpl>(profile);
252 } 309 }
253 310
254 } // namespace chromeos 311 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698