chromium/ash/public/cpp/assistant/assistant_state_base.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/public/cpp/assistant/assistant_state_base.h"

#include <ostream>
#include <sstream>

#include "ash/public/cpp/accelerators.h"
#include "base/functional/bind.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/to_string.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"

namespace ash {

using assistant::prefs::AssistantOnboardingMode;

AssistantStateBase::AssistantStateBase() = default;

AssistantStateBase::~AssistantStateBase() {
  for (auto& observer : observers_)
    observer.OnAssistantStateDestroyed();
}

std::string AssistantStateBase::ToString() const {
#define STRINGIFY(field) \
  #field, (field.has_value() ? base::ToString(field.value()) : "(no value)")
  return base::StrCat(
      {"AssistantStatus: ", base::ToString(assistant_status_),
       STRINGIFY(settings_enabled()), STRINGIFY(context_enabled()),
       STRINGIFY(hotword_enabled()), STRINGIFY(allowed_state()),
       STRINGIFY(locale()), STRINGIFY(arc_play_store_enabled()),
       STRINGIFY(locked_full_screen_enabled()), STRINGIFY(onboarding_mode())});
#undef STRINGIFY
}

void AssistantStateBase::AddObserver(AssistantStateObserver* observer) {
  observers_.AddObserver(observer);
  InitializeObserver(observer);
}

void AssistantStateBase::RemoveObserver(AssistantStateObserver* observer) {
  observers_.RemoveObserver(observer);
}

void AssistantStateBase::RegisterPrefChanges(PrefService* pref_service) {
  pref_change_registrar_.reset();

  if (!pref_service)
    return;

  // Register preference changes.
  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
  pref_change_registrar_->Init(pref_service);
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantConsentStatus,
      base::BindRepeating(&AssistantStateBase::UpdateConsentStatus,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantContextEnabled,
      base::BindRepeating(&AssistantStateBase::UpdateContextEnabled,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantEnabled,
      base::BindRepeating(&AssistantStateBase::UpdateSettingsEnabled,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantHotwordAlwaysOn,
      base::BindRepeating(&AssistantStateBase::UpdateHotwordAlwaysOn,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantHotwordEnabled,
      base::BindRepeating(&AssistantStateBase::UpdateHotwordEnabled,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantLaunchWithMicOpen,
      base::BindRepeating(&AssistantStateBase::UpdateLaunchWithMicOpen,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantNotificationEnabled,
      base::BindRepeating(&AssistantStateBase::UpdateNotificationEnabled,
                          base::Unretained(this)));
  pref_change_registrar_->Add(
      assistant::prefs::kAssistantOnboardingMode,
      base::BindRepeating(&AssistantStateBase::UpdateOnboardingMode,
                          base::Unretained(this)));

  UpdateConsentStatus();
  UpdateContextEnabled();
  UpdateSettingsEnabled();
  UpdateHotwordAlwaysOn();
  UpdateHotwordEnabled();
  UpdateLaunchWithMicOpen();
  UpdateNotificationEnabled();
  UpdateOnboardingMode();
}

bool AssistantStateBase::IsScreenContextAllowed() const {
  return allowed_state() == assistant::AssistantAllowedState::ALLOWED &&
         settings_enabled().value_or(false) &&
         context_enabled().value_or(false);
}

bool AssistantStateBase::HasAudioInputDevice() const {
  ash::AudioDeviceList devices;
  ash::CrasAudioHandler::Get()->GetAudioDevices(&devices);
  for (const AudioDevice& device : devices) {
    if (device.is_input)
      return true;
  }
  return false;
}

void AssistantStateBase::InitializeObserver(AssistantStateObserver* observer) {
  if (consent_status_.has_value())
    observer->OnAssistantConsentStatusChanged(consent_status_.value());
  if (context_enabled_.has_value())
    observer->OnAssistantContextEnabled(context_enabled_.value());
  if (settings_enabled_.has_value())
    observer->OnAssistantSettingsEnabled(settings_enabled_.value());
  if (hotword_always_on_.has_value())
    observer->OnAssistantHotwordAlwaysOn(hotword_always_on_.value());
  if (hotword_enabled_.has_value())
    observer->OnAssistantHotwordEnabled(hotword_enabled_.value());
  if (launch_with_mic_open_.has_value())
    observer->OnAssistantLaunchWithMicOpen(launch_with_mic_open_.value());
  if (notification_enabled_.has_value())
    observer->OnAssistantNotificationEnabled(notification_enabled_.value());
  if (onboarding_mode_.has_value())
    observer->OnAssistantOnboardingModeChanged(onboarding_mode_.value());

  observer->OnAssistantStatusChanged(assistant_status_);
  if (allowed_state_.has_value())
    observer->OnAssistantFeatureAllowedChanged(allowed_state_.value());
  if (locale_.has_value())
    observer->OnLocaleChanged(locale_.value());
  if (arc_play_store_enabled_.has_value())
    observer->OnArcPlayStoreEnabledChanged(arc_play_store_enabled_.value());
}

void AssistantStateBase::UpdateConsentStatus() {
  auto consent_status = pref_change_registrar_->prefs()->GetInteger(
      assistant::prefs::kAssistantConsentStatus);
  if (consent_status_.has_value() &&
      consent_status_.value() == consent_status) {
    return;
  }
  consent_status_ = consent_status;
  for (auto& observer : observers_)
    observer.OnAssistantConsentStatusChanged(consent_status_.value());
}

void AssistantStateBase::UpdateContextEnabled() {
  auto context_enabled = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantContextEnabled);
  if (context_enabled_.has_value() &&
      context_enabled_.value() == context_enabled) {
    return;
  }
  context_enabled_ = context_enabled;
  for (auto& observer : observers_)
    observer.OnAssistantContextEnabled(context_enabled_.value());
}

void AssistantStateBase::UpdateSettingsEnabled() {
  auto settings_enabled = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantEnabled);
  if (settings_enabled_.has_value() &&
      settings_enabled_.value() == settings_enabled) {
    return;
  }
  settings_enabled_ = settings_enabled;
  for (auto& observer : observers_)
    observer.OnAssistantSettingsEnabled(settings_enabled_.value());
}

void AssistantStateBase::UpdateHotwordAlwaysOn() {
  auto hotword_always_on = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantHotwordAlwaysOn);
  if (hotword_always_on_.has_value() &&
      hotword_always_on_.value() == hotword_always_on) {
    return;
  }
  hotword_always_on_ = hotword_always_on;
  for (auto& observer : observers_)
    observer.OnAssistantHotwordAlwaysOn(hotword_always_on_.value());
}

void AssistantStateBase::UpdateHotwordEnabled() {
  auto hotword_enabled = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantHotwordEnabled);
  if (hotword_enabled_.has_value() &&
      hotword_enabled_.value() == hotword_enabled) {
    return;
  }
  hotword_enabled_ = hotword_enabled;
  for (auto& observer : observers_)
    observer.OnAssistantHotwordEnabled(hotword_enabled_.value());
}

void AssistantStateBase::UpdateLaunchWithMicOpen() {
  auto launch_with_mic_open = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantLaunchWithMicOpen);
  if (launch_with_mic_open_.has_value() &&
      launch_with_mic_open_.value() == launch_with_mic_open) {
    return;
  }
  launch_with_mic_open_ = launch_with_mic_open;
  for (auto& observer : observers_)
    observer.OnAssistantLaunchWithMicOpen(launch_with_mic_open_.value());
}

void AssistantStateBase::UpdateNotificationEnabled() {
  auto notification_enabled = pref_change_registrar_->prefs()->GetBoolean(
      assistant::prefs::kAssistantNotificationEnabled);
  if (notification_enabled_.has_value() &&
      notification_enabled_.value() == notification_enabled) {
    return;
  }
  notification_enabled_ = notification_enabled;
  for (auto& observer : observers_)
    observer.OnAssistantNotificationEnabled(notification_enabled_.value());
}

void AssistantStateBase::UpdateOnboardingMode() {
  AssistantOnboardingMode onboarding_mode = assistant::prefs::ToOnboardingMode(
      pref_change_registrar_->prefs()->GetString(
          assistant::prefs::kAssistantOnboardingMode));

  if (onboarding_mode_ == onboarding_mode)
    return;

  onboarding_mode_ = onboarding_mode;
  for (auto& observer : observers_)
    observer.OnAssistantOnboardingModeChanged(onboarding_mode_.value());
}

void AssistantStateBase::UpdateAssistantStatus(
    assistant::AssistantStatus status) {
  assistant_status_ = status;
  for (auto& observer : observers_)
    observer.OnAssistantStatusChanged(assistant_status_);
}

void AssistantStateBase::UpdateFeatureAllowedState(
    assistant::AssistantAllowedState state) {
  allowed_state_ = state;
  for (auto& observer : observers_)
    observer.OnAssistantFeatureAllowedChanged(allowed_state_.value());
}

void AssistantStateBase::UpdateLocale(const std::string& locale) {
  locale_ = locale;
  for (auto& observer : observers_)
    observer.OnLocaleChanged(locale_.value());
}

void AssistantStateBase::UpdateArcPlayStoreEnabled(bool enabled) {
  arc_play_store_enabled_ = enabled;
  for (auto& observer : observers_)
    observer.OnArcPlayStoreEnabledChanged(arc_play_store_enabled_.value());
}

void AssistantStateBase::UpdateLockedFullScreenState(bool enabled) {
  locked_full_screen_enabled_ = enabled;
  for (auto& observer : observers_) {
    observer.OnLockedFullScreenStateChanged(
        locked_full_screen_enabled_.value());
  }
}

}  // namespace ash