blob: 0bd3e4c3fea2dfca9ee142c6f75244de2c9ac0ce [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_API_PRINTER_PROVIDER_PRINTER_PROVIDER_API_H_
#define EXTENSIONS_BROWSER_API_PRINTER_PROVIDER_PRINTER_PROVIDER_API_H_
#include <map>
#include <set>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/scoped_observer.h"
#include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_registry_observer.h"
namespace base {
class DictionaryValue;
class ListValue;
}
namespace content {
class BrowserContext;
}
namespace extensions {
class Extension;
class ExtensionRegistry;
class PrinterProviderInternalAPI;
}
namespace extensions {
// Implements chrome.printerProvider API events.
class PrinterProviderAPI : public BrowserContextKeyedAPI,
public PrinterProviderInternalAPIObserver,
public ExtensionRegistryObserver {
public:
// Struct describing print job that should be forwarded to an extension via
// chrome.printerProvider.onPrintRequested event.
struct PrintJob {
PrintJob();
~PrintJob();
// The id of the printer that should handle the print job. The id is
// formatted as <extension_id>:<printer_id>, where <extension_id> is the
// id of the extension that manages the printer, and <printer_id> is
// the the printer's id within the extension (as reported via
// chrome.printerProvider.onGetPrintersRequested event callback).
std::string printer_id;
// The print job ticket.
std::string ticket_json;
// Content type of the document that should be printed.
std::string content_type;
// The document data that should be printed.
scoped_refptr<base::RefCountedMemory> document_bytes;
};
using GetPrintersCallback =
base::Callback<void(const base::ListValue& printers, bool done)>;
using GetCapabilityCallback =
base::Callback<void(const base::DictionaryValue& capability)>;
using PrintCallback =
base::Callback<void(bool success, const std::string& error)>;
static BrowserContextKeyedAPIFactory<PrinterProviderAPI>*
GetFactoryInstance();
static std::string GetDefaultPrintError();
explicit PrinterProviderAPI(content::BrowserContext* browser_context);
~PrinterProviderAPI() override;
// Requests list of supported printers from extensions implementing
// chrome.printerProvider API. It dispatches
// chrome.printerProvider.onGetPrintersRequested event. The callback is
// called once for every extension handling the event with a list of its
// supported printers. The printer values reported by an extension are
// added "extensionId" property that is set to the ID of the extension
// returning the list.
// Note that the "id" property of printer values reported by an extension are
// rewriten as "<extension_id>:<id>" to ensure they are unique across
// different extensions.
void DispatchGetPrintersRequested(const GetPrintersCallback& callback);
// Requests printer capability for a printer with id |printer_id|.
// |printer_id| should be one of the printer ids reported by |GetPrinters|
// callback.
// It dispatches chrome.printerProvider.onGetCapabilityRequested event
// to the extension that manages the printer (which can be determined from
// |printer_id| value).
// |callback| is passed a dictionary value containing printer capabilities as
// reported by the extension.
void DispatchGetCapabilityRequested(const std::string& printer_id,
const GetCapabilityCallback& callback);
// It dispatches chrome.printerProvider.onPrintRequested event with the
// provided print job. The event is dispatched only to the extension that
// manages printer with id |job.printer_id|.
// |callback| is passed the print status returned by the extension, and it
// must not be null.
void DispatchPrintRequested(const PrintJob& job,
const PrintCallback& callback);
// The API currently cannot handle very large files, so the document size that
// may be sent to an extension is restricted.
// TODO(tbarzic): Fix the API to support huge documents.
static const int kMaxDocumentSize = 50 * 1000 * 1000;
private:
friend class BrowserContextKeyedAPIFactory<PrinterProviderAPI>;
// Holds information about a pending onGetPrintersRequested request;
// in particular, the list of extensions to which the event was dispatched but
// which haven't yet responded, and the |GetPrinters| callback associated with
// the event.
class GetPrintersRequest {
public:
explicit GetPrintersRequest(const GetPrintersCallback& callback);
~GetPrintersRequest();
// Adds an extension id to the list of the extensions that need to respond
// to the event.
void AddSource(const std::string& extension_id);
// Whether all extensions have responded to the event.
bool IsDone() const;
// Runs the callback for an extension and removes the extension from the
// list of extensions that still have to respond to the event.
void ReportForExtension(const std::string& extension_id,
const base::ListValue& printers);
private:
// Callback reporting event result for an extension. Called once for each
// extension.
GetPrintersCallback callback_;
// The list of extensions that still have to respond to the event.
std::set<std::string> extensions_;
};
// Keeps track of pending chrome.printerProvider.onGetPrintersRequested
// requests.
class PendingGetPrintersRequests {
public:
PendingGetPrintersRequests();
~PendingGetPrintersRequests();
// Adds a new request to the set of pending requests. Returns the id
// assigned to the request.
int Add(const GetPrintersCallback& callback);
// Completes a request for an extension. It runs the request callback with
// values reported by the extension.
bool CompleteForExtension(const std::string& extension_id,
int request_id,
const base::ListValue& result);
// Runs callbacks for the extension for all requests that are waiting for a
// response from the extension with the provided extension id. Callbacks are
// called as if the extension reported empty set of printers.
void FailAllForExtension(const std::string& extension_id);
// Adds an extension id to the list of the extensions that need to respond
// to the event.
bool AddSource(int request_id, const std::string& extension_id);
private:
int last_request_id_;
std::map<int, GetPrintersRequest> pending_requests_;
DISALLOW_COPY_AND_ASSIGN(PendingGetPrintersRequests);
};
// Keeps track of pending chrome.printerProvider.onGetCapabilityRequested
// requests for an extension.
class PendingGetCapabilityRequests {
public:
PendingGetCapabilityRequests();
~PendingGetCapabilityRequests();
// Adds a new request to the set. Only information needed is the callback
// associated with the request. Returns the id assigned to the request.
int Add(const GetCapabilityCallback& callback);
// Completes the request with the provided request id. It runs the request
// callback and removes the request from the set.
bool Complete(int request_id, const base::DictionaryValue& result);
// Runs all pending callbacks with empty capability value and clears the
// set of pending requests.
void FailAll();
private:
int last_request_id_;
std::map<int, GetCapabilityCallback> pending_requests_;
};
// Keeps track of pending chrome.printerProvider.ontPrintRequested requests
// for an extension.
class PendingPrintRequests {
public:
PendingPrintRequests();
~PendingPrintRequests();
// Adds a new request to the set. Only information needed is the callback
// associated with the request. Returns the id assigned to the request.
int Add(const PrintCallback& callback);
// Completes the request with the provided request id. It runs the request
// callback and removes the request from the set.
bool Complete(int request_id, bool success, const std::string& result);
// Runs all pending callbacks with ERROR_FAILED and clears the set of
// pending requests.
void FailAll();
private:
int last_request_id_;
std::map<int, PrintCallback> pending_requests_;
};
// BrowserContextKeyedAPI implementation.
static const bool kServiceRedirectedInIncognito = true;
static const char* service_name() { return "PrinterProvider"; }
// PrinterProviderInternalAPIObserver implementation:
void OnGetPrintersResult(
const Extension* extension,
int request_id,
const PrinterProviderInternalAPIObserver::PrinterInfoVector& result)
override;
void OnGetCapabilityResult(const Extension* extension,
int request_id,
const base::DictionaryValue& result) override;
void OnPrintResult(
const Extension* extension,
int request_id,
core_api::printer_provider_internal::PrintError error) override;
// ExtensionRegistryObserver implementation:
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionInfo::Reason reason) override;
// Called before chrome.printerProvider.onGetPrintersRequested event is
// dispatched to an extension. It returns whether the extension is interested
// in the event. If the extension listens to the event, it's added to the set
// of |request| sources. |request| is |GetPrintersRequest| object associated
// with the event.
bool WillRequestPrinters(int request_id,
content::BrowserContext* browser_context,
const Extension* extension,
base::ListValue* args);
content::BrowserContext* browser_context_;
PendingGetPrintersRequests pending_get_printers_requests_;
std::map<std::string, PendingPrintRequests> pending_print_requests_;
std::map<std::string, PendingGetCapabilityRequests>
pending_capability_requests_;
ScopedObserver<PrinterProviderInternalAPI, PrinterProviderInternalAPIObserver>
internal_api_observer_;
ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
extension_registry_observer_;
DISALLOW_COPY_AND_ASSIGN(PrinterProviderAPI);
};
template <>
void BrowserContextKeyedAPIFactory<
PrinterProviderAPI>::DeclareFactoryDependencies();
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_PRINTER_PROVIDER_PRINTER_PROVIDER_API_H_