chromium/ash/system/camera/autozoom_controller_impl.cc

// 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 "ash/system/camera/autozoom_controller_impl.h"

#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/system/anchored_nudge_manager.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"

namespace ash {

AutozoomControllerImpl::AutozoomControllerImpl()
    : nudge_controller_(std::make_unique<AutozoomNudgeController>(this)) {
  auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance();
  if (camera_hal_dispatcher) {
    camera_hal_dispatcher->GetAutoFramingSupported(
        base::BindOnce(&AutozoomControllerImpl::SetAutozoomSupported,
                       weak_ptr_factory_.GetWeakPtr()));
    camera_hal_dispatcher->AddActiveClientObserver(this);
  }

  Shell::Get()->session_controller()->AddObserver(this);
}

AutozoomControllerImpl::~AutozoomControllerImpl() {
  Shell::Get()->session_controller()->RemoveObserver(this);

  auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance();
  if (camera_hal_dispatcher) {
    camera_hal_dispatcher->RemoveActiveClientObserver(this);
  }
}

bool AutozoomControllerImpl::IsAutozoomControlEnabled() {
  if (autozoom_supported_for_test_) {
    return true;
  }
  // TODO(b/264472916): Add simon vs. non-simon logic here.
  return autozoom_supported_ && active_camera_client_count_ > 0;
}

cros::mojom::CameraAutoFramingState AutozoomControllerImpl::GetState() {
  return state_;
}

void AutozoomControllerImpl::SetState(
    cros::mojom::CameraAutoFramingState state) {
  if (active_user_pref_service_) {
    active_user_pref_service_->SetInteger(prefs::kAutozoomState,
                                          static_cast<int32_t>(state));
  }
}

void AutozoomControllerImpl::SetAutozoomSupported(bool autozoom_supported) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  bool orig_control_enabled = IsAutozoomControlEnabled();
  autozoom_supported_ = autozoom_supported;

  bool control_enabled = IsAutozoomControlEnabled();
  if (control_enabled != orig_control_enabled) {
    for (auto& observer : observers_)
      observer.OnAutozoomControlEnabledChanged(control_enabled);
  }
}

void AutozoomControllerImpl::Toggle() {
  SetState(state_ == cros::mojom::CameraAutoFramingState::OFF
               ? cros::mojom::CameraAutoFramingState::ON_SINGLE
               : cros::mojom::CameraAutoFramingState::OFF);
  AnchoredNudgeManager::Get()->MaybeRecordNudgeAction(
      NudgeCatalogName::kAutozoom);
}

void AutozoomControllerImpl::AddObserver(AutozoomObserver* observer) {
  observers_.AddObserver(observer);
}

void AutozoomControllerImpl::RemoveObserver(AutozoomObserver* observer) {
  observers_.RemoveObserver(observer);
}

void AutozoomControllerImpl::OnActiveUserPrefServiceChanged(
    PrefService* pref_service) {
  if (pref_service == active_user_pref_service_)
    return;

  // Initial login and user switching in multi profiles.
  active_user_pref_service_ = pref_service;
  InitFromUserPrefs();
}

void AutozoomControllerImpl::OnStatePrefChanged() {
  Refresh();
}

void AutozoomControllerImpl::Refresh() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (active_user_pref_service_) {
    state_ = static_cast<cros::mojom::CameraAutoFramingState>(
        active_user_pref_service_->GetInteger(prefs::kAutozoomState));
  } else {
    state_ = cros::mojom::CameraAutoFramingState::OFF;
  }

  auto* camera_hal_dispatcher = media::CameraHalDispatcherImpl::GetInstance();
  if (camera_hal_dispatcher) {
    camera_hal_dispatcher->SetAutoFramingState(state_);
  }

  for (auto& observer : observers_)
    observer.OnAutozoomStateChanged(state_);
}

void AutozoomControllerImpl::StartWatchingPrefsChanges() {
  DCHECK(active_user_pref_service_);

  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
  pref_change_registrar_->Init(active_user_pref_service_);
  pref_change_registrar_->Add(
      prefs::kAutozoomState,
      base::BindRepeating(&AutozoomControllerImpl::OnStatePrefChanged,
                          base::Unretained(this)));
}

void AutozoomControllerImpl::InitFromUserPrefs() {
  StartWatchingPrefsChanges();
  Refresh();
}

void AutozoomControllerImpl::OnActiveClientChange(
    cros::mojom::CameraClientType type,
    bool is_new_active_client,
    const base::flat_set<std::string>& active_device_ids) {
  bool orig_control_enabled = IsAutozoomControlEnabled();
  if (is_new_active_client) {
    active_camera_client_count_++;
  } else if (active_device_ids.empty()) {
    DCHECK(active_camera_client_count_ > 0);
    active_camera_client_count_--;
  }

  bool control_enabled = IsAutozoomControlEnabled();
  if (control_enabled != orig_control_enabled) {
    for (auto& observer : observers_)
      observer.OnAutozoomControlEnabledChanged(control_enabled);
  }
}

// static
void AutozoomControllerImpl::RegisterProfilePrefs(
    PrefRegistrySimple* registry) {
  registry->RegisterIntegerPref(
      prefs::kAutozoomState,
      static_cast<int32_t>(cros::mojom::CameraAutoFramingState::OFF));
}

}  // namespace ash