chromium/ash/system/video_conference/effects/video_conference_tray_effects_delegate.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/video_conference/effects/video_conference_tray_effects_delegate.h"

#include "ash/constants/ash_features.h"
#include "ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h"
#include "ash/system/video_conference/video_conference_tray_controller.h"
#include "ash/system/video_conference/video_conference_utils.h"
#include "base/metrics/histogram_functions.h"

namespace ash {

namespace {

// Returns whether all resources, which `effect` depends on, are
// presented/enabled.
bool DependenciesSatisfied(VcHostedEffect* effect) {
  DCHECK(effect);

  const VcHostedEffect::ResourceDependencyFlags dependency_flags =
      effect->dependency_flags();
  VideoConferenceTrayController* controller =
      VideoConferenceTrayController::Get();
  if (dependency_flags & VcHostedEffect::ResourceDependency::kCamera &&
      !controller->HasCameraPermission()) {
    // `effect` has a camera dependency, but the apps do not have permission.
    return false;
  }
  if (dependency_flags & VcHostedEffect::ResourceDependency::kMicrophone &&
      !controller->HasMicrophonePermission()) {
    // `effect` has a microphone dependency, but the apps do not have
    // permission.
    return false;
  }

  // All dependencies satisfied.
  return true;
}

}  // namespace

VcEffectsDelegate::VcEffectsDelegate() = default;

VcEffectsDelegate::~VcEffectsDelegate() = default;

void VcEffectsDelegate::AddEffect(std::unique_ptr<VcHostedEffect> effect) {
  const auto& id = effect->id();
  if (!effects_.contains(id)) {
    effects_[id] = std::move(effect);
  }
}

void VcEffectsDelegate::RemoveEffect(VcEffectId effect_id) {
  if (features::IsVcDlcUiEnabled()) {
    // Propagate effect removal to ensure dependant `VcUiTileController`'s are
    // reset, and DLC downloads are canceled if they are in progress.
    on_effect_will_be_removed_callback_.Run(this);
  }

  effects_.erase(effect_id);
}

int VcEffectsDelegate::GetNumEffects() {
  return effects_.size();
}

const VcHostedEffect* VcEffectsDelegate::GetEffectById(VcEffectId effect_id) {
  if (effects_.contains(effect_id)) {
    return effects_[effect_id].get();
  }
  return nullptr;
}

std::vector<VcHostedEffect*> VcEffectsDelegate::GetEffects(VcEffectType type) {
  std::vector<VcHostedEffect*> effects_of_type;

  for (const auto& [effect_id, effect] : effects_) {
    if (!DependenciesSatisfied(effect.get())) {
      // `effect` has at least one resource dependency that is not satisfied,
      // and is therefore not inserted in the output vector.
      continue;
    }

    if (effect->type() == type) {
      effects_of_type.push_back(effect.get());
    }
  }

  return effects_of_type;
}

void VcEffectsDelegate::RecordInitialStates() {
  for (auto& [effect_id, effect] : effects_) {
    // Only record supported effects, because if an effect does not apply to the
    // current session the current state is not relevant.
    if (!DependenciesSatisfied(effect.get())) {
      continue;
    }

    auto current_state = effect->get_state_callback().Run();
    if (!current_state.has_value()) {
      return;
    }

    if (effect->type() == VcEffectType::kToggle) {
      CHECK_EQ(effect->GetNumStates(), 1);
      base::UmaHistogramBoolean(
          video_conference_utils::GetEffectHistogramNameForInitialState(
              effect_id),
          current_state.value());
    } else {
      RecordMetricsForSetValueEffectOnStartup(effect_id, current_state.value());
    }
  }
}

}  // namespace ash