| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/ash/components/language_packs/language_packs_impl.h" |
| |
| #include <optional> |
| #include <string> |
| |
| #include "base/no_destructor.h" |
| #include "chromeos/ash/components/language_packs/language_pack_manager.h" |
| #include "chromeos/ash/components/language_packs/public/mojom/language_packs.mojom-shared.h" |
| #include "mojo/public/cpp/bindings/associated_remote.h" |
| |
| namespace ash::language_packs { |
| |
| using ::ash::language::mojom::BasePackInfo; |
| using ::ash::language::mojom::ErrorCode; |
| using ::ash::language::mojom::FeatureId; |
| using ::ash::language::mojom::LanguagePackInfo; |
| using ::ash::language::mojom::LanguagePacks; |
| using ::ash::language::mojom::PackState; |
| |
| namespace { |
| |
| std::optional<std::string> ConvertMojoFeatureToPackId(FeatureId mojo_id) { |
| switch (mojo_id) { |
| case FeatureId::HANDWRITING_RECOGNITION: |
| return kHandwritingFeatureId; |
| |
| case FeatureId::TTS: |
| return kTtsFeatureId; |
| |
| // Catch all unknown cases here. |
| default: |
| return std::nullopt; |
| } |
| } |
| |
| PackState GetPackStateFromStatusCode(const PackResult::StatusCode status_code) { |
| switch (status_code) { |
| case PackResult::StatusCode::kNotInstalled: |
| return PackState::NOT_INSTALLED; |
| case PackResult::StatusCode::kInProgress: |
| return PackState::INSTALLING; |
| case PackResult::StatusCode::kInstalled: |
| return PackState::INSTALLED; |
| // Catch all remaining cases as error. |
| default: |
| // TODO: b/294162606 - Deprecate this value and use UNKNOWN instead. |
| return PackState::ERROR; |
| } |
| } |
| |
| ErrorCode GetMojoErrorFromPackError(const PackResult::ErrorCode pack_error) { |
| // This conversion is exhaustive. We don't use a default: case so that we can |
| // catch missing values at compile time. |
| switch (pack_error) { |
| case PackResult::ErrorCode::kNone: |
| return ErrorCode::kNone; |
| case PackResult::ErrorCode::kOther: |
| return ErrorCode::kOther; |
| case PackResult::ErrorCode::kWrongId: |
| return ErrorCode::kWrongId; |
| case PackResult::ErrorCode::kNeedReboot: |
| return ErrorCode::kNeedReboot; |
| case PackResult::ErrorCode::kAllocation: |
| return ErrorCode::kAllocation; |
| } |
| } |
| |
| FeatureId ToFeatureId(std::string_view feature_id) { |
| if (feature_id == kHandwritingFeatureId) { |
| return FeatureId::HANDWRITING_RECOGNITION; |
| } else if (feature_id == kTtsFeatureId) { |
| return FeatureId::TTS; |
| } |
| |
| return FeatureId::UNSUPPORTED_UNKNOWN; |
| } |
| |
| // Called when GetPackState() or InstallPack() functions from Language Packs |
| // are complete. |
| void OnOperationComplete(LanguagePacksImpl::GetPackInfoCallback mojo_callback, |
| const PackResult& pack_result) { |
| auto info = LanguagePackInfo::New(); |
| info->pack_state = GetPackStateFromStatusCode(pack_result.pack_state); |
| info->error = GetMojoErrorFromPackError(pack_result.operation_error); |
| info->feature_id = ToFeatureId(pack_result.feature_id); |
| if (pack_result.pack_state == PackResult::StatusCode::kInstalled) { |
| info->path = pack_result.path; |
| } |
| |
| std::move(mojo_callback).Run(std::move(info)); |
| } |
| |
| // Called when InstallBasePack() from Language Packs is complete. |
| void OnInstallBasePackComplete( |
| LanguagePacksImpl::InstallBasePackCallback mojo_callback, |
| const PackResult& pack_result) { |
| auto info = BasePackInfo::New(); |
| info->pack_state = GetPackStateFromStatusCode(pack_result.pack_state); |
| info->error = GetMojoErrorFromPackError(pack_result.operation_error); |
| if (pack_result.pack_state == PackResult::StatusCode::kInstalled) { |
| info->path = pack_result.path; |
| } |
| |
| std::move(mojo_callback).Run(std::move(info)); |
| } |
| |
| void OnUninstallComplete(LanguagePacksImpl::UninstallPackCallback mojo_callback, |
| const PackResult& result) { |
| std::move(mojo_callback).Run(); |
| } |
| |
| } // namespace |
| |
| LanguagePacksImpl::LanguagePacksImpl() { |
| auto* manager = LanguagePackManager::GetInstance(); |
| if (manager) { |
| // Note: RemoveObserver is never called here because this class should |
| // never be destroyed (see LanguagePacksImpl::GetInstance). |
| manager->AddObserver(this); |
| } |
| } |
| LanguagePacksImpl::~LanguagePacksImpl() = default; |
| |
| LanguagePacksImpl& LanguagePacksImpl::GetInstance() { |
| static base::NoDestructor<LanguagePacksImpl> impl; |
| return *impl; |
| } |
| |
| void LanguagePacksImpl::BindReceiver( |
| mojo::PendingReceiver<language::mojom::LanguagePacks> receiver) { |
| receivers_.Add(this, std::move(receiver)); |
| } |
| |
| void LanguagePacksImpl::GetPackInfo(FeatureId feature_id, |
| const std::string& language, |
| GetPackInfoCallback mojo_callback) { |
| const std::optional<std::string> pack_id = |
| ConvertMojoFeatureToPackId(feature_id); |
| |
| if (pack_id.has_value()) { |
| LanguagePackManager::GetPackState( |
| pack_id.value(), language, |
| base::BindOnce(&OnOperationComplete, std::move(mojo_callback))); |
| } else { |
| auto info = LanguagePackInfo::New(); |
| info->pack_state = PackState::ERROR; |
| info->feature_id = feature_id; |
| std::move(mojo_callback).Run(std::move(info)); |
| } |
| } |
| |
| void LanguagePacksImpl::InstallPack(FeatureId feature_id, |
| const std::string& language, |
| InstallPackCallback mojo_callback) { |
| const std::optional<std::string> pack_id = |
| ConvertMojoFeatureToPackId(feature_id); |
| |
| if (pack_id.has_value()) { |
| LanguagePackManager::InstallPack( |
| pack_id.value(), language, |
| base::BindOnce(&OnOperationComplete, std::move(mojo_callback))); |
| } else { |
| auto info = LanguagePackInfo::New(); |
| info->pack_state = PackState::ERROR; |
| info->feature_id = feature_id; |
| std::move(mojo_callback).Run(std::move(info)); |
| } |
| } |
| |
| void LanguagePacksImpl::InstallBasePack(FeatureId feature_id, |
| InstallBasePackCallback mojo_callback) { |
| const std::optional<std::string> pack_id = |
| ConvertMojoFeatureToPackId(feature_id); |
| |
| if (pack_id.has_value()) { |
| LanguagePackManager::InstallBasePack( |
| *pack_id, |
| base::BindOnce(&OnInstallBasePackComplete, std::move(mojo_callback))); |
| } else { |
| auto info = BasePackInfo::New(); |
| info->pack_state = PackState::ERROR; |
| std::move(mojo_callback).Run(std::move(info)); |
| } |
| } |
| |
| void LanguagePacksImpl::UninstallPack(FeatureId feature_id, |
| const std::string& language, |
| UninstallPackCallback mojo_callback) { |
| const std::optional<std::string> pack_id = |
| ConvertMojoFeatureToPackId(feature_id); |
| |
| // We ignore the request if the input parameters are incorrect. |
| if (pack_id.has_value()) { |
| LanguagePackManager::RemovePack( |
| pack_id.value(), language, |
| base::BindOnce(&OnUninstallComplete, std::move(mojo_callback))); |
| } |
| } |
| |
| void LanguagePacksImpl::AddObserver( |
| mojo::PendingAssociatedRemote<ash::language::mojom::LanguagePacksObserver> |
| observer) { |
| observers_.Add(std::move(observer)); |
| } |
| |
| void LanguagePacksImpl::OnPackStateChanged(const PackResult& pack_result) { |
| auto info = LanguagePackInfo::New(); |
| info->pack_state = GetPackStateFromStatusCode(pack_result.pack_state); |
| info->error = GetMojoErrorFromPackError(pack_result.operation_error); |
| if (pack_result.pack_state == PackResult::StatusCode::kInstalled) { |
| info->path = pack_result.path; |
| } |
| info->feature_id = ToFeatureId(pack_result.feature_id); |
| info->locale = pack_result.language_code; |
| |
| for (const auto& observer : observers_) { |
| observer->OnPackStateChanged(info.Clone()); |
| } |
| } |
| |
| } // namespace ash::language_packs |