chromium/components/desks_storage/core/fake_desk_sync_bridge.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/desks_storage/core/fake_desk_sync_bridge.h"

#include "ash/public/cpp/desk_template.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/uuid.h"
#include "build/chromeos_buildflags.h"
#include "components/app_constants/constants.h"
#include "components/desks_storage/core/desk_model_observer.h"
#include "components/desks_storage/core/desk_template_util.h"
#include "ui/base/ui_base_types.h"

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/cpp/lacros_startup_state.h"  // nogncheck
#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

namespace desks_storage {

FakeDeskSyncBridge::FakeDeskSyncBridge() : cache_guid_("test_guid") {}

FakeDeskSyncBridge::~FakeDeskSyncBridge() = default;

DeskModel::GetAllEntriesResult FakeDeskSyncBridge::GetAllEntries() {
  if (!IsReady()) {
    return GetAllEntriesResult(
        GetAllEntriesStatus::kFailure,
        std::vector<raw_ptr<const ash::DeskTemplate, VectorExperimental>>());
  }

  std::vector<raw_ptr<const ash::DeskTemplate, VectorExperimental>> entries;

  for (const auto& it : policy_entries_) {
    entries.push_back(it.get());
  }

  for (const auto& it : desk_template_entries_) {
    DCHECK_EQ(it.first, it.second->uuid());
    entries.push_back(it.second.get());
  }

  return GetAllEntriesResult(GetAllEntriesStatus::kOk, std::move(entries));
}

DeskModel::GetEntryByUuidResult FakeDeskSyncBridge::GetEntryByUUID(
    const base::Uuid& uuid) {
  if (!IsReady()) {
    return GetEntryByUuidResult(GetEntryByUuidStatus::kFailure, nullptr);
  }

  if (!uuid.is_valid()) {
    return GetEntryByUuidResult(GetEntryByUuidStatus::kInvalidUuid, nullptr);
  }

  auto it = desk_template_entries_.find(uuid);
  if (it == desk_template_entries_.end()) {
    std::unique_ptr<ash::DeskTemplate> policy_entry =
        GetAdminDeskTemplateByUUID(uuid);

    if (policy_entry) {
      return GetEntryByUuidResult(GetEntryByUuidStatus::kOk,
                                  std::move(policy_entry));
    } else {
      return GetEntryByUuidResult(GetEntryByUuidStatus::kNotFound, nullptr);
    }
  } else {
    return GetEntryByUuidResult(GetEntryByUuidStatus::kOk,
                                it->second.get()->Clone());
  }
}

void FakeDeskSyncBridge::AddOrUpdateEntry(
    std::unique_ptr<ash::DeskTemplate> new_entry,
    AddOrUpdateEntryCallback callback) {
  if (!IsReady()) {
    // This sync bridge has not finished initializing. Do not save the new entry
    // yet.
    std::move(callback).Run(AddOrUpdateEntryStatus::kFailure,
                            std::move(new_entry));
    return;
  }

  if (!new_entry) {
    std::move(callback).Run(AddOrUpdateEntryStatus::kInvalidArgument,
                            std::move(new_entry));
    return;
  }

  base::Uuid uuid = new_entry->uuid();
  if (!uuid.is_valid()) {
    std::move(callback).Run(AddOrUpdateEntryStatus::kInvalidArgument,
                            std::move(new_entry));
    return;
  }
  std::vector<raw_ptr<const ash::DeskTemplate, VectorExperimental>>
      added_or_updated;
  // When a user creates a desk template locally, the desk template has `kUser`
  // as its source. Only user desk templates should be saved to Sync.
  DCHECK_EQ(ash::DeskTemplateSource::kUser, new_entry->source());
  auto entry = new_entry->Clone();

  entry->set_template_name(
      base::CollapseWhitespace(new_entry->template_name(), true));

  desk_template_entries_[uuid] = std::move(entry);
  added_or_updated.push_back(GetUserEntryByUUID(uuid));
  NotifyRemoteDeskTemplateAddedOrUpdated(added_or_updated);
  std::move(callback).Run(AddOrUpdateEntryStatus::kOk, std::move(new_entry));
}

void FakeDeskSyncBridge::DeleteEntry(const base::Uuid& uuid,
                                     DeleteEntryCallback callback) {
  if (!IsReady()) {
    // This sync bridge has not finished initializing.
    // Cannot delete anything.
    std::move(callback).Run(DeleteEntryStatus::kFailure);
    return;
  }

  if (GetUserEntryByUUID(uuid) == nullptr) {
    // Consider the deletion successful if the entry does not exist.
    std::move(callback).Run(DeleteEntryStatus::kOk);
    return;
  }

  desk_template_entries_.erase(uuid);
  std::move(callback).Run(DeleteEntryStatus::kOk);
}

void FakeDeskSyncBridge::DeleteAllEntries(DeleteEntryCallback callback) {
  desk_template_entries_.clear();
  std::move(callback).Run(DeleteEntryStatus::kOk);
}

size_t FakeDeskSyncBridge::GetEntryCount() const {
  return GetSaveAndRecallDeskEntryCount() + GetDeskTemplateEntryCount();
}

// Return 0 for now since chrome sync does not support save and recall desks.
size_t FakeDeskSyncBridge::GetSaveAndRecallDeskEntryCount() const {
  return 0u;
}

size_t FakeDeskSyncBridge::GetDeskTemplateEntryCount() const {
  size_t template_count = std::count_if(
      desk_template_entries_.begin(), desk_template_entries_.end(),
      [](const std::pair<base::Uuid, std::unique_ptr<ash::DeskTemplate>>&
             entry) {
        return entry.second->type() == ash::DeskTemplateType::kTemplate;
      });
  return template_count + policy_entries_.size();
}

// Chrome sync does not support save and recall desks yet. Return 0 for max
// count.
size_t FakeDeskSyncBridge::GetMaxSaveAndRecallDeskEntryCount() const {
  return 0u;
}

size_t FakeDeskSyncBridge::GetMaxDeskTemplateEntryCount() const {
  return 6u + policy_entries_.size();
}

std::set<base::Uuid> FakeDeskSyncBridge::GetAllEntryUuids() const {
  std::set<base::Uuid> keys;

  for (const auto& it : policy_entries_) {
    keys.emplace(it.get()->uuid());
  }

  for (const auto& it : desk_template_entries_) {
    DCHECK_EQ(it.first, it.second->uuid());
    keys.emplace(it.first);
  }
  return keys;
}

bool FakeDeskSyncBridge::IsReady() const {
  return true;
}

bool FakeDeskSyncBridge::IsSyncing() const {
  return false;
}

ash::DeskTemplate* FakeDeskSyncBridge::FindOtherEntryWithName(
    const std::u16string& name,
    ash::DeskTemplateType type,
    const base::Uuid& uuid) const {
  return desk_template_util::FindOtherEntryWithName(name, uuid,
                                                    desk_template_entries_);
}

const ash::DeskTemplate* FakeDeskSyncBridge::GetUserEntryByUUID(
    const base::Uuid& uuid) const {
  auto it = desk_template_entries_.find(uuid);
  if (it == desk_template_entries_.end()) {
    return nullptr;
  }
  return it->second.get();
}

void FakeDeskSyncBridge::NotifyRemoteDeskTemplateAddedOrUpdated(
    const std::vector<raw_ptr<const ash::DeskTemplate, VectorExperimental>>&
        new_entries) {
  if (new_entries.empty()) {
    return;
  }

  for (DeskModelObserver& observer : observers_) {
    observer.EntriesAddedOrUpdatedRemotely(new_entries);
  }
}

std::string FakeDeskSyncBridge::GetCacheGuid() {
  return cache_guid_;
}

}  // namespace desks_storage