blob: d58c2a6dad9867e1daf16a98f4180ad3333dd336 [file] [log] [blame]
// 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/lobster/lobster_service.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/lobster/lobster_enums.h"
#include "ash/public/cpp/lobster/lobster_session.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/task/single_thread_task_runner.h"
#include "base/types/cxx23_to_underlying.h"
#include "chrome/browser/ash/lobster/lobster_candidate_id_generator.h"
#include "chrome/browser/ash/lobster/lobster_image_fetcher.h"
#include "chrome/browser/ash/lobster/lobster_image_provider_from_memory.h"
#include "chrome/browser/ash/lobster/lobster_image_provider_from_snapper.h"
#include "chrome/browser/ash/lobster/lobster_system_state_provider.h"
#include "chrome/browser/ash/lobster/lobster_system_state_provider_impl.h"
#include "chrome/browser/ash/magic_boost/magic_boost_controller_ash.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chromeos/ash/components/browser_context_helper/annotated_account_id.h"
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
#include "chromeos/ash/components/editor_menu/public/cpp/editor_consent_status.h"
#include "chromeos/components/magic_boost/public/cpp/magic_boost_state.h"
#include "chromeos/crosapi/mojom/magic_boost.mojom.h"
#include "components/manta/snapper_provider.h"
#include "ui/display/screen.h"
namespace {
constexpr std::u16string_view kAnnouncementViewName = u"Lobster";
constexpr base::TimeDelta kAnnouncementDelay = base::Milliseconds(200);
} // namespace
LobsterService::LobsterService(
std::unique_ptr<manta::SnapperProvider> snapper_provider,
Profile* profile)
: profile_(profile),
// `LobsterService` is only created for regular profiles as specified in
// the `LobsterServiceProvider` constructor, so the below call should
// always return a non-null pointer.
account_id_(CHECK_DEREF(ash::AnnotatedAccountId::Get(profile))),
image_provider_(std::move(snapper_provider)),
image_fetcher_(std::make_unique<LobsterImageFetcher>(
std::make_unique<LobsterImageProviderFromSnapper>(
image_provider_.get(),
&candidate_id_generator_))),
resizer_(std::make_unique<LobsterCandidateResizer>(image_fetcher_.get())),
system_state_provider_(std::make_unique<LobsterSystemStateProviderImpl>(
profile->GetPrefs(),
IdentityManagerFactory::GetForProfile(profile),
/*is_in_demo_mode=*/ash::demo_mode::IsDeviceInDemoMode())),
announcer_(
std::make_unique<LobsterLiveRegionAnnouncer>(kAnnouncementViewName)) {
if (profile != nullptr) {
PrefService* pref_service = profile->GetPrefs();
pref_change_registrar_.Init(pref_service);
pref_change_registrar_.Add(
ash::prefs::kLobsterEnabled,
base::BindRepeating(
[](PrefService* pref_service) {
if (pref_service->GetBoolean(ash::prefs::kLobsterEnabled) &&
chromeos::editor_menu::GetConsentStatusFromInteger(
pref_service->GetInteger(
ash::prefs::kOrcaConsentStatus)) ==
chromeos::editor_menu::EditorConsentStatus::kDeclined) {
pref_service->SetInteger(
ash::prefs::kOrcaConsentStatus,
base::to_underlying(
chromeos::editor_menu::EditorConsentStatus::kUnset));
}
},
pref_service));
}
}
LobsterService::~LobsterService() = default;
void LobsterService::SetActiveSession(ash::LobsterSession* session) {
active_session_ = session;
}
ash::LobsterSession* LobsterService::active_session() {
return active_session_;
}
LobsterSystemStateProvider* LobsterService::system_state_provider() {
return system_state_provider_.get();
}
void LobsterService::RequestCandidates(
const std::string& query,
int num_candidates,
ash::RequestCandidatesCallback callback) {
image_fetcher_->RequestCandidates(query, num_candidates, std::move(callback));
}
void LobsterService::InflateCandidate(uint32_t seed,
const std::string& query,
ash::InflateCandidateCallback callback) {
resizer_->InflateImage(seed, query, std::move(callback));
}
void LobsterService::QueueInsertion(const std::string& image_bytes,
StatusCallback insert_status_callback) {
queued_insertion_ = std::make_unique<LobsterInsertion>(
image_bytes, std::move(insert_status_callback));
}
void LobsterService::ShowDisclaimerUI() {
if (chromeos::MagicBoostState::Get()->IsUserEligibleForGenAIFeatures()) {
ash::MagicBoostControllerAsh::Get()->ShowDisclaimerUi(
/*display_id=*/display::Screen::Get()->GetPrimaryDisplay().id(),
/*action=*/
crosapi::mojom::MagicBoostController::TransitionAction::
kShowLobsterPanel,
/*opt_in_features=*/
crosapi::mojom::MagicBoostController::OptInFeatures::kOrcaAndHmr);
}
}
void LobsterService::LoadUI(std::optional<std::string> query,
ash::LobsterMode mode,
const gfx::Rect& caret_bounds) {
bubble_coordinator_.LoadUI(
profile_, query, mode, caret_bounds,
/*should_show_feedback=*/
profile_->GetPrefs()->GetInteger(
ash::prefs::kLobsterEnterprisePolicySettings) ==
base::to_underlying(ash::LobsterEnterprisePolicyValue::
kAllowedWithModelImprovement) &&
base::FeatureList::IsEnabled(ash::features::kLobsterFeedback));
}
void LobsterService::ShowUI() {
bubble_coordinator_.ShowUI();
}
void LobsterService::CloseUI() {
bubble_coordinator_.CloseUI();
}
void LobsterService::OnFocus(int context_id) {
if (queued_insertion_ == nullptr) {
return;
}
if (queued_insertion_->HasTimedOut()) {
queued_insertion_ = nullptr;
return;
}
queued_insertion_->Commit();
queued_insertion_ = nullptr;
}
void LobsterService::AnnounceLater(const std::u16string& message) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[](LobsterAnnouncer* announcer, const std::u16string& message) {
announcer->Announce(message);
},
announcer_.get(), message),
kAnnouncementDelay);
}
bool LobsterService::CanShowFeatureSettingsToggle() {
// An empty text input context should not affect the visibility of the feature
// settings toggle.
ash::LobsterSystemState::SystemChecks system_checks =
system_state_provider()
->GetSystemState(ash::LobsterTextInputContext())
.failed_checks;
return (!system_checks.Has(
ash::LobsterSystemCheck::kInvalidAccountCapabilities) &&
!system_checks.Has(ash::LobsterSystemCheck::kInvalidRegion) &&
!system_checks.Has(ash::LobsterSystemCheck::kInvalidAccountType) &&
!system_checks.Has(ash::LobsterSystemCheck::kInvalidFeatureFlags) &&
!system_checks.Has(ash::LobsterSystemCheck::kUnsupportedHardware) &&
!system_checks.Has(ash::LobsterSystemCheck::kUnsupportedInKioskMode));
}
bool LobsterService::OverrideLobsterImageProviderForTesting() {
image_fetcher_->SetProvider(std::make_unique<LobsterImageProviderFromMemory>(
&candidate_id_generator_));
return true;
}
void LobsterService::set_lobster_system_state_provider_for_testing(
std::unique_ptr<LobsterSystemStateProvider> provider) {
system_state_provider_ = std::move(provider);
}