blob: d40171c7d4629dd88ec352bad9327c01c1ab7fc0 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/services/app_service/public/cpp/app_registry_cache.h"
#include <utility>
namespace apps {
AppRegistryCache::Observer::Observer(AppRegistryCache* cache) {
Observe(cache);
}
AppRegistryCache::Observer::Observer() = default;
AppRegistryCache::Observer::~Observer() {
if (cache_) {
cache_->RemoveObserver(this);
}
}
void AppRegistryCache::Observer::Observe(AppRegistryCache* cache) {
if (cache == cache_) {
// Early exit to avoid infinite loops if we're in the middle of a callback.
return;
}
if (cache_) {
cache_->RemoveObserver(this);
}
cache_ = cache;
if (cache_) {
cache_->AddObserver(this);
}
}
AppRegistryCache::AppRegistryCache() = default;
AppRegistryCache::~AppRegistryCache() = default;
void AppRegistryCache::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void AppRegistryCache::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void AppRegistryCache::OnApps(std::vector<apps::mojom::AppPtr> deltas) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
if (!deltas_in_progress_.empty()) {
std::move(deltas.begin(), deltas.end(),
std::back_inserter(deltas_pending_));
return;
}
DoOnApps(std::move(deltas));
while (!deltas_pending_.empty()) {
std::vector<apps::mojom::AppPtr> pending;
pending.swap(deltas_pending_);
DoOnApps(std::move(pending));
}
}
void AppRegistryCache::DoOnApps(std::vector<apps::mojom::AppPtr> deltas) {
// Merge any deltas elements that have the same app_id. If an observer's
// OnAppUpdate calls back into this AppRegistryCache then we can therefore
// present a single delta for any given app_id.
for (auto& delta : deltas) {
auto d_iter = deltas_in_progress_.find(delta->app_id);
if (d_iter != deltas_in_progress_.end()) {
AppUpdate::Merge(d_iter->second, delta.get());
} else {
deltas_in_progress_[delta->app_id] = delta.get();
}
}
// The remaining for loops range over the deltas_in_progress_ map, not the
// deltas vector, so that OnAppUpdate is called only once per unique app_id.
// Notify the observers for every de-duplicated delta.
for (const auto& d_iter : deltas_in_progress_) {
auto s_iter = states_.find(d_iter.first);
apps::mojom::App* state =
(s_iter != states_.end()) ? s_iter->second.get() : nullptr;
apps::mojom::App* delta = d_iter.second;
for (auto& obs : observers_) {
obs.OnAppUpdate(AppUpdate(state, delta));
}
}
// Update the states for every de-duplicated delta.
for (const auto& d_iter : deltas_in_progress_) {
auto s_iter = states_.find(d_iter.first);
apps::mojom::App* state =
(s_iter != states_.end()) ? s_iter->second.get() : nullptr;
apps::mojom::App* delta = d_iter.second;
if (state) {
AppUpdate::Merge(state, delta);
} else {
states_.insert(std::make_pair(delta->app_id, delta->Clone()));
}
}
deltas_in_progress_.clear();
}
apps::mojom::AppType AppRegistryCache::GetAppType(const std::string& app_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
auto d_iter = deltas_in_progress_.find(app_id);
if (d_iter != deltas_in_progress_.end()) {
return d_iter->second->app_type;
}
auto s_iter = states_.find(app_id);
if (s_iter != states_.end()) {
return s_iter->second->app_type;
}
return apps::mojom::AppType::kUnknown;
}
} // namespace apps