// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/extension_printer_service_ash.h"
#include <memory>
#include <utility>
#include "base/check_is_test.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/unguessable_token.h"
#include "chromeos/crosapi/mojom/extension_printer.mojom.h"
namespace crosapi {
namespace {
void ReportNumberOfLacrosExtensionPrinters(size_t number) {
base::UmaHistogramCounts100000(
"Printing.LacrosExtensions.FromAsh.NumberOfPrinters", number);
}
} // namespace
ExtensionPrinterServiceAsh::ExtensionPrinterServiceAsh() = default;
ExtensionPrinterServiceAsh::~ExtensionPrinterServiceAsh() = default;
void ExtensionPrinterServiceAsh::BindReceiver(
mojo::PendingReceiver<mojom::ExtensionPrinterService> pending_receiver) {
receivers_.Add(this, std::move(pending_receiver));
}
bool ExtensionPrinterServiceAsh::HasProvider() const {
return service_provider_.is_bound() && service_provider_.is_connected();
}
void ExtensionPrinterServiceAsh::ClearPendingRequests() {
// In theory, pending requests should not exist when there is no provider.
if (!HasProvider() && HasAnyPendingGetPrintersRequests()) {
LOG(WARNING) << "ExtensionPrinterServiceAsh::ClearPendingRequests():none "
"ExtensionPrinterServiceProvider available";
}
// Clear pending get printers requests if any.
pending_printers_added_callbacks_.clear();
pending_get_printers_done_callbacks_.clear();
total_printers_so_far_.clear();
weak_ptr_factory_.InvalidateWeakPtrs();
}
void ExtensionPrinterServiceAsh::RegisterServiceProvider(
mojo::PendingRemote<mojom::ExtensionPrinterServiceProvider> provider) {
VLOG(1) << "ExtensionPrinterServiceAsh::RegisterServiceProvider()";
service_provider_ =
mojo::Remote<mojom::ExtensionPrinterServiceProvider>(std::move(provider));
service_provider_.set_disconnect_handler(base::BindOnce(
&ExtensionPrinterServiceAsh::ExtensionPrinterServiceProviderDisconnected,
weak_ptr_factory_.GetWeakPtr()));
}
void ExtensionPrinterServiceAsh::PrintersAdded(
const base::UnguessableToken& request_id,
base::Value::List printers,
bool is_done) {
VLOG(1) << "ExtensionPrinterServiceAsh::PrintersAdded():" << " request_id="
<< request_id.ToString() << " printers.size()=" << printers.size()
<< " done=" << is_done;
if (!printers.empty() &&
pending_printers_added_callbacks_.contains(request_id)) {
total_printers_so_far_[request_id] += printers.size();
pending_printers_added_callbacks_[request_id].Run(std::move(printers));
}
if (!is_done) {
return;
}
// Calls the done callback and clear the caches for the request_id.
if (pending_get_printers_done_callbacks_.contains(request_id)) {
std::move(pending_get_printers_done_callbacks_[request_id]).Run();
pending_get_printers_done_callbacks_.erase(request_id);
}
pending_printers_added_callbacks_.erase(request_id);
// Record number of printers if any from all printing extensions.
if (total_printers_so_far_[request_id] > 0) {
ReportNumberOfLacrosExtensionPrinters(total_printers_so_far_[request_id]);
total_printers_so_far_.erase(request_id);
}
}
void ExtensionPrinterServiceAsh::ExtensionPrinterServiceProviderDisconnected() {
VLOG(1) << "ExtensionPrinterServiceProviderDisconnected()";
ClearPendingRequests();
}
void ExtensionPrinterServiceAsh::StartGetPrinters(
AddedPrintersCallback added_printers_callback,
GetPrintersDoneCallback done_callback) {
// Checks whether there is any ExtensionPrinterServiceProvider registered.
if (!HasProvider()) {
LOG(WARNING) << "ExtensionPrinterServiceAsh::StartGetPrinters: none "
"ExtensionPrinterServiceProvider available";
std::move(done_callback).Run();
return;
}
// Generates a request_id and caches the callbacks.
base::UnguessableToken request_id = base::UnguessableToken::Create();
pending_printers_added_callbacks_[request_id] =
std::move(added_printers_callback);
pending_get_printers_done_callbacks_[request_id] = std::move(done_callback);
VLOG(1) << "ExtensionPrinterServiceAsh::StartGetPrinters():" << " request_id="
<< request_id.ToString();
service_provider_->DispatchGetPrintersRequest(request_id);
}
void ExtensionPrinterServiceAsh::Reset() {
VLOG(1) << "ExtensionPrinterServiceAsh::Reset():";
// Clears local states.
ClearPendingRequests();
// Asks downstream to clear states.
if (HasProvider()) {
service_provider_->DispatchResetRequest();
}
}
void ExtensionPrinterServiceAsh::StartGetCapability(
const std::string& destination_id,
GetCapabilityCallback callback) {
VLOG(1) << "ExtensionPrinterServiceAsh::StartGetCapability():"
<< " destination_id=" << destination_id;
if (!HasProvider()) {
LOG(WARNING) << "ExtensionPrinterServiceAsh::StartGetCapability(): none "
"ExtensionPrinterServiceProvider available";
std::move(callback).Run(base::Value::Dict());
return;
}
service_provider_->DispatchStartGetCapability(destination_id,
std::move(callback));
}
bool ExtensionPrinterServiceAsh::HasAnyPendingGetPrintersRequests() const {
return !pending_get_printers_done_callbacks_.empty() ||
!pending_printers_added_callbacks_.empty();
}
void ExtensionPrinterServiceAsh::StartPrint(
const std::u16string& job_title,
base::Value::Dict settings,
scoped_refptr<base::RefCountedMemory> print_data,
StartPrintCallback callback) {
VLOG(1) << "ExtensionPrinterServiceAsh::StartPrint():" << " job_title="
<< job_title;
if (!HasProvider()) {
LOG(WARNING) << "ExtensionPrinterServiceAsh::StartPrint(): none "
"ExtensionPrinterServiceProvider available";
std::move(callback).Run(crosapi::mojom::StartPrintStatus::kFailed);
return;
}
service_provider_->DispatchStartPrint(job_title, std::move(settings),
print_data, std::move(callback));
}
void ExtensionPrinterServiceAsh::StartGrantPrinterAccess(
const std::string& printer_id,
GetPrinterInfoCallback callback) {
VLOG(1) << "ExtensionPrinterServiceAsh::StartGrantPrinterAccess():"
<< " printer_id=" << printer_id;
if (!HasProvider()) {
LOG(WARNING)
<< "ExtensionPrinterServiceAsh::StartGrantPrinterAccess(): none "
"ExtensionPrinterServiceProvider available";
std::move(callback).Run(base::Value::Dict());
return;
}
service_provider_->DispatchStartGrantPrinterAccess(printer_id,
std::move(callback));
}
bool ExtensionPrinterServiceAsh::HasPendingGetPrintersRequestForTesting(
base::UnguessableToken& request_id) const {
CHECK_IS_TEST();
return pending_get_printers_done_callbacks_.contains(request_id) &&
pending_printers_added_callbacks_.contains(request_id);
}
bool ExtensionPrinterServiceAsh::HasProviderForTesting() const {
CHECK_IS_TEST();
return HasProvider();
}
} // namespace crosapi