Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / extension_printer_handler.cc
blob3021dcf223cb7727660e2b5e7707661de1899168
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.
5 #include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/task_runner_util.h"
18 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
19 #include "components/cloud_devices/common/cloud_device_description.h"
20 #include "components/cloud_devices/common/printer_description.h"
21 #include "device/core/device_client.h"
22 #include "device/usb/usb_device.h"
23 #include "device/usb/usb_service.h"
24 #include "extensions/browser/api/device_permissions_manager.h"
25 #include "extensions/browser/api/printer_provider/printer_provider_api.h"
26 #include "extensions/browser/api/printer_provider/printer_provider_api_factory.h"
27 #include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
28 #include "extensions/browser/extension_registry.h"
29 #include "extensions/common/api/printer_provider/usb_printer_manifest_data.h"
30 #include "extensions/common/permissions/permissions_data.h"
31 #include "extensions/common/permissions/usb_device_permission.h"
32 #include "extensions/common/permissions/usb_device_permission_data.h"
33 #include "extensions/common/value_builder.h"
34 #include "printing/pdf_render_settings.h"
35 #include "printing/pwg_raster_settings.h"
37 using device::UsbDevice;
38 using extensions::DevicePermissionsManager;
39 using extensions::DictionaryBuilder;
40 using extensions::Extension;
41 using extensions::ExtensionRegistry;
42 using extensions::ListBuilder;
43 using extensions::UsbPrinterManifestData;
44 using local_discovery::PWGRasterConverter;
46 namespace {
48 const char kContentTypePdf[] = "application/pdf";
49 const char kContentTypePWGRaster[] = "image/pwg-raster";
50 const char kContentTypeAll[] = "*/*";
52 const char kInvalidDataPrintError[] = "INVALID_DATA";
53 const char kInvalidTicketPrintError[] = "INVALID_TICKET";
55 // Updates |job| with raster file path, size and last modification time.
56 // Returns the updated print job.
57 scoped_ptr<extensions::PrinterProviderPrintJob> UpdateJobFileInfoOnWorkerThread(
58 const base::FilePath& raster_path,
59 scoped_ptr<extensions::PrinterProviderPrintJob> job) {
60 if (base::GetFileInfo(raster_path, &job->file_info))
61 job->document_path = raster_path;
62 return job.Pass();
65 // Callback to PWG raster conversion.
66 // Posts a task to update print job with info about file containing converted
67 // PWG raster data. The task is posted to |slow_task_runner|.
68 void UpdateJobFileInfo(
69 scoped_ptr<extensions::PrinterProviderPrintJob> job,
70 const scoped_refptr<base::TaskRunner>& slow_task_runner,
71 const ExtensionPrinterHandler::PrintJobCallback& callback,
72 bool success,
73 const base::FilePath& pwg_file_path) {
74 if (!success) {
75 callback.Run(job.Pass());
76 return;
79 base::PostTaskAndReplyWithResult(
80 slow_task_runner.get(), FROM_HERE,
81 base::Bind(&UpdateJobFileInfoOnWorkerThread, pwg_file_path,
82 base::Passed(&job)),
83 callback);
86 bool HasUsbPrinterProviderPermissions(const Extension* extension) {
87 return extension->permissions_data() &&
88 extension->permissions_data()->HasAPIPermission(
89 extensions::APIPermission::kPrinterProvider) &&
90 extension->permissions_data()->HasAPIPermission(
91 extensions::APIPermission::kUsb);
94 } // namespace
96 ExtensionPrinterHandler::ExtensionPrinterHandler(
97 content::BrowserContext* browser_context,
98 const scoped_refptr<base::TaskRunner>& slow_task_runner)
99 : browser_context_(browser_context),
100 slow_task_runner_(slow_task_runner),
101 weak_ptr_factory_(this) {
104 ExtensionPrinterHandler::~ExtensionPrinterHandler() {
107 void ExtensionPrinterHandler::Reset() {
108 // TODO(tbarzic): Keep track of pending request ids issued by |this| and
109 // cancel them from here.
110 pending_enumeration_count_ = 0;
111 weak_ptr_factory_.InvalidateWeakPtrs();
114 void ExtensionPrinterHandler::StartGetPrinters(
115 const PrinterHandler::GetPrintersCallback& callback) {
116 // Assume that there can only be one printer enumeration occuring at once.
117 DCHECK_EQ(pending_enumeration_count_, 0);
118 pending_enumeration_count_ = 1;
120 bool extension_supports_usb_printers = false;
121 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
122 for (const auto& extension : registry->enabled_extensions()) {
123 if (UsbPrinterManifestData::Get(extension.get()) &&
124 HasUsbPrinterProviderPermissions(extension.get())) {
125 extension_supports_usb_printers = true;
126 break;
130 if (extension_supports_usb_printers) {
131 device::UsbService* service = device::DeviceClient::Get()->GetUsbService();
132 pending_enumeration_count_++;
133 service->GetDevices(
134 base::Bind(&ExtensionPrinterHandler::OnUsbDevicesEnumerated,
135 weak_ptr_factory_.GetWeakPtr(), callback));
138 extensions::PrinterProviderAPIFactory::GetInstance()
139 ->GetForBrowserContext(browser_context_)
140 ->DispatchGetPrintersRequested(
141 base::Bind(&ExtensionPrinterHandler::WrapGetPrintersCallback,
142 weak_ptr_factory_.GetWeakPtr(), callback));
145 void ExtensionPrinterHandler::StartGetCapability(
146 const std::string& destination_id,
147 const PrinterHandler::GetCapabilityCallback& callback) {
148 extensions::PrinterProviderAPIFactory::GetInstance()
149 ->GetForBrowserContext(browser_context_)
150 ->DispatchGetCapabilityRequested(
151 destination_id,
152 base::Bind(&ExtensionPrinterHandler::WrapGetCapabilityCallback,
153 weak_ptr_factory_.GetWeakPtr(), callback, destination_id));
156 void ExtensionPrinterHandler::StartPrint(
157 const std::string& destination_id,
158 const std::string& capability,
159 const base::string16& job_title,
160 const std::string& ticket_json,
161 const gfx::Size& page_size,
162 const scoped_refptr<base::RefCountedMemory>& print_data,
163 const PrinterHandler::PrintCallback& callback) {
164 scoped_ptr<extensions::PrinterProviderPrintJob> print_job(
165 new extensions::PrinterProviderPrintJob());
166 print_job->printer_id = destination_id;
167 print_job->job_title = job_title;
168 print_job->ticket_json = ticket_json;
170 cloud_devices::CloudDeviceDescription printer_description;
171 printer_description.InitFromString(capability);
173 cloud_devices::printer::ContentTypesCapability content_types;
174 content_types.LoadFrom(printer_description);
176 const bool kUsePdf = content_types.Contains(kContentTypePdf) ||
177 content_types.Contains(kContentTypeAll);
179 if (kUsePdf) {
180 // TODO(tbarzic): Consider writing larger PDF to disk and provide the data
181 // the same way as it's done with PWG raster.
182 print_job->content_type = kContentTypePdf;
183 print_job->document_bytes = print_data;
184 DispatchPrintJob(callback, print_job.Pass());
185 return;
188 cloud_devices::CloudDeviceDescription ticket;
189 if (!ticket.InitFromString(ticket_json)) {
190 WrapPrintCallback(callback, false, kInvalidTicketPrintError);
191 return;
194 print_job->content_type = kContentTypePWGRaster;
195 ConvertToPWGRaster(print_data, printer_description, ticket, page_size,
196 print_job.Pass(),
197 base::Bind(&ExtensionPrinterHandler::DispatchPrintJob,
198 weak_ptr_factory_.GetWeakPtr(), callback));
201 void ExtensionPrinterHandler::SetPwgRasterConverterForTesting(
202 scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter) {
203 pwg_raster_converter_ = pwg_raster_converter.Pass();
206 void ExtensionPrinterHandler::ConvertToPWGRaster(
207 const scoped_refptr<base::RefCountedMemory>& data,
208 const cloud_devices::CloudDeviceDescription& printer_description,
209 const cloud_devices::CloudDeviceDescription& ticket,
210 const gfx::Size& page_size,
211 scoped_ptr<extensions::PrinterProviderPrintJob> job,
212 const ExtensionPrinterHandler::PrintJobCallback& callback) {
213 if (!pwg_raster_converter_) {
214 pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
216 pwg_raster_converter_->Start(
217 data.get(),
218 PWGRasterConverter::GetConversionSettings(printer_description, page_size),
219 PWGRasterConverter::GetBitmapSettings(printer_description, ticket),
220 base::Bind(&UpdateJobFileInfo, base::Passed(&job), slow_task_runner_,
221 callback));
224 void ExtensionPrinterHandler::DispatchPrintJob(
225 const PrinterHandler::PrintCallback& callback,
226 scoped_ptr<extensions::PrinterProviderPrintJob> print_job) {
227 if (print_job->document_path.empty() && !print_job->document_bytes) {
228 WrapPrintCallback(callback, false, kInvalidDataPrintError);
229 return;
232 extensions::PrinterProviderAPIFactory::GetInstance()
233 ->GetForBrowserContext(browser_context_)
234 ->DispatchPrintRequested(
235 *print_job, base::Bind(&ExtensionPrinterHandler::WrapPrintCallback,
236 weak_ptr_factory_.GetWeakPtr(), callback));
239 void ExtensionPrinterHandler::WrapGetPrintersCallback(
240 const PrinterHandler::GetPrintersCallback& callback,
241 const base::ListValue& printers,
242 bool done) {
243 DCHECK_GT(pending_enumeration_count_, 0);
244 if (done)
245 pending_enumeration_count_--;
247 callback.Run(printers, pending_enumeration_count_ == 0);
250 void ExtensionPrinterHandler::WrapGetCapabilityCallback(
251 const PrinterHandler::GetCapabilityCallback& callback,
252 const std::string& destination_id,
253 const base::DictionaryValue& capability) {
254 callback.Run(destination_id, capability);
257 void ExtensionPrinterHandler::WrapPrintCallback(
258 const PrinterHandler::PrintCallback& callback,
259 bool success,
260 const std::string& status) {
261 callback.Run(success, status);
264 void ExtensionPrinterHandler::OnUsbDevicesEnumerated(
265 const PrinterHandler::GetPrintersCallback& callback,
266 const std::vector<scoped_refptr<UsbDevice>>& devices) {
267 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
268 DevicePermissionsManager* permissions_manager =
269 DevicePermissionsManager::Get(browser_context_);
271 ListBuilder printer_list;
273 for (const auto& extension : registry->enabled_extensions()) {
274 const UsbPrinterManifestData* manifest_data =
275 UsbPrinterManifestData::Get(extension.get());
276 if (!manifest_data || !HasUsbPrinterProviderPermissions(extension.get()))
277 continue;
279 const extensions::DevicePermissions* device_permissions =
280 permissions_manager->GetForExtension(extension->id());
281 for (const auto& device : devices) {
282 if (manifest_data->SupportsDevice(device)) {
283 extensions::UsbDevicePermission::CheckParam param(
284 device->vendor_id(), device->product_id(),
285 extensions::UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
286 if (device_permissions->FindUsbDeviceEntry(device) ||
287 extension->permissions_data()->CheckAPIPermissionWithParam(
288 extensions::APIPermission::kUsbDevice, &param)) {
289 // Skip devices the extension already has permission to access.
290 continue;
293 printer_list.Append(
294 DictionaryBuilder()
295 .Set("id", base::StringPrintf("provisional-usb:%s:%u",
296 extension->id().c_str(),
297 device->unique_id()))
298 .Set("name",
299 DevicePermissionsManager::GetPermissionMessage(
300 device->vendor_id(), device->product_id(),
301 device->manufacturer_string(),
302 device->product_string(), base::string16(), false))
303 .Set("extensionId", extension->id())
304 .Set("extensionName", extension->name())
305 .Set("provisional", true));
310 DCHECK_GT(pending_enumeration_count_, 0);
311 pending_enumeration_count_--;
312 callback.Run(*printer_list.Build().get(), pending_enumeration_count_ == 0);