// Copyright 2022 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/accessibility/accessibility_dlc_installer.h"
#include <string_view>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "ui/accessibility/accessibility_features.h"
namespace {
constexpr char kFaceGazeAssetsInstallDurationMetric[] =
"Accessibility.DlcInstallerFaceGazeAssetsInstallationDuration";
constexpr char kFaceGazeAssetsInstallationMetric[] =
"Accessibility.DlcInstallerFaceGazeAssetsSuccess";
constexpr char kPumpkinInstallationMetric[] =
"PumpkinInstaller.InstallationSuccess";
constexpr char kPumpkinInstallDurationMetric[] =
"Accessibility.DlcInstallerPumpkinInstallationDuration";
} // namespace
namespace ash {
AccessibilityDlcInstaller::Callbacks::Callbacks(InstalledCallback on_installed,
ProgressCallback on_progress,
ErrorCallback on_error) {
on_installed_ = std::move(on_installed);
on_progress_ = std::move(on_progress);
on_error_ = std::move(on_error);
}
AccessibilityDlcInstaller::Callbacks::~Callbacks() = default;
void AccessibilityDlcInstaller::Callbacks::RunOnInstalled(
const bool success,
std::string root_path) {
DCHECK(!on_installed_.is_null());
std::move(on_installed_).Run(success, root_path);
}
void AccessibilityDlcInstaller::Callbacks::RunOnProgress(double progress) {
DCHECK(!on_progress_.is_null());
on_progress_.Run(progress);
}
void AccessibilityDlcInstaller::Callbacks::RunOnError(std::string_view error) {
DCHECK(!on_error_.is_null());
std::move(on_error_).Run(error);
}
AccessibilityDlcInstaller::AccessibilityDlcInstaller() = default;
AccessibilityDlcInstaller::~AccessibilityDlcInstaller() = default;
void AccessibilityDlcInstaller::MaybeInstall(DlcType type,
InstalledCallback on_installed,
ProgressCallback on_progress,
ErrorCallback on_error) {
if (pending_requests_[type]) {
std::move(on_error).Run(GetPendingDlcRequestErrorMessage(type));
return;
}
callbacks_.insert_or_assign(
type,
std::make_unique<Callbacks>(std::move(on_installed),
std::move(on_progress), std::move(on_error)));
pending_requests_.insert_or_assign(type, true);
DlcserviceClient::Get()->GetDlcState(
GetDlcName(type),
base::BindOnce(&AccessibilityDlcInstaller::MaybeInstallHelper,
GetWeakPtr(), type));
}
void AccessibilityDlcInstaller::MaybeInstallHelper(
DlcType type,
std::string_view error,
const dlcservice::DlcState& dlc_state) {
pending_requests_.insert_or_assign(type, false);
if (error != dlcservice::kErrorNone) {
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnError(error);
}
return;
}
switch (dlc_state.state()) {
case dlcservice::DlcState_State_INSTALLING:
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnError(GetDlcInstallingErrorMessage(type));
}
return;
case dlcservice::DlcState_State_INSTALLED:
installed_dlcs_.insert(type);
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnInstalled(true, dlc_state.root_path());
}
return;
default:
break;
}
// Install DLC.
pending_requests_.insert_or_assign(type, true);
dlcservice::InstallRequest install_request;
install_request.set_id(GetDlcName(type));
DlcserviceClient::Get()->Install(
install_request,
base::BindOnce(&AccessibilityDlcInstaller::OnInstalled, GetWeakPtr(),
type, base::Time::Now()),
base::BindRepeating(&AccessibilityDlcInstaller::OnProgress, GetWeakPtr(),
type));
}
void AccessibilityDlcInstaller::OnInstalled(
DlcType type,
const base::Time start_time,
const DlcserviceClient::InstallResult& install_result) {
pending_requests_.insert_or_assign(type, false);
// Record success metric.
switch (type) {
case DlcType::kFaceGazeAssets:
base::UmaHistogramBoolean(kFaceGazeAssetsInstallationMetric,
install_result.error == dlcservice::kErrorNone);
break;
case DlcType::kPumpkin:
base::UmaHistogramBoolean(kPumpkinInstallationMetric,
install_result.error == dlcservice::kErrorNone);
break;
}
if (install_result.error != dlcservice::kErrorNone) {
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnError(install_result.error);
}
return;
}
// Record install duration metric.
const base::TimeDelta install_duration = base::Time::Now() - start_time;
switch (type) {
case DlcType::kFaceGazeAssets:
base::UmaHistogramTimes(kFaceGazeAssetsInstallDurationMetric,
install_duration);
break;
case DlcType::kPumpkin:
base::UmaHistogramTimes(kPumpkinInstallDurationMetric, install_duration);
break;
}
installed_dlcs_.insert(type);
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnInstalled(true, install_result.root_path);
}
}
void AccessibilityDlcInstaller::OnProgress(DlcType type, double progress) {
if (GetCallbacks(type)) {
GetCallbacks(type)->RunOnProgress(progress);
}
}
AccessibilityDlcInstaller::Callbacks* AccessibilityDlcInstaller::GetCallbacks(
DlcType type) {
if (!callbacks_[type]) {
return nullptr;
}
return callbacks_[type].get();
}
std::string AccessibilityDlcInstaller::GetDlcName(DlcType type) {
switch (type) {
case DlcType::kFaceGazeAssets:
return "facegaze-assets";
case DlcType::kPumpkin:
return "pumpkin";
}
}
std::string AccessibilityDlcInstaller::GetDlcInstallingErrorMessage(
DlcType type) {
return base::StringPrintf("%s already installing.", GetDlcName(type).c_str());
}
std::string AccessibilityDlcInstaller::GetPendingDlcRequestErrorMessage(
DlcType type) {
return base::StringPrintf("Cannot install %s, DLC request in progress.",
GetDlcName(type).c_str());
}
bool AccessibilityDlcInstaller::IsFaceGazeAssetsInstalled() const {
return base::Contains(installed_dlcs_, DlcType::kFaceGazeAssets);
}
bool AccessibilityDlcInstaller::IsPumpkinInstalled() const {
return base::Contains(installed_dlcs_, DlcType::kPumpkin);
}
base::WeakPtr<AccessibilityDlcInstaller>
AccessibilityDlcInstaller::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace ash