Commit 97bf1add authored by Justin Carlson's avatar Justin Carlson Committed by Commit Bot

Change PpdProvider API to make it discovery friendly.

This changes two main things.  First, and most significantly, the
way we resolve a PpdReference is unified -- instead of trying
a make-and-model string or trying usb ids, now we have a single
function to which you supply everything you know about the printer
and it gives you back a PpdReference or a failure.

Second, the way we support UI make, model listings changes.  When
the user asks for a list of supported printers from a manufacturer,
instead of getting back just the names, now the api returns the
names paired with the corresponding PpdReference.  Before, the
user had to call back into the ppd provider to get the reference, which
meant we had a weird "have to call this before that" sort of constraint
which this removes.

All callsites and tests updated as well.

Bug: 744996
Change-Id: Ied385c087e4c3d6c1b21b924fcea772c786074c5
Reviewed-on: https://chromium-review.googlesource.com/580007
Commit-Queue: Justin Carlson <justincarlson@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarSean Kau <skau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488716}
parent df983b6f
...@@ -210,8 +210,11 @@ class UsbPrinterDetectorImpl : public UsbPrinterDetector, ...@@ -210,8 +210,11 @@ class UsbPrinterDetectorImpl : public UsbPrinterDetector,
// Look for an exact match based on USB ids. // Look for an exact match based on USB ids.
scoped_refptr<PpdProvider> ppd_provider = CreatePpdProvider(profile_); scoped_refptr<PpdProvider> ppd_provider = CreatePpdProvider(profile_);
ppd_provider->ResolveUsbIds( PpdProvider::PrinterSearchData printer_search_data;
device->vendor_id(), device->product_id(), printer_search_data.usb_vendor_id = device->vendor_id();
printer_search_data.usb_product_id = device->product_id();
ppd_provider->ResolvePpdReference(
printer_search_data,
base::Bind(&UsbPrinterDetectorImpl::ResolveUsbIdsDone, base::Bind(&UsbPrinterDetectorImpl::ResolveUsbIdsDone,
weak_ptr_factory_.GetWeakPtr(), ppd_provider, weak_ptr_factory_.GetWeakPtr(), ppd_provider,
base::Passed(std::move(data)))); base::Passed(std::move(data))));
...@@ -235,12 +238,11 @@ class UsbPrinterDetectorImpl : public UsbPrinterDetector, ...@@ -235,12 +238,11 @@ class UsbPrinterDetectorImpl : public UsbPrinterDetector,
void ResolveUsbIdsDone(scoped_refptr<PpdProvider> provider, void ResolveUsbIdsDone(scoped_refptr<PpdProvider> provider,
std::unique_ptr<SetUpPrinterData> data, std::unique_ptr<SetUpPrinterData> data,
PpdProvider::CallbackResultCode result, PpdProvider::CallbackResultCode result,
const std::string& effective_make_and_model) { const Printer::PpdReference& ppd_reference) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (result == PpdProvider::SUCCESS) { if (result == PpdProvider::SUCCESS) {
// Got something based on usb ids. Go with it. // Got something based on usb ids. Go with it.
data->printer->mutable_ppd_reference()->effective_make_and_model = *data->printer->mutable_ppd_reference() = ppd_reference;
effective_make_and_model;
} else { } else {
// Couldn't figure this printer out based on usb ids, fall back to // Couldn't figure this printer out based on usb ids, fall back to
// guessing the make/model string from what the USB system reports. // guessing the make/model string from what the USB system reports.
......
...@@ -384,9 +384,17 @@ void CupsPrintersHandler::HandleAddCupsPrinter(const base::ListValue* args) { ...@@ -384,9 +384,17 @@ void CupsPrintersHandler::HandleAddCupsPrinter(const base::ListValue* args) {
printer.mutable_ppd_reference()->user_supplied_ppd_url = tmp.spec(); printer.mutable_ppd_reference()->user_supplied_ppd_url = tmp.spec();
} else if (!ppd_manufacturer.empty() && !ppd_model.empty()) { } else if (!ppd_manufacturer.empty() && !ppd_model.empty()) {
RecordPpdSource(kScs); RecordPpdSource(kScs);
// Using the manufacturer and model, get a ppd reference. // Pull out the ppd reference associated with the selected manufacturer and
if (!ppd_provider_->GetPpdReference(ppd_manufacturer, ppd_model, // model.
printer.mutable_ppd_reference())) { bool found = false;
for (const auto& resolved_printer : resolved_printers_[ppd_manufacturer]) {
if (resolved_printer.first == ppd_model) {
*printer.mutable_ppd_reference() = resolved_printer.second;
found = true;
break;
}
}
if (!found) {
LOG(ERROR) << "Failed to get ppd reference"; LOG(ERROR) << "Failed to get ppd reference";
OnAddPrinterError(); OnAddPrinterError();
return; return;
...@@ -490,8 +498,9 @@ void CupsPrintersHandler::HandleGetCupsPrinterModels( ...@@ -490,8 +498,9 @@ void CupsPrintersHandler::HandleGetCupsPrinterModels(
} }
ppd_provider_->ResolvePrinters( ppd_provider_->ResolvePrinters(
manufacturer, base::Bind(&CupsPrintersHandler::ResolvePrintersDone, manufacturer,
weak_factory_.GetWeakPtr(), js_callback)); base::Bind(&CupsPrintersHandler::ResolvePrintersDone,
weak_factory_.GetWeakPtr(), manufacturer, js_callback));
} }
void CupsPrintersHandler::HandleSelectPPDFile(const base::ListValue* args) { void CupsPrintersHandler::HandleSelectPPDFile(const base::ListValue* args) {
...@@ -529,12 +538,16 @@ void CupsPrintersHandler::ResolveManufacturersDone( ...@@ -529,12 +538,16 @@ void CupsPrintersHandler::ResolveManufacturersDone(
} }
void CupsPrintersHandler::ResolvePrintersDone( void CupsPrintersHandler::ResolvePrintersDone(
const std::string& manufacturer,
const std::string& js_callback, const std::string& js_callback,
PpdProvider::CallbackResultCode result_code, PpdProvider::CallbackResultCode result_code,
const std::vector<std::string>& printers) { const PpdProvider::ResolvedPrintersList& printers) {
auto printers_value = base::MakeUnique<base::ListValue>(); auto printers_value = base::MakeUnique<base::ListValue>();
if (result_code == PpdProvider::SUCCESS) { if (result_code == PpdProvider::SUCCESS) {
printers_value->AppendStrings(printers); resolved_printers_[manufacturer] = printers;
for (const auto& printer : printers) {
printers_value->AppendString(printer.first);
}
} }
base::DictionaryValue response; base::DictionaryValue response;
response.SetBoolean("success", result_code == PpdProvider::SUCCESS); response.SetBoolean("success", result_code == PpdProvider::SUCCESS);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -90,9 +91,10 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, ...@@ -90,9 +91,10 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler,
void ResolveManufacturersDone(const std::string& js_callback, void ResolveManufacturersDone(const std::string& js_callback,
PpdProvider::CallbackResultCode result_code, PpdProvider::CallbackResultCode result_code,
const std::vector<std::string>& available); const std::vector<std::string>& available);
void ResolvePrintersDone(const std::string& js_callback, void ResolvePrintersDone(const std::string& manufacturer,
const std::string& js_callback,
PpdProvider::CallbackResultCode result_code, PpdProvider::CallbackResultCode result_code,
const std::vector<std::string>& available); const PpdProvider::ResolvedPrintersList& printers);
// ui::SelectFileDialog::Listener override: // ui::SelectFileDialog::Listener override:
void FileSelected(const base::FilePath& path, void FileSelected(const base::FilePath& path,
...@@ -119,6 +121,10 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler, ...@@ -119,6 +121,10 @@ class CupsPrintersHandler : public ::settings::SettingsPageUIHandler,
scoped_refptr<PpdProvider> ppd_provider_; scoped_refptr<PpdProvider> ppd_provider_;
std::unique_ptr<PrinterConfigurer> printer_configurer_; std::unique_ptr<PrinterConfigurer> printer_configurer_;
// Cached list of {printer name, PpdReference} pairs for each manufacturer
// that has been resolved in the lifetime of this object.
std::map<std::string, PpdProvider::ResolvedPrintersList> resolved_printers_;
Profile* profile_; Profile* profile_;
scoped_refptr<ui::SelectFileDialog> select_file_dialog_; scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
std::string webui_callback_id_; std::string webui_callback_id_;
......
...@@ -180,12 +180,6 @@ struct ManufacturerMetadata { ...@@ -180,12 +180,6 @@ struct ManufacturerMetadata {
std::unique_ptr<std::unordered_map<std::string, std::string>> printers; std::unique_ptr<std::unordered_map<std::string, std::string>> printers;
}; };
// Data for an inflight USB metadata resolution.
struct UsbDeviceId {
int vendor_id;
int device_id;
};
// A queued request to download printer information for a manufacturer. // A queued request to download printer information for a manufacturer.
struct PrinterResolutionQueueEntry { struct PrinterResolutionQueueEntry {
// Localized manufacturer name // Localized manufacturer name
...@@ -248,6 +242,53 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -248,6 +242,53 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
MaybeStartFetch(); MaybeStartFetch();
} }
// If there are any queued ppd reference resolutions, attempt to make progress
// on them. Returns true if a fetch was started, false if no fetch was
// started.
bool MaybeStartNextPpdReferenceResolution() {
while (!ppd_reference_resolution_queue_.empty()) {
const PrinterSearchData& next =
ppd_reference_resolution_queue_.front().first;
if (!next.make_and_model.empty()) {
if (cached_ppd_index_.get() == nullptr) {
// Need to load the index before we can work on this resolution.
StartFetch(GetPpdIndexURL(), FT_PPD_INDEX);
return true;
}
// Check the index for each make-and-model guess.
for (const std::string& make_and_model : next.make_and_model) {
auto it = cached_ppd_index_->find(make_and_model);
if (it != cached_ppd_index_->end()) {
// Found a hit, satisfy this resolution.
Printer::PpdReference ret;
ret.effective_make_and_model = make_and_model;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(ppd_reference_resolution_queue_.front().second,
PpdProvider::SUCCESS, ret));
ppd_reference_resolution_queue_.pop_front();
}
}
}
// If we get to this point, either we don't have any make and model
// guesses for the front entry, or they all missed. Try USB ids
// instead. This entry will be completed when the usb fetch
// returns.
if (next.usb_vendor_id && next.usb_product_id) {
StartFetch(GetUsbURL(next.usb_vendor_id), FT_USB_DEVICES);
return true;
}
// We don't have anything else left to try. NOT_FOUND it is.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(ppd_reference_resolution_queue_.front().second,
PpdProvider::NOT_FOUND, Printer::PpdReference()));
ppd_reference_resolution_queue_.pop_front();
}
// Didn't start any fetches.
return false;
}
// If there is work outstanding that requires a URL fetch to complete, start // If there is work outstanding that requires a URL fetch to complete, start
// going on it. // going on it.
void MaybeStartFetch() { void MaybeStartFetch() {
...@@ -256,9 +297,7 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -256,9 +297,7 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
return; return;
} }
if (!usb_resolution_queue_.empty()) { if (MaybeStartNextPpdReferenceResolution()) {
StartFetch(GetUsbURL(usb_resolution_queue_.front().first.vendor_id),
FT_USB_DEVICES);
return; return;
} }
...@@ -319,8 +358,8 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -319,8 +358,8 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
LOG(ERROR) << "Can't resolve printers for unknown manufacturer " LOG(ERROR) << "Can't resolve printers for unknown manufacturer "
<< manufacturer; << manufacturer;
base::SequencedTaskRunnerHandle::Get()->PostTask( base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(cb, PpdProvider::INTERNAL_ERROR, FROM_HERE,
std::vector<std::string>())); base::Bind(cb, PpdProvider::INTERNAL_ERROR, ResolvedPrintersList()));
return; return;
} }
if (it->second.printers.get() != nullptr) { if (it->second.printers.get() != nullptr) {
...@@ -339,34 +378,12 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -339,34 +378,12 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
} }
} }
void ResolveUsbIds(int vendor_id, void ResolvePpdReference(const PrinterSearchData& search_data,
int device_id, const ResolvePpdReferenceCallback& cb) override {
const ResolveUsbIdsCallback& cb) override { ppd_reference_resolution_queue_.push_back({search_data, cb});
usb_resolution_queue_.push_back({{vendor_id, device_id}, cb});
MaybeStartFetch(); MaybeStartFetch();
} }
bool GetPpdReference(const std::string& manufacturer,
const std::string& printer,
Printer::PpdReference* reference) const override {
std::unordered_map<std::string, ManufacturerMetadata>::iterator top_it;
if (cached_metadata_.get() == nullptr) {
return false;
}
auto it = cached_metadata_->find(manufacturer);
if (it == cached_metadata_->end() || it->second.printers.get() == nullptr) {
return false;
}
const auto& printers_map = *it->second.printers;
auto it2 = printers_map.find(printer);
if (it2 == printers_map.end()) {
return false;
}
*reference = Printer::PpdReference();
reference->effective_make_and_model = it2->second;
return true;
}
void ResolvePpd(const Printer::PpdReference& reference, void ResolvePpd(const Printer::PpdReference& reference,
const ResolvePpdCallback& cb) override { const ResolvePpdCallback& cb) override {
// Do a sanity check here, so we can assumed |reference| is well-formed in // Do a sanity check here, so we can assumed |reference| is well-formed in
...@@ -611,7 +628,7 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -611,7 +628,7 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
if (code != PpdProvider::SUCCESS) { if (code != PpdProvider::SUCCESS) {
base::SequencedTaskRunnerHandle::Get()->PostTask( base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(printers_resolution_queue_.front().cb, code, FROM_HERE, base::Bind(printers_resolution_queue_.front().cb, code,
std::vector<std::string>())); ResolvedPrintersList()));
} else { } else {
// This should be a list of lists of 2-element strings, where the first // This should be a list of lists of 2-element strings, where the first
// element is the localized name of the printer and the second element // element is the localized name of the printer and the second element
...@@ -686,14 +703,15 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -686,14 +703,15 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
} }
// Called when |fetcher_| should have just downloaded a usb device map // Called when |fetcher_| should have just downloaded a usb device map
// for the vendor at the head of the |usb_resolution_queue_|. // for the vendor at the head of the |ppd_reference_resolution_queue_|.
void OnUsbFetchComplete() { void OnUsbFetchComplete() {
DCHECK(!usb_resolution_queue_.empty()); DCHECK(!ppd_reference_resolution_queue_.empty());
std::string contents; std::string contents;
std::string buffer; std::string buffer;
PpdProvider::CallbackResultCode result = PpdProvider::CallbackResultCode result =
ValidateAndGetResponseAsString(&buffer); ValidateAndGetResponseAsString(&buffer);
int desired_device_id = usb_resolution_queue_.front().first.device_id; int desired_device_id =
ppd_reference_resolution_queue_.front().first.usb_product_id;
if (result == PpdProvider::SUCCESS) { if (result == PpdProvider::SUCCESS) {
// Parse the JSON response. This should be a list of the form // Parse the JSON response. This should be a list of the form
// [ // [
...@@ -732,13 +750,14 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -732,13 +750,14 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
} }
} }
} }
if (result != PpdProvider::SUCCESS) { Printer::PpdReference ret;
contents.clear(); if (result == PpdProvider::SUCCESS) {
ret.effective_make_and_model = contents;
} }
base::SequencedTaskRunnerHandle::Get()->PostTask( base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE, base::Bind(ppd_reference_resolution_queue_.front().second,
base::Bind(usb_resolution_queue_.front().second, result, contents)); result, ret));
usb_resolution_queue_.pop_front(); ppd_reference_resolution_queue_.pop_front();
} }
// Something went wrong during metadata fetches. Fail all queued metadata // Something went wrong during metadata fetches. Fail all queued metadata
...@@ -751,13 +770,13 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -751,13 +770,13 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
manufacturers_resolution_queue_.clear(); manufacturers_resolution_queue_.clear();
} }
// Fail all server-based ppd resolutions inflight, because we failed to grab // Fail all server-based ppd and ppd reference resolutions inflight, because
// the necessary index data from the server. Note we leave any user-based ppd // we failed to grab the necessary index data from the server. Note we leave
// resolutions intact, as they don't depend on the data we're missing. // any user-based ppd resolutions intact, as they don't depend on the data
// we're missing.
void FailQueuedServerPpdResolutions(PpdProvider::CallbackResultCode code) { void FailQueuedServerPpdResolutions(PpdProvider::CallbackResultCode code) {
std::deque<std::pair<Printer::PpdReference, ResolvePpdCallback>> std::deque<std::pair<Printer::PpdReference, ResolvePpdCallback>>
filtered_queue; filtered_queue;
for (const auto& entry : ppd_resolution_queue_) { for (const auto& entry : ppd_resolution_queue_) {
if (!entry.first.user_supplied_ppd_url.empty()) { if (!entry.first.user_supplied_ppd_url.empty()) {
filtered_queue.push_back(entry); filtered_queue.push_back(entry);
...@@ -766,6 +785,15 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -766,6 +785,15 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
} }
} }
ppd_resolution_queue_ = std::move(filtered_queue); ppd_resolution_queue_ = std::move(filtered_queue);
// Everything in the ppdreference queue also depends on server information,
// so should also be failed.
auto task_runner = base::SequencedTaskRunnerHandle::Get();
for (const auto& entry : ppd_reference_resolution_queue_) {
task_runner->PostTask(
FROM_HERE, base::Bind(entry.second, code, Printer::PpdReference()));
}
ppd_reference_resolution_queue_.clear();
} }
// Given a list of possible locale strings (e.g. 'en-GB'), determine which of // Given a list of possible locale strings (e.g. 'en-GB'), determine which of
...@@ -927,16 +955,22 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -927,16 +955,22 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
// Get the list of printers from a given manufacturer from |cached_metadata_|. // Get the list of printers from a given manufacturer from |cached_metadata_|.
// Requires that we have already resolved this from the server. // Requires that we have already resolved this from the server.
std::vector<std::string> GetManufacturerPrinterList( ResolvedPrintersList GetManufacturerPrinterList(
const ManufacturerMetadata& meta) const { const ManufacturerMetadata& meta) const {
CHECK(meta.printers.get() != nullptr); CHECK(meta.printers.get() != nullptr);
std::vector<std::string> ret; ResolvedPrintersList ret;
ret.reserve(meta.printers->size()); ret.reserve(meta.printers->size());
for (const auto& entry : *meta.printers) { for (const auto& entry : *meta.printers) {
ret.push_back(entry.first); Printer::PpdReference ppd_ref;
ppd_ref.effective_make_and_model = entry.second;
ret.push_back({entry.first, ppd_ref});
} }
// TODO(justincarlson) -- this should be a localization-aware sort. // TODO(justincarlson) -- this should be a localization-aware sort.
sort(ret.begin(), ret.end()); sort(ret.begin(), ret.end(),
[](const std::pair<std::string, Printer::PpdReference>& a,
const std::pair<std::string, Printer::PpdReference>& b) -> bool {
return a.first < b.first;
});
return ret; return ret;
} }
...@@ -967,9 +1001,9 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -967,9 +1001,9 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
std::deque<std::pair<Printer::PpdReference, ResolvePpdCallback>> std::deque<std::pair<Printer::PpdReference, ResolvePpdCallback>>
ppd_resolution_queue_; ppd_resolution_queue_;
// Queued ResolveUsbIds() requests. // Queued ResolvePpdReference() requests.
std::deque<std::pair<UsbDeviceId, ResolveUsbIdsCallback>> std::deque<std::pair<PrinterSearchData, ResolvePpdReferenceCallback>>
usb_resolution_queue_; ppd_reference_resolution_queue_;
// Locale we're using for grabbing stuff from the server. Empty if we haven't // Locale we're using for grabbing stuff from the server. Empty if we haven't
// determined it yet. // determined it yet.
...@@ -1010,6 +1044,11 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate { ...@@ -1010,6 +1044,11 @@ class PpdProviderImpl : public PpdProvider, public net::URLFetcherDelegate {
} // namespace } // namespace
PpdProvider::PrinterSearchData::PrinterSearchData() = default;
PpdProvider::PrinterSearchData::PrinterSearchData(
const PrinterSearchData& other) = default;
PpdProvider::PrinterSearchData::~PrinterSearchData() = default;
// static // static
scoped_refptr<PpdProvider> PpdProvider::Create( scoped_refptr<PpdProvider> PpdProvider::Create(
const std::string& browser_locale, const std::string& browser_locale,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "base/callback.h" #include "base/callback.h"
...@@ -55,6 +56,25 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> { ...@@ -55,6 +56,25 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> {
std::string ppd_server_root = "https://www.gstatic.com/chromeos_printing"; std::string ppd_server_root = "https://www.gstatic.com/chromeos_printing";
}; };
// Everything we might know about a printer when looking for a
// driver for it. All of the default values for fields in this struct
// mean we *don't* have that piece of information.
//
// Fields are listed in search order preference -- we use earlier
// fields first to attempt to find a match.
struct PrinterSearchData {
PrinterSearchData();
PrinterSearchData(const PrinterSearchData& other);
~PrinterSearchData();
// Make-and-model string guesses.
std::vector<std::string> make_and_model;
// 16-bit usb identifiers.
int usb_vendor_id = 0;
int usb_product_id = 0;
};
// Result of a ResolvePpd() call. // Result of a ResolvePpd() call.
// If the result code is SUCCESS, then: // If the result code is SUCCESS, then:
// string holds the contents of a PPD (that may or may not be gzipped). // string holds the contents of a PPD (that may or may not be gzipped).
...@@ -71,17 +91,25 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> { ...@@ -71,17 +91,25 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> {
using ResolveManufacturersCallback = using ResolveManufacturersCallback =
base::Callback<void(CallbackResultCode, const std::vector<std::string>&)>; base::Callback<void(CallbackResultCode, const std::vector<std::string>&)>;
// A list of printer names paired with the PpdReference that should be used
// for that printer.
using ResolvedPrintersList =
std::vector<std::pair<std::string, Printer::PpdReference>>;
// Result of a ResolvePrinters() call. If the result code is SUCCESS, then // Result of a ResolvePrinters() call. If the result code is SUCCESS, then
// the vector contains a sorted list of all printer models from the given // the vector contains a sorted list <model_name, PpdReference> tuples of all
// manufacturer for which we have a driver. // printer models from the given manufacturer for which we have a driver,
// sorted by model_name.
using ResolvePrintersCallback = using ResolvePrintersCallback =
base::Callback<void(CallbackResultCode, const std::vector<std::string>&)>; base::Callback<void(CallbackResultCode, const ResolvedPrintersList&)>;
// Result of a ResolveUsbIds call. If the result code is SUCCESS, then the // Result of a ResolvePpdReference call. If the result code is
// second argument contains the effective make and model of the printer. // SUCCESS, then the second argument contains the a PpdReference
// NOT_FOUND means we don't know about this Usb device. // that we have high confidence can be used to obtain a driver for
using ResolveUsbIdsCallback = // the printer. NOT_FOUND means we couldn't confidently figure out
base::Callback<void(CallbackResultCode, const std::string&)>; // a driver for the printer.
using ResolvePpdReferenceCallback =
base::Callback<void(CallbackResultCode, const Printer::PpdReference&)>;
// Create and return a new PpdProvider with the given cache and options. // Create and return a new PpdProvider with the given cache and options.
// A references to |url_context_getter| is taken. // A references to |url_context_getter| is taken.
...@@ -97,33 +125,20 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> { ...@@ -97,33 +125,20 @@ class CHROMEOS_EXPORT PpdProvider : public base::RefCounted<PpdProvider> {
// |cb| will be called on the invoking thread, and will be sequenced. // |cb| will be called on the invoking thread, and will be sequenced.
virtual void ResolveManufacturers(const ResolveManufacturersCallback& cb) = 0; virtual void ResolveManufacturers(const ResolveManufacturersCallback& cb) = 0;
// Get all models from a given manufacturer, localized in the default browser // Get all models from a given manufacturer, localized in the
// locale or the closest available fallback. |manufacturer| must be a value // default browser locale or the closest available fallback.
// returned from a successful ResolveManufacturers() call performed from this // |manufacturer| must be a value returned from a successful
// PpdProvider instance. // ResolveManufacturers() call performed from this PpdProvider
// instance.
// //
// |cb| will be called on the invoking thread, and will be sequenced. // |cb| will be called on the invoking thread, and will be sequenced.
virtual void ResolvePrinters(const std::string& manufacturer, virtual void ResolvePrinters(const std::string& manufacturer,
const ResolvePrintersCallback& cb) = 0; const ResolvePrintersCallback& cb) = 0;
// Given a usb vendor/device id, attempt to get an effective make and model // Attempt to find a PpdReference for the given printer. You should supply
// string for the given printer. // as much information in search_data as you can.
virtual void ResolveUsbIds(int vendor_id, virtual void ResolvePpdReference(const PrinterSearchData& search_data,
int device_id, const ResolvePpdReferenceCallback& cb) = 0;
const ResolveUsbIdsCallback& cb) = 0;
// Given a |manufacturer| from ResolveManufacturers() and a |printer| from
// a ResolvePrinters() call for that manufacturer, fill in |reference|
// with the information needed to resolve the Ppd for this printer. Returns
// true on success and overwrites the contents of |reference|. On failure,
// |reference| is unchanged.
//
// Note that, unlike the other functions in this class, |reference| can be
// saved and given to ResolvePpd() in a different PpdProvider instance without
// first resolving manufactuerers or printers.
virtual bool GetPpdReference(const std::string& manufacturer,
const std::string& printer,
Printer::PpdReference* reference) const = 0;
// Given a PpdReference, attempt to get the PPD for printing. // Given a PpdReference, attempt to get the PPD for printing.
// //
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "chromeos/chromeos_paths.h" #include "chromeos/chromeos_paths.h"
#include "chromeos/printing/ppd_cache.h" #include "chromeos/printing/ppd_cache.h"
#include "chromeos/printing/ppd_provider.h" #include "chromeos/printing/ppd_provider.h"
#include "chromeos/printing/printer_configuration.h"
#include "net/url_request/test_url_request_interceptor.h" #include "net/url_request/test_url_request_interceptor.h"
#include "net/url_request/url_request_test_util.h" #include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -167,7 +168,7 @@ class PpdProviderTest : public ::testing::Test { ...@@ -167,7 +168,7 @@ class PpdProviderTest : public ::testing::Test {
// Capture the result of a ResolvePrinters() call. // Capture the result of a ResolvePrinters() call.
void CaptureResolvePrinters(PpdProvider::CallbackResultCode code, void CaptureResolvePrinters(PpdProvider::CallbackResultCode code,
const std::vector<std::string>& data) { const PpdProvider::ResolvedPrintersList& data) {
captured_resolve_printers_.push_back({code, data}); captured_resolve_printers_.push_back({code, data});
} }
...@@ -183,9 +184,9 @@ class PpdProviderTest : public ::testing::Test { ...@@ -183,9 +184,9 @@ class PpdProviderTest : public ::testing::Test {
} }
// Capture the result of a ResolveUsbIds() call. // Capture the result of a ResolveUsbIds() call.
void CaptureResolveUsbIds(PpdProvider::CallbackResultCode code, void CaptureResolvePpdReference(PpdProvider::CallbackResultCode code,
const std::string& contents) { const Printer::PpdReference& ref) {
captured_resolve_usb_ids_.push_back({code, contents}); captured_resolve_ppd_references_.push_back({code, ref});
} }
// Discard the result of a ResolvePpd() call. // Discard the result of a ResolvePpd() call.
...@@ -222,8 +223,8 @@ class PpdProviderTest : public ::testing::Test { ...@@ -222,8 +223,8 @@ class PpdProviderTest : public ::testing::Test {
std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>> std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>>
captured_resolve_manufacturers_; captured_resolve_manufacturers_;
std::vector< std::vector<std::pair<PpdProvider::CallbackResultCode,
std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>> PpdProvider::ResolvedPrintersList>>
captured_resolve_printers_; captured_resolve_printers_;
struct CapturedResolvePpdResults { struct CapturedResolvePpdResults {
...@@ -233,8 +234,8 @@ class PpdProviderTest : public ::testing::Test { ...@@ -233,8 +234,8 @@ class PpdProviderTest : public ::testing::Test {
}; };
std::vector<CapturedResolvePpdResults> captured_resolve_ppd_; std::vector<CapturedResolvePpdResults> captured_resolve_ppd_;
std::vector<std::pair<PpdProvider::CallbackResultCode, std::string>> std::vector<std::pair<PpdProvider::CallbackResultCode, Printer::PpdReference>>
captured_resolve_usb_ids_; captured_resolve_ppd_references_;
std::unique_ptr<net::TestURLRequestInterceptor> interceptor_; std::unique_ptr<net::TestURLRequestInterceptor> interceptor_;
...@@ -303,39 +304,49 @@ TEST_F(PpdProviderTest, UsbResolution) { ...@@ -303,39 +304,49 @@ TEST_F(PpdProviderTest, UsbResolution) {
StartFakePpdServer(); StartFakePpdServer();
auto provider = CreateProvider("en"); auto provider = CreateProvider("en");
PpdProvider::PrinterSearchData search_data;
// Should get back "Some canonical reference" // Should get back "Some canonical reference"
provider->ResolveUsbIds(0x031f, 1592, search_data.usb_vendor_id = 0x031f;
base::Bind(&PpdProviderTest::CaptureResolveUsbIds, search_data.usb_product_id = 1592;
base::Unretained(this))); provider->ResolvePpdReference(
search_data, base::Bind(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
// Should get back "Some other canonical reference" // Should get back "Some other canonical reference"
provider->ResolveUsbIds(0x031f, 6535, search_data.usb_vendor_id = 0x031f;
base::Bind(&PpdProviderTest::CaptureResolveUsbIds, search_data.usb_product_id = 6535;
base::Unretained(this))); provider->ResolvePpdReference(
search_data, base::Bind(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
// Extant vendor id, nonexistant device id, should get a NOT_FOUND // Extant vendor id, nonexistant device id, should get a NOT_FOUND
provider->ResolveUsbIds(0x031f, 8162, search_data.usb_vendor_id = 0x031f;
base::Bind(&PpdProviderTest::CaptureResolveUsbIds, search_data.usb_product_id = 8162;
base::Unretained(this))); provider->ResolvePpdReference(
search_data, base::Bind(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
// Nonexistant vendor id, should get a NOT_FOUND in the real world, but // Nonexistant vendor id, should get a NOT_FOUND in the real world, but
// the URL interceptor we're using considers all nonexistant files to // the URL interceptor we're using considers all nonexistant files to
// be effectively CONNECTION REFUSED, so we just check for non-success // be effectively CONNECTION REFUSED, so we just check for non-success
// on this one. // on this one.
provider->ResolveUsbIds(1234, 1782, search_data.usb_vendor_id = 1234;
base::Bind(&PpdProviderTest::CaptureResolveUsbIds, search_data.usb_product_id = 1782;
base::Unretained(this))); provider->ResolvePpdReference(
search_data, base::Bind(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
scoped_task_environment_.RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
ASSERT_EQ(captured_resolve_usb_ids_.size(), static_cast<size_t>(4)); ASSERT_EQ(captured_resolve_ppd_references_.size(), static_cast<size_t>(4));
EXPECT_EQ(captured_resolve_usb_ids_[0].first, PpdProvider::SUCCESS); EXPECT_EQ(captured_resolve_ppd_references_[0].first, PpdProvider::SUCCESS);
EXPECT_EQ(captured_resolve_usb_ids_[0].second, "Some canonical reference"); EXPECT_EQ(captured_resolve_ppd_references_[0].second.effective_make_and_model,
EXPECT_EQ(captured_resolve_usb_ids_[1].first, PpdProvider::SUCCESS); "Some canonical reference");
EXPECT_EQ(captured_resolve_usb_ids_[1].second, EXPECT_EQ(captured_resolve_ppd_references_[1].first, PpdProvider::SUCCESS);
EXPECT_EQ(captured_resolve_ppd_references_[1].second.effective_make_and_model,
"Some other canonical reference"); "Some other canonical reference");
EXPECT_EQ(captured_resolve_usb_ids_[2].first, PpdProvider::NOT_FOUND); EXPECT_EQ(captured_resolve_ppd_references_[2].first, PpdProvider::NOT_FOUND);
EXPECT_EQ(captured_resolve_usb_ids_[2].second, ""); EXPECT_FALSE(captured_resolve_ppd_references_[3].first ==
EXPECT_FALSE(captured_resolve_usb_ids_[3].first == PpdProvider::SUCCESS); PpdProvider::SUCCESS);
EXPECT_EQ(captured_resolve_usb_ids_[3].second, "");
} }
// For convenience a null ResolveManufacturers callback target. // For convenience a null ResolveManufacturers callback target.
...@@ -365,16 +376,23 @@ TEST_F(PpdProviderTest, ResolvePrinters) { ...@@ -365,16 +376,23 @@ TEST_F(PpdProviderTest, ResolvePrinters) {
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first); EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first); EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first);
EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size()); EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size());
EXPECT_EQ(std::vector<std::string>({"printer_a", "printer_b"}),
captured_resolve_printers_[0].second);
EXPECT_EQ(std::vector<std::string>({"printer_c"}),
captured_resolve_printers_[1].second);
// We have manufacturers and models, we should be able to get a ppd out of // First capture should get back printer_a, and printer_b, with ppd
// this. // reference effective make and models of printer_a_ref and printer_b_ref.
Printer::PpdReference ref; const auto& capture0 = captured_resolve_printers_[0].second;
ASSERT_TRUE( ASSERT_EQ(2UL, capture0.size());
provider->GetPpdReference("manufacturer_a_en", "printer_b", &ref)); EXPECT_EQ("printer_a", capture0[0].first);
EXPECT_EQ("printer_a_ref", capture0[0].second.effective_make_and_model);
EXPECT_EQ("printer_b", capture0[1].first);
EXPECT_EQ("printer_b_ref", capture0[1].second.effective_make_and_model);
// Second capture should get back printer_c with effective make and model of
// printer_c_ref
const auto& capture1 = captured_resolve_printers_[1].second;
ASSERT_EQ(1UL, capture1.size());
EXPECT_EQ("printer_c", capture1[0].first);
EXPECT_EQ("printer_c_ref", capture1[0].second.effective_make_and_model);
} }
// Test that if we give a bad reference to ResolvePrinters(), we get an // Test that if we give a bad reference to ResolvePrinters(), we get an
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment