chromium/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc

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

#include "components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h"

#include <utility>
#include <vector>

#include "base/check.h"
#include "base/containers/contains.h"
#include "base/observer_list.h"
#include "components/services/app_service/public/cpp/shortcut/shortcut_update.h"

namespace apps {

ShortcutRegistryCache::ShortcutRegistryCache() = default;

ShortcutRegistryCache::~ShortcutRegistryCache() {
  for (auto& obs : observers_) {
    obs.OnShortcutRegistryCacheWillBeDestroyed(this);
  }
  CHECK(observers_.empty());
}

void ShortcutRegistryCache::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void ShortcutRegistryCache::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

void ShortcutRegistryCache::UpdateShortcut(ShortcutPtr delta) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  // Do not allow notified observer to modify shortcut cache again.
  DCHECK(!is_updating_);
  is_updating_ = true;
  const ShortcutId shortcut_id = delta->shortcut_id;

  Shortcut* state =
      HasShortcut(shortcut_id) ? states_[shortcut_id].get() : nullptr;

  ShortcutPtr state_before_update = state ? state->Clone() : nullptr;

  if (state) {
    ShortcutUpdate::Merge(state, delta.get());
  } else {
    // Call ShortcutUpdate::Merge to set the init value for the icon key's
    // `update_version`.
    auto shortcut =
        std::make_unique<Shortcut>(delta->host_app_id, delta->local_id);
    ShortcutUpdate::Merge(shortcut.get(), delta.get());
    states_.emplace(shortcut_id, std::move(shortcut));
  }

  for (auto& obs : observers_) {
    obs.OnShortcutUpdated(
        ShortcutUpdate(state_before_update.get(), delta.get()));
  }

  is_updating_ = false;
}

void ShortcutRegistryCache::RemoveShortcut(const ShortcutId& id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  // Do not allow notified observer to modify shortcut cache again.
  CHECK(!is_updating_);
  is_updating_ = true;
  states_.erase(id);
  for (auto& obs : observers_) {
    obs.OnShortcutRemoved(id);
  }
  is_updating_ = false;
}

ShortcutView ShortcutRegistryCache::GetShortcut(const ShortcutId& shortcut_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  auto shortcut = states_.find(shortcut_id);
  return ShortcutView((shortcut != states_.end()) ? shortcut->second.get()
                                                  : nullptr);
}

bool ShortcutRegistryCache::HasShortcut(const ShortcutId& shortcut_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return base::Contains(states_, shortcut_id);
}

std::vector<ShortcutView> ShortcutRegistryCache::GetAllShortcuts() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  std::vector<ShortcutView> shortcuts;
  for (const auto& [shortcut_id, shortcut] : states_) {
    shortcuts.emplace_back(shortcut.get());
  }
  return shortcuts;
}

// Returns the host app id for shortcut represented by 'id'.
std::string ShortcutRegistryCache::GetShortcutHostAppId(const ShortcutId& id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  ShortcutView shortcut = GetShortcut(id);
  if (!shortcut) {
    return "";
  }
  return shortcut->host_app_id;
}

// Returns the local id for shortcut represented by 'id'.
std::string ShortcutRegistryCache::GetShortcutLocalId(const ShortcutId& id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  ShortcutView shortcut = GetShortcut(id);
  if (!shortcut) {
    return "";
  }
  return shortcut->local_id;
}

}  // namespace apps