| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h" | 5 #include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/json/json_string_value_serializer.h" | 12 #include "base/json/json_string_value_serializer.h" |
| 13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 15 #include "base/path_service.h" | 15 #include "base/path_service.h" |
| 16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 17 #include "base/threading/sequenced_task_runner_handle.h" | 17 #include "base/threading/sequenced_task_runner_handle.h" |
| 18 #include "base/values.h" | 18 #include "base/values.h" |
| 19 #include "chrome/browser/browser_process.h" | 19 #include "chrome/browser/browser_process.h" |
| 20 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" | 20 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" |
| 21 #include "chrome/browser/chromeos/printing/printer_configurer.h" | 21 #include "chrome/browser/chromeos/printing/printer_configurer.h" |
| 22 #include "chrome/browser/chromeos/printing/printer_discoverer.h" | 22 #include "chrome/browser/chromeos/printing/printer_discoverer.h" |
| 23 #include "chrome/browser/chromeos/printing/printer_info.h" |
| 23 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" | 24 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" |
| 24 #include "chrome/browser/download/download_prefs.h" | 25 #include "chrome/browser/download/download_prefs.h" |
| 25 #include "chrome/browser/profiles/profile.h" | 26 #include "chrome/browser/profiles/profile.h" |
| 26 #include "chrome/browser/ui/browser_finder.h" | 27 #include "chrome/browser/ui/browser_finder.h" |
| 27 #include "chrome/browser/ui/browser_window.h" | 28 #include "chrome/browser/ui/browser_window.h" |
| 28 #include "chrome/browser/ui/chrome_select_file_policy.h" | 29 #include "chrome/browser/ui/chrome_select_file_policy.h" |
| 29 #include "chrome/common/chrome_paths.h" | 30 #include "chrome/common/chrome_paths.h" |
| 30 #include "chromeos/dbus/dbus_thread_manager.h" | 31 #include "chromeos/dbus/dbus_thread_manager.h" |
| 31 #include "chromeos/dbus/debug_daemon_client.h" | 32 #include "chromeos/dbus/debug_daemon_client.h" |
| 32 #include "chromeos/printing/ppd_cache.h" | 33 #include "chromeos/printing/ppd_cache.h" |
| 33 #include "chromeos/printing/ppd_provider.h" | 34 #include "chromeos/printing/ppd_provider.h" |
| 34 #include "content/public/browser/browser_context.h" | 35 #include "content/public/browser/browser_context.h" |
| 35 #include "content/public/browser/browser_thread.h" | 36 #include "content/public/browser/browser_thread.h" |
| 36 #include "content/public/browser/web_ui.h" | 37 #include "content/public/browser/web_ui.h" |
| 37 #include "google_apis/google_api_keys.h" | 38 #include "google_apis/google_api_keys.h" |
| 38 #include "net/base/filename_util.h" | 39 #include "net/base/filename_util.h" |
| 39 #include "net/url_request/url_request_context_getter.h" | 40 #include "net/url_request/url_request_context_getter.h" |
| 40 #include "printing/backend/print_backend.h" | 41 #include "printing/backend/print_backend.h" |
| 41 #include "url/third_party/mozilla/url_parse.h" | 42 #include "url/third_party/mozilla/url_parse.h" |
| 42 | 43 |
| 43 namespace chromeos { | 44 namespace chromeos { |
| 44 namespace settings { | 45 namespace settings { |
| 45 | 46 |
| 46 namespace { | 47 namespace { |
| 47 | 48 |
| 49 const char kIppScheme[] = "ipp"; |
| 50 const char kIppsScheme[] = "ipps"; |
| 51 |
| 52 const int kIppPort = 631; |
| 53 const int kIppsPort = 443; |
| 54 |
| 48 // These values are written to logs. New enum values can be added, but existing | 55 // These values are written to logs. New enum values can be added, but existing |
| 49 // enums must never be renumbered or deleted and reused. | 56 // enums must never be renumbered or deleted and reused. |
| 50 enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax }; | 57 enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax }; |
| 51 | 58 |
| 52 void RecordPpdSource(const PpdSourceForHistogram& source) { | 59 void RecordPpdSource(const PpdSourceForHistogram& source) { |
| 53 UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PpdSource", source, kPpdSourceMax); | 60 UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PpdSource", source, kPpdSourceMax); |
| 54 } | 61 } |
| 55 | 62 |
| 56 void OnRemovedPrinter(const Printer::PrinterProtocol& protocol, bool success) { | 63 void OnRemovedPrinter(const Printer::PrinterProtocol& protocol, bool success) { |
| 57 UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterRemoved", protocol, | 64 UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterRemoved", protocol, |
| 58 Printer::PrinterProtocol::kProtocolMax); | 65 Printer::PrinterProtocol::kProtocolMax); |
| 59 } | 66 } |
| 60 | 67 |
| 68 // Returns a JSON representation of |printer| as a CupsPrinterInfo. |
| 61 std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) { | 69 std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) { |
| 62 std::unique_ptr<base::DictionaryValue> printer_info = | 70 std::unique_ptr<base::DictionaryValue> printer_info = |
| 63 base::MakeUnique<base::DictionaryValue>(); | 71 base::MakeUnique<base::DictionaryValue>(); |
| 64 printer_info->SetString("printerId", printer.id()); | 72 printer_info->SetString("printerId", printer.id()); |
| 65 printer_info->SetString("printerName", printer.display_name()); | 73 printer_info->SetString("printerName", printer.display_name()); |
| 66 printer_info->SetString("printerDescription", printer.description()); | 74 printer_info->SetString("printerDescription", printer.description()); |
| 67 printer_info->SetString("printerManufacturer", printer.manufacturer()); | 75 printer_info->SetString("printerManufacturer", printer.manufacturer()); |
| 68 printer_info->SetString("printerModel", printer.model()); | 76 printer_info->SetString("printerModel", printer.model()); |
| 69 // Get protocol, ip address and queue from the printer's URI. | 77 // Get protocol, ip address and queue from the printer's URI. |
| 70 const std::string printer_uri = printer.uri(); | 78 const std::string printer_uri = printer.uri(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 91 printer_info->SetString("printerAddress", host); | 99 printer_info->SetString("printerAddress", host); |
| 92 if (!path.empty()) { | 100 if (!path.empty()) { |
| 93 printer_info->SetString("printerQueue", path.substr(1)); | 101 printer_info->SetString("printerQueue", path.substr(1)); |
| 94 } | 102 } |
| 95 } | 103 } |
| 96 printer_info->SetString("printerProtocol", base::ToLowerASCII(scheme)); | 104 printer_info->SetString("printerProtocol", base::ToLowerASCII(scheme)); |
| 97 | 105 |
| 98 return printer_info; | 106 return printer_info; |
| 99 } | 107 } |
| 100 | 108 |
| 109 // Extracts a sanitized value of printerQueeu from |printer_dict|. Returns an |
| 110 // empty string if the value was not present in the dictionary. |
| 111 std::string GetPrinterQueue(const base::DictionaryValue& printer_dict) { |
| 112 std::string queue; |
| 113 if (!printer_dict.GetString("printerQueue", &queue)) { |
| 114 return queue; |
| 115 } |
| 116 |
| 117 if (!queue.empty() && queue[0] == '/') { |
| 118 // Strip the leading backslash. It is expected that this results in an |
| 119 // empty string if the input is just a backslash. |
| 120 queue = queue.substr(1); |
| 121 } |
| 122 |
| 123 return queue; |
| 124 } |
| 125 |
| 101 } // namespace | 126 } // namespace |
| 102 | 127 |
| 103 CupsPrintersHandler::CupsPrintersHandler(content::WebUI* webui) | 128 CupsPrintersHandler::CupsPrintersHandler(content::WebUI* webui) |
| 104 : printer_discoverer_(nullptr), | 129 : printer_discoverer_(nullptr), |
| 105 profile_(Profile::FromWebUI(webui)), | 130 profile_(Profile::FromWebUI(webui)), |
| 106 weak_factory_(this) { | 131 weak_factory_(this) { |
| 107 ppd_provider_ = printing::CreateProvider(profile_); | 132 ppd_provider_ = printing::CreateProvider(profile_); |
| 108 printer_configurer_ = chromeos::PrinterConfigurer::Create(profile_); | 133 printer_configurer_ = chromeos::PrinterConfigurer::Create(profile_); |
| 109 } | 134 } |
| 110 | 135 |
| 111 CupsPrintersHandler::~CupsPrintersHandler() {} | 136 CupsPrintersHandler::~CupsPrintersHandler() {} |
| 112 | 137 |
| 113 void CupsPrintersHandler::RegisterMessages() { | 138 void CupsPrintersHandler::RegisterMessages() { |
| 114 web_ui()->RegisterMessageCallback( | 139 web_ui()->RegisterMessageCallback( |
| 115 "getCupsPrintersList", | 140 "getCupsPrintersList", |
| 116 base::Bind(&CupsPrintersHandler::HandleGetCupsPrintersList, | 141 base::Bind(&CupsPrintersHandler::HandleGetCupsPrintersList, |
| 117 base::Unretained(this))); | 142 base::Unretained(this))); |
| 118 web_ui()->RegisterMessageCallback( | 143 web_ui()->RegisterMessageCallback( |
| 119 "updateCupsPrinter", | 144 "updateCupsPrinter", |
| 120 base::Bind(&CupsPrintersHandler::HandleUpdateCupsPrinter, | 145 base::Bind(&CupsPrintersHandler::HandleUpdateCupsPrinter, |
| 121 base::Unretained(this))); | 146 base::Unretained(this))); |
| 122 web_ui()->RegisterMessageCallback( | 147 web_ui()->RegisterMessageCallback( |
| 123 "removeCupsPrinter", | 148 "removeCupsPrinter", |
| 124 base::Bind(&CupsPrintersHandler::HandleRemoveCupsPrinter, | 149 base::Bind(&CupsPrintersHandler::HandleRemoveCupsPrinter, |
| 125 base::Unretained(this))); | 150 base::Unretained(this))); |
| 126 web_ui()->RegisterMessageCallback( | 151 web_ui()->RegisterMessageCallback( |
| 127 "addCupsPrinter", base::Bind(&CupsPrintersHandler::HandleAddCupsPrinter, | 152 "addCupsPrinter", base::Bind(&CupsPrintersHandler::HandleAddCupsPrinter, |
| 128 base::Unretained(this))); | 153 base::Unretained(this))); |
| 129 web_ui()->RegisterMessageCallback( | 154 web_ui()->RegisterMessageCallback( |
| 155 "getPrinterInfo", base::Bind(&CupsPrintersHandler::HandleGetPrinterInfo, |
| 156 base::Unretained(this))); |
| 157 web_ui()->RegisterMessageCallback( |
| 130 "getCupsPrinterManufacturersList", | 158 "getCupsPrinterManufacturersList", |
| 131 base::Bind(&CupsPrintersHandler::HandleGetCupsPrinterManufacturers, | 159 base::Bind(&CupsPrintersHandler::HandleGetCupsPrinterManufacturers, |
| 132 base::Unretained(this))); | 160 base::Unretained(this))); |
| 133 web_ui()->RegisterMessageCallback( | 161 web_ui()->RegisterMessageCallback( |
| 134 "getCupsPrinterModelsList", | 162 "getCupsPrinterModelsList", |
| 135 base::Bind(&CupsPrintersHandler::HandleGetCupsPrinterModels, | 163 base::Bind(&CupsPrintersHandler::HandleGetCupsPrinterModels, |
| 136 base::Unretained(this))); | 164 base::Unretained(this))); |
| 137 web_ui()->RegisterMessageCallback( | 165 web_ui()->RegisterMessageCallback( |
| 138 "selectPPDFile", base::Bind(&CupsPrintersHandler::HandleSelectPPDFile, | 166 "selectPPDFile", base::Bind(&CupsPrintersHandler::HandleSelectPPDFile, |
| 139 base::Unretained(this))); | 167 base::Unretained(this))); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 Printer::PrinterProtocol protocol = printer->GetProtocol(); | 224 Printer::PrinterProtocol protocol = printer->GetProtocol(); |
| 197 prefs->RemovePrinter(printer_id); | 225 prefs->RemovePrinter(printer_id); |
| 198 | 226 |
| 199 chromeos::DebugDaemonClient* client = | 227 chromeos::DebugDaemonClient* client = |
| 200 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 228 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
| 201 client->CupsRemovePrinter(printer_name, | 229 client->CupsRemovePrinter(printer_name, |
| 202 base::Bind(&OnRemovedPrinter, protocol), | 230 base::Bind(&OnRemovedPrinter, protocol), |
| 203 base::Bind(&base::DoNothing)); | 231 base::Bind(&base::DoNothing)); |
| 204 } | 232 } |
| 205 | 233 |
| 234 void CupsPrintersHandler::HandleGetPrinterInfo(const base::ListValue* args) { |
| 235 DCHECK(args); |
| 236 std::string callback_id; |
| 237 if (!args->GetString(0, &callback_id)) { |
| 238 NOTREACHED() << "Expected request for a promise"; |
| 239 return; |
| 240 } |
| 241 |
| 242 const base::DictionaryValue* printer_dict = nullptr; |
| 243 if (!args->GetDictionary(1, &printer_dict)) { |
| 244 NOTREACHED() << "Dictionary missing"; |
| 245 return; |
| 246 } |
| 247 |
| 248 AllowJavascript(); |
| 249 |
| 250 std::string printer_address; |
| 251 if (!printer_dict->GetString("printerAddress", &printer_address)) { |
| 252 NOTREACHED() << "Address missing"; |
| 253 return; |
| 254 } |
| 255 |
| 256 if (printer_address.empty()) { |
| 257 // Run the failure callback. |
| 258 OnPrinterInfo(callback_id, false, "", "", false); |
| 259 return; |
| 260 } |
| 261 |
| 262 std::string printer_queue = GetPrinterQueue(*printer_dict); |
| 263 |
| 264 std::string printer_protocol; |
| 265 if (!printer_dict->GetString("printerProtocol", &printer_protocol)) { |
| 266 NOTREACHED() << "Protocol missing"; |
| 267 return; |
| 268 } |
| 269 |
| 270 // Parse url to separate address and port. ParseStandardURL expects a scheme, |
| 271 // so add the printer_protocol. |
| 272 std::string printer_uri = |
| 273 printer_protocol + url::kStandardSchemeSeparator + printer_address; |
| 274 const char* uri_ptr = printer_uri.c_str(); |
| 275 url::Parsed parsed; |
| 276 url::ParseStandardURL(uri_ptr, printer_uri.length(), &parsed); |
| 277 base::StringPiece host(&printer_uri[parsed.host.begin], parsed.host.len); |
| 278 |
| 279 int port = ParsePort(uri_ptr, parsed.port); |
| 280 if (port == url::SpecialPort::PORT_UNSPECIFIED || |
| 281 port == url::SpecialPort::PORT_INVALID) { |
| 282 // imply port from protocol |
| 283 if (printer_protocol == kIppScheme) { |
| 284 port = kIppPort; |
| 285 } else if (printer_protocol == kIppsScheme) { |
| 286 // ipps is ipp over https so it uses the https port. |
| 287 port = kIppsPort; |
| 288 } else { |
| 289 NOTREACHED() << "Unrecognized protocol. Port was not set."; |
| 290 } |
| 291 } |
| 292 |
| 293 ::chromeos::QueryIppPrinter( |
| 294 host.as_string(), port, printer_queue, |
| 295 base::Bind(&CupsPrintersHandler::OnPrinterInfo, |
| 296 weak_factory_.GetWeakPtr(), callback_id)); |
| 297 } |
| 298 |
| 299 void CupsPrintersHandler::OnPrinterInfo(const std::string& callback_id, |
| 300 bool success, |
| 301 const std::string& make, |
| 302 const std::string& model, |
| 303 bool ipp_everywhere) { |
| 304 if (!success) { |
| 305 base::DictionaryValue reject; |
| 306 reject.SetString("message", "Querying printer failed"); |
| 307 RejectJavascriptCallback(base::Value(callback_id), reject); |
| 308 return; |
| 309 } |
| 310 |
| 311 base::DictionaryValue info; |
| 312 info.SetString("manufacturer", make); |
| 313 info.SetString("model", model); |
| 314 info.SetBoolean("autoconf", ipp_everywhere); |
| 315 ResolveJavascriptCallback(base::Value(callback_id), info); |
| 316 } |
| 317 |
| 206 void CupsPrintersHandler::HandleAddCupsPrinter(const base::ListValue* args) { | 318 void CupsPrintersHandler::HandleAddCupsPrinter(const base::ListValue* args) { |
| 207 AllowJavascript(); | 319 AllowJavascript(); |
| 208 | 320 |
| 209 const base::DictionaryValue* printer_dict = nullptr; | 321 const base::DictionaryValue* printer_dict = nullptr; |
| 210 CHECK(args->GetDictionary(0, &printer_dict)); | 322 CHECK(args->GetDictionary(0, &printer_dict)); |
| 211 | 323 |
| 212 std::string printer_id; | 324 std::string printer_id; |
| 213 std::string printer_name; | 325 std::string printer_name; |
| 214 std::string printer_description; | 326 std::string printer_description; |
| 215 std::string printer_manufacturer; | 327 std::string printer_manufacturer; |
| 216 std::string printer_model; | 328 std::string printer_model; |
| 217 std::string printer_address; | 329 std::string printer_address; |
| 218 std::string printer_protocol; | 330 std::string printer_protocol; |
| 219 std::string printer_queue; | |
| 220 std::string printer_ppd_path; | 331 std::string printer_ppd_path; |
| 221 CHECK(printer_dict->GetString("printerId", &printer_id)); | 332 CHECK(printer_dict->GetString("printerId", &printer_id)); |
| 222 CHECK(printer_dict->GetString("printerName", &printer_name)); | 333 CHECK(printer_dict->GetString("printerName", &printer_name)); |
| 223 CHECK(printer_dict->GetString("printerDescription", &printer_description)); | 334 CHECK(printer_dict->GetString("printerDescription", &printer_description)); |
| 224 CHECK(printer_dict->GetString("printerManufacturer", &printer_manufacturer)); | 335 CHECK(printer_dict->GetString("printerManufacturer", &printer_manufacturer)); |
| 225 CHECK(printer_dict->GetString("printerModel", &printer_model)); | 336 CHECK(printer_dict->GetString("printerModel", &printer_model)); |
| 226 CHECK(printer_dict->GetString("printerAddress", &printer_address)); | 337 CHECK(printer_dict->GetString("printerAddress", &printer_address)); |
| 227 CHECK(printer_dict->GetString("printerProtocol", &printer_protocol)); | 338 CHECK(printer_dict->GetString("printerProtocol", &printer_protocol)); |
| 228 // printerQueue might be null for a printer whose protocol is not 'LPD'. | |
| 229 printer_dict->GetString("printerQueue", &printer_queue); | |
| 230 | 339 |
| 231 // printerPPDPath might be null for an auto-discovered printer. | 340 std::string printer_queue = GetPrinterQueue(*printer_dict); |
| 232 printer_dict->GetString("printerPPDPath", &printer_ppd_path); | 341 |
| 233 std::string printer_uri = printer_protocol + "://" + printer_address; | 342 std::string printer_uri = |
| 343 printer_protocol + url::kStandardSchemeSeparator + printer_address; |
| 234 if (!printer_queue.empty()) { | 344 if (!printer_queue.empty()) { |
| 235 printer_uri += "/" + printer_queue; | 345 printer_uri += "/" + printer_queue; |
| 236 } | 346 } |
| 237 | 347 |
| 348 // printerPPDPath might be null for an auto-discovered printer. |
| 349 printer_dict->GetString("printerPPDPath", &printer_ppd_path); |
| 350 |
| 238 std::unique_ptr<Printer> printer = base::MakeUnique<Printer>(printer_id); | 351 std::unique_ptr<Printer> printer = base::MakeUnique<Printer>(printer_id); |
| 239 printer->set_display_name(printer_name); | 352 printer->set_display_name(printer_name); |
| 240 printer->set_description(printer_description); | 353 printer->set_description(printer_description); |
| 241 printer->set_manufacturer(printer_manufacturer); | 354 printer->set_manufacturer(printer_manufacturer); |
| 242 printer->set_model(printer_model); | 355 printer->set_model(printer_model); |
| 243 printer->set_uri(printer_uri); | 356 printer->set_uri(printer_uri); |
| 244 | 357 |
| 245 // Verify a valid ppd path is present. | 358 bool autoconf = false; |
| 246 if (!printer_ppd_path.empty()) { | 359 printer_dict->GetBoolean("printerAutoconf", &autoconf); |
| 360 |
| 361 // Verify that the printer is autoconf or a valid ppd path is present. |
| 362 if (autoconf) { |
| 363 printer->mutable_ppd_reference()->autoconf = true; |
| 364 } else if (!printer_ppd_path.empty()) { |
| 247 RecordPpdSource(kUser); | 365 RecordPpdSource(kUser); |
| 248 GURL tmp = net::FilePathToFileURL(base::FilePath(printer_ppd_path)); | 366 GURL tmp = net::FilePathToFileURL(base::FilePath(printer_ppd_path)); |
| 249 if (!tmp.is_valid()) { | 367 if (!tmp.is_valid()) { |
| 250 LOG(ERROR) << "Invalid ppd path: " << printer_ppd_path; | 368 LOG(ERROR) << "Invalid ppd path: " << printer_ppd_path; |
| 251 OnAddPrinterError(); | 369 OnAddPrinterError(); |
| 252 return; | 370 return; |
| 253 } | 371 } |
| 254 printer->mutable_ppd_reference()->user_supplied_ppd_url = tmp.spec(); | 372 printer->mutable_ppd_reference()->user_supplied_ppd_url = tmp.spec(); |
| 255 } else if (!printer_manufacturer.empty() && !printer_model.empty()) { | 373 } else if (!printer_manufacturer.empty() && !printer_model.empty()) { |
| 256 RecordPpdSource(kScs); | 374 RecordPpdSource(kScs); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 FireWebUIListener("on-printer-discovered", *printers_list); | 556 FireWebUIListener("on-printer-discovered", *printers_list); |
| 439 } | 557 } |
| 440 | 558 |
| 441 void CupsPrintersHandler::OnDiscoveryInitialScanDone(int printer_count) { | 559 void CupsPrintersHandler::OnDiscoveryInitialScanDone(int printer_count) { |
| 442 UMA_HISTOGRAM_COUNTS_100("Printing.CUPS.PrintersDiscovered", printer_count); | 560 UMA_HISTOGRAM_COUNTS_100("Printing.CUPS.PrintersDiscovered", printer_count); |
| 443 FireWebUIListener("on-printer-discovery-done"); | 561 FireWebUIListener("on-printer-discovery-done"); |
| 444 } | 562 } |
| 445 | 563 |
| 446 } // namespace settings | 564 } // namespace settings |
| 447 } // namespace chromeos | 565 } // namespace chromeos |
| OLD | NEW |