Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / extensions / browser / api / printer_provider / printer_provider_api.cc
blob9e84186b7dfa2c073e5cb1fe40aafe95e0a94853
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 "extensions/browser/api/printer_provider/printer_provider_api.h"
7 #include <utility>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/lazy_instance.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h"
15 #include "extensions/browser/event_router.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extension_registry_factory.h"
18 #include "extensions/common/api/printer_provider.h"
19 #include "extensions/common/api/printer_provider_internal.h"
20 #include "extensions/common/extension.h"
22 namespace extensions {
24 namespace {
26 static base::LazyInstance<BrowserContextKeyedAPIFactory<PrinterProviderAPI>>
27 g_api_factory = LAZY_INSTANCE_INITIALIZER;
29 // The separator between extension id and the extension's internal printer id
30 // used when generating a printer id unique across extensions.
31 const char kPrinterIdSeparator = ':';
33 // Given an extension ID and an ID of a printer reported by the extension, it
34 // generates a ID for the printer unique across extensions (assuming that the
35 // printer id is unique in the extension's space).
36 std::string GeneratePrinterId(const std::string& extension_id,
37 const std::string& internal_printer_id) {
38 std::string result = extension_id;
39 result.append(1, kPrinterIdSeparator);
40 result.append(internal_printer_id);
41 return result;
44 // Parses an ID created using |GeneratePrinterId| to it's components:
45 // the extension ID and the printer ID internal to the extension.
46 // Returns whenter the ID was succesfully parsed.
47 bool ParsePrinterId(const std::string& printer_id,
48 std::string* extension_id,
49 std::string* internal_printer_id) {
50 size_t separator = printer_id.find_first_of(kPrinterIdSeparator);
51 if (separator == std::string::npos)
52 return false;
53 *extension_id = printer_id.substr(0, separator);
54 *internal_printer_id = printer_id.substr(separator + 1);
55 return true;
58 PrinterProviderAPI::PrintError APIPrintErrorToInternalType(
59 core_api::printer_provider_internal::PrintError error) {
60 switch (error) {
61 case core_api::printer_provider_internal::PRINT_ERROR_NONE:
62 // The PrintError parameter is not set, which implies an error.
63 return PrinterProviderAPI::PRINT_ERROR_FAILED;
64 case core_api::printer_provider_internal::PRINT_ERROR_OK:
65 return PrinterProviderAPI::PRINT_ERROR_NONE;
66 case core_api::printer_provider_internal::PRINT_ERROR_FAILED:
67 return PrinterProviderAPI::PRINT_ERROR_FAILED;
68 case core_api::printer_provider_internal::PRINT_ERROR_INVALID_TICKET:
69 return PrinterProviderAPI::PRINT_ERROR_INVALID_TICKET;
70 case core_api::printer_provider_internal::PRINT_ERROR_INVALID_DATA:
71 return PrinterProviderAPI::PRINT_ERROR_INVALID_DATA;
73 return PrinterProviderAPI::PRINT_ERROR_FAILED;
76 } // namespace
78 PrinterProviderAPI::PrintJob::PrintJob() {
81 PrinterProviderAPI::PrintJob::~PrintJob() {
84 // static
85 BrowserContextKeyedAPIFactory<PrinterProviderAPI>*
86 PrinterProviderAPI::GetFactoryInstance() {
87 return g_api_factory.Pointer();
90 PrinterProviderAPI::PrinterProviderAPI(content::BrowserContext* browser_context)
91 : browser_context_(browser_context),
92 internal_api_observer_(this),
93 extension_registry_observer_(this) {
94 internal_api_observer_.Add(
95 PrinterProviderInternalAPI::GetFactoryInstance()->Get(browser_context));
96 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context));
99 PrinterProviderAPI::~PrinterProviderAPI() {
102 void PrinterProviderAPI::DispatchGetPrintersRequested(
103 const GetPrintersCallback& callback) {
104 EventRouter* event_router = EventRouter::Get(browser_context_);
105 if (!event_router->HasEventListener(
106 core_api::printer_provider::OnGetPrintersRequested::kEventName)) {
107 callback.Run(base::ListValue(), true /* done */);
108 return;
111 scoped_ptr<GetPrintersRequest> request(new GetPrintersRequest(callback));
112 // |pending_get_printers_requests_| take ownership of |request| which gets
113 // NULLed out. Save the pointer before passing it to the requests, as it will
114 // be needed later on.
115 GetPrintersRequest* raw_request_ptr = request.get();
116 int request_id = pending_get_printers_requests_.Add(request.Pass());
118 scoped_ptr<base::ListValue> internal_args(new base::ListValue);
119 // Request id is not part of the public API, but it will be massaged out in
120 // custom bindings.
121 internal_args->AppendInteger(request_id);
123 scoped_ptr<Event> event(
124 new Event(core_api::printer_provider::OnGetPrintersRequested::kEventName,
125 internal_args.Pass()));
126 // This callback is called synchronously during |BroadcastEvent|, so
127 // Unretained is safe. Also, |raw_request_ptr| will stay valid at least until
128 // |BroadcastEvent| finishes.
129 event->will_dispatch_callback =
130 base::Bind(&PrinterProviderAPI::WillRequestPrinters,
131 base::Unretained(this), raw_request_ptr);
133 event_router->BroadcastEvent(event.Pass());
136 void PrinterProviderAPI::DispatchGetCapabilityRequested(
137 const std::string& printer_id,
138 const PrinterProviderAPI::GetCapabilityCallback& callback) {
139 std::string extension_id;
140 std::string internal_printer_id;
141 if (!ParsePrinterId(printer_id, &extension_id, &internal_printer_id)) {
142 callback.Run(base::DictionaryValue());
143 return;
146 EventRouter* event_router = EventRouter::Get(browser_context_);
147 if (!event_router->ExtensionHasEventListener(
148 extension_id,
149 core_api::printer_provider::OnGetCapabilityRequested::kEventName)) {
150 callback.Run(base::DictionaryValue());
151 return;
154 int request_id = pending_capability_requests_[extension_id].Add(callback);
156 scoped_ptr<base::ListValue> internal_args(new base::ListValue);
157 // Request id is not part of the public API, but it will be massaged out in
158 // custom bindings.
159 internal_args->AppendInteger(request_id);
160 internal_args->AppendString(internal_printer_id);
162 scoped_ptr<Event> event(new Event(
163 core_api::printer_provider::OnGetCapabilityRequested::kEventName,
164 internal_args.Pass()));
166 event_router->DispatchEventToExtension(extension_id, event.Pass());
169 void PrinterProviderAPI::DispatchPrintRequested(
170 const PrinterProviderAPI::PrintJob& job,
171 const PrinterProviderAPI::PrintCallback& callback) {
172 std::string extension_id;
173 std::string internal_printer_id;
174 if (!ParsePrinterId(job.printer_id, &extension_id, &internal_printer_id)) {
175 callback.Run(PRINT_ERROR_FAILED);
176 return;
179 EventRouter* event_router = EventRouter::Get(browser_context_);
180 if (!event_router->ExtensionHasEventListener(
181 extension_id,
182 core_api::printer_provider::OnPrintRequested::kEventName)) {
183 callback.Run(PRINT_ERROR_FAILED);
184 return;
187 core_api::printer_provider::PrintJob print_job;
188 print_job.printer_id = internal_printer_id;
189 print_job.content_type = job.content_type;
190 print_job.document =
191 std::vector<char>(job.document_bytes.begin(), job.document_bytes.end());
193 int request_id = pending_print_requests_[extension_id].Add(callback);
195 scoped_ptr<base::ListValue> internal_args(new base::ListValue);
196 // Request id is not part of the public API and it will be massaged out in
197 // custom bindings.
198 internal_args->AppendInteger(request_id);
199 internal_args->Append(print_job.ToValue().release());
200 scoped_ptr<Event> event(
201 new Event(core_api::printer_provider::OnPrintRequested::kEventName,
202 internal_args.Pass()));
204 event_router->DispatchEventToExtension(extension_id, event.Pass());
207 PrinterProviderAPI::GetPrintersRequest::GetPrintersRequest(
208 const GetPrintersCallback& callback)
209 : callback_(callback) {
212 PrinterProviderAPI::GetPrintersRequest::~GetPrintersRequest() {
215 void PrinterProviderAPI::GetPrintersRequest::AddSource(
216 const std::string& extension_id) {
217 extensions_.insert(extension_id);
220 bool PrinterProviderAPI::GetPrintersRequest::IsDone() const {
221 return extensions_.empty();
224 void PrinterProviderAPI::GetPrintersRequest::ReportForExtension(
225 const std::string& extension_id,
226 const base::ListValue& printers) {
227 if (extensions_.erase(extension_id) > 0)
228 callback_.Run(printers, IsDone());
231 PrinterProviderAPI::PendingGetPrintersRequests::PendingGetPrintersRequests()
232 : last_request_id_(0) {
235 PrinterProviderAPI::PendingGetPrintersRequests::~PendingGetPrintersRequests() {
236 STLDeleteContainerPairSecondPointers(pending_requests_.begin(),
237 pending_requests_.end());
240 int PrinterProviderAPI::PendingGetPrintersRequests::Add(
241 scoped_ptr<GetPrintersRequest> request) {
242 pending_requests_[++last_request_id_] = request.release();
243 return last_request_id_;
246 bool PrinterProviderAPI::PendingGetPrintersRequests::CompleteForExtension(
247 const std::string& extension_id,
248 int request_id,
249 const base::ListValue& result) {
250 auto it = pending_requests_.find(request_id);
251 if (it == pending_requests_.end())
252 return false;
254 GetPrintersRequest* request = it->second;
255 request->ReportForExtension(extension_id, result);
256 if (request->IsDone()) {
257 pending_requests_.erase(it);
258 delete request;
260 return true;
263 void PrinterProviderAPI::PendingGetPrintersRequests::FailAllForExtension(
264 const std::string& extension_id) {
265 auto it = pending_requests_.begin();
266 while (it != pending_requests_.end()) {
267 int request_id = it->first;
268 // |it| may get deleted during |CompleteForExtension|, so progress it to the
269 // next item before calling the method.
270 ++it;
271 CompleteForExtension(extension_id, request_id, base::ListValue());
275 PrinterProviderAPI::PendingGetCapabilityRequests::PendingGetCapabilityRequests()
276 : last_request_id_(0) {
279 PrinterProviderAPI::PendingGetCapabilityRequests::
280 ~PendingGetCapabilityRequests() {
283 int PrinterProviderAPI::PendingGetCapabilityRequests::Add(
284 const PrinterProviderAPI::GetCapabilityCallback& callback) {
285 pending_requests_[++last_request_id_] = callback;
286 return last_request_id_;
289 bool PrinterProviderAPI::PendingGetCapabilityRequests::Complete(
290 int request_id,
291 const base::DictionaryValue& response) {
292 auto it = pending_requests_.find(request_id);
293 if (it == pending_requests_.end())
294 return false;
296 GetCapabilityCallback callback = it->second;
297 pending_requests_.erase(it);
299 callback.Run(response);
300 return true;
303 void PrinterProviderAPI::PendingGetCapabilityRequests::FailAll() {
304 for (auto& request : pending_requests_)
305 request.second.Run(base::DictionaryValue());
306 pending_requests_.clear();
309 PrinterProviderAPI::PendingPrintRequests::PendingPrintRequests()
310 : last_request_id_(0) {
313 PrinterProviderAPI::PendingPrintRequests::~PendingPrintRequests() {
316 int PrinterProviderAPI::PendingPrintRequests::Add(
317 const PrinterProviderAPI::PrintCallback& callback) {
318 pending_requests_[++last_request_id_] = callback;
319 return last_request_id_;
322 bool PrinterProviderAPI::PendingPrintRequests::Complete(int request_id,
323 PrintError response) {
324 auto it = pending_requests_.find(request_id);
325 if (it == pending_requests_.end())
326 return false;
328 PrintCallback callback = it->second;
329 pending_requests_.erase(it);
331 callback.Run(response);
332 return true;
335 void PrinterProviderAPI::PendingPrintRequests::FailAll() {
336 for (auto& request : pending_requests_)
337 request.second.Run(PRINT_ERROR_FAILED);
338 pending_requests_.clear();
341 void PrinterProviderAPI::OnGetPrintersResult(
342 const Extension* extension,
343 int request_id,
344 const PrinterProviderInternalAPIObserver::PrinterInfoVector& result) {
345 base::ListValue printer_list;
347 // Update some printer description properties to better identify the extension
348 // managing the printer.
349 for (size_t i = 0; i < result.size(); ++i) {
350 scoped_ptr<base::DictionaryValue> printer(result[i]->ToValue());
351 std::string internal_printer_id;
352 CHECK(printer->GetString("id", &internal_printer_id));
353 printer->SetString("id",
354 GeneratePrinterId(extension->id(), internal_printer_id));
355 printer->SetString("extensionId", extension->id());
356 printer_list.Append(printer.release());
359 pending_get_printers_requests_.CompleteForExtension(extension->id(),
360 request_id, printer_list);
363 void PrinterProviderAPI::OnGetCapabilityResult(
364 const Extension* extension,
365 int request_id,
366 const base::DictionaryValue& result) {
367 pending_capability_requests_[extension->id()].Complete(request_id, result);
370 void PrinterProviderAPI::OnPrintResult(
371 const Extension* extension,
372 int request_id,
373 core_api::printer_provider_internal::PrintError error) {
374 pending_print_requests_[extension->id()].Complete(
375 request_id, APIPrintErrorToInternalType(error));
378 void PrinterProviderAPI::OnExtensionUnloaded(
379 content::BrowserContext* browser_context,
380 const Extension* extension,
381 UnloadedExtensionInfo::Reason reason) {
382 pending_get_printers_requests_.FailAllForExtension(extension->id());
384 auto print_it = pending_print_requests_.find(extension->id());
385 if (print_it != pending_print_requests_.end()) {
386 print_it->second.FailAll();
387 pending_print_requests_.erase(print_it);
390 auto capability_it = pending_capability_requests_.find(extension->id());
391 if (capability_it != pending_capability_requests_.end()) {
392 capability_it->second.FailAll();
393 pending_capability_requests_.erase(capability_it);
397 bool PrinterProviderAPI::WillRequestPrinters(
398 PrinterProviderAPI::GetPrintersRequest* request,
399 content::BrowserContext* browser_context,
400 const Extension* extension,
401 base::ListValue* args) const {
402 if (!extension)
403 return false;
404 EventRouter* event_router = EventRouter::Get(browser_context_);
405 if (!event_router->ExtensionHasEventListener(
406 extension->id(),
407 core_api::printer_provider::OnGetPrintersRequested::kEventName)) {
408 return false;
411 request->AddSource(extension->id());
412 return true;
415 template <>
416 void BrowserContextKeyedAPIFactory<
417 PrinterProviderAPI>::DeclareFactoryDependencies() {
418 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
419 DependsOn(PrinterProviderInternalAPI::GetFactoryInstance());
420 DependsOn(ExtensionRegistryFactory::GetInstance());
423 } // namespace extensions