blob: 7972b0614eb5e85eb44a66083d761a6676bb98b5 [file] [log] [blame]
// Copyright 2015 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 "ios/chrome/browser/browser_state/browser_state_info_cache.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <utility>
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "ios/chrome/browser/browser_state/browser_state_info_cache_observer.h"
#include "ios/chrome/browser/pref_names.h"
namespace {
const char kGAIAIdKey[] = "gaia_id";
const char kIsAuthErrorKey[] = "is_auth_error";
const char kUserNameKey[] = "user_name";
}
BrowserStateInfoCache::BrowserStateInfoCache(
PrefService* prefs,
const base::FilePath& user_data_dir)
: prefs_(prefs), user_data_dir_(user_data_dir) {
// Populate the cache
DictionaryPrefUpdate update(prefs_, prefs::kBrowserStateInfoCache);
base::DictionaryValue* cache = update.Get();
for (base::DictionaryValue::Iterator it(*cache); !it.IsAtEnd();
it.Advance()) {
base::DictionaryValue* info = nullptr;
cache->GetDictionaryWithoutPathExpansion(it.key(), &info);
AddBrowserStateCacheKey(it.key());
}
}
BrowserStateInfoCache::~BrowserStateInfoCache() {}
void BrowserStateInfoCache::AddBrowserState(
const base::FilePath& browser_state_path,
const std::string& gaia_id,
const base::string16& user_name) {
std::string key = CacheKeyFromBrowserStatePath(browser_state_path);
DictionaryPrefUpdate update(prefs_, prefs::kBrowserStateInfoCache);
base::DictionaryValue* cache = update.Get();
std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue);
info->SetString(kGAIAIdKey, gaia_id);
info->SetString(kUserNameKey, user_name);
cache->SetWithoutPathExpansion(key, std::move(info));
AddBrowserStateCacheKey(key);
for (auto& observer : observer_list_)
observer.OnBrowserStateAdded(browser_state_path);
}
void BrowserStateInfoCache::AddObserver(
BrowserStateInfoCacheObserver* observer) {
observer_list_.AddObserver(observer);
}
void BrowserStateInfoCache::RemoveObserver(
BrowserStateInfoCacheObserver* observer) {
observer_list_.RemoveObserver(observer);
}
void BrowserStateInfoCache::RemoveBrowserState(
const base::FilePath& browser_state_path) {
size_t browser_state_index =
GetIndexOfBrowserStateWithPath(browser_state_path);
if (browser_state_index == std::string::npos) {
NOTREACHED();
return;
}
DictionaryPrefUpdate update(prefs_, prefs::kBrowserStateInfoCache);
base::DictionaryValue* cache = update.Get();
std::string key = CacheKeyFromBrowserStatePath(browser_state_path);
cache->Remove(key, nullptr);
sorted_keys_.erase(std::find(sorted_keys_.begin(), sorted_keys_.end(), key));
for (auto& observer : observer_list_)
observer.OnBrowserStateWasRemoved(browser_state_path);
}
size_t BrowserStateInfoCache::GetNumberOfBrowserStates() const {
return sorted_keys_.size();
}
size_t BrowserStateInfoCache::GetIndexOfBrowserStateWithPath(
const base::FilePath& browser_state_path) const {
if (browser_state_path.DirName() != user_data_dir_)
return std::string::npos;
std::string search_key = CacheKeyFromBrowserStatePath(browser_state_path);
for (size_t i = 0; i < sorted_keys_.size(); ++i) {
if (sorted_keys_[i] == search_key)
return i;
}
return std::string::npos;
}
base::string16 BrowserStateInfoCache::GetUserNameOfBrowserStateAtIndex(
size_t index) const {
base::string16 user_name;
GetInfoForBrowserStateAtIndex(index)->GetString(kUserNameKey, &user_name);
return user_name;
}
base::FilePath BrowserStateInfoCache::GetPathOfBrowserStateAtIndex(
size_t index) const {
return user_data_dir_.AppendASCII(sorted_keys_[index]);
}
std::string BrowserStateInfoCache::GetGAIAIdOfBrowserStateAtIndex(
size_t index) const {
std::string gaia_id;
GetInfoForBrowserStateAtIndex(index)->GetString(kGAIAIdKey, &gaia_id);
return gaia_id;
}
bool BrowserStateInfoCache::BrowserStateIsAuthenticatedAtIndex(
size_t index) const {
// The browser state is authenticated if the gaia_id of the info is not empty.
// If it is empty, also check if the user name is not empty. This latter
// check is needed in case the browser state has not been loaded yet and the
// gaia_id property has not yet been written.
return !GetGAIAIdOfBrowserStateAtIndex(index).empty() ||
!GetUserNameOfBrowserStateAtIndex(index).empty();
}
bool BrowserStateInfoCache::BrowserStateIsAuthErrorAtIndex(size_t index) const {
bool value = false;
GetInfoForBrowserStateAtIndex(index)->GetBoolean(kIsAuthErrorKey, &value);
return value;
}
void BrowserStateInfoCache::SetAuthInfoOfBrowserStateAtIndex(
size_t index,
const std::string& gaia_id,
const base::string16& user_name) {
// If both gaia_id and username are unchanged, abort early.
if (gaia_id == GetGAIAIdOfBrowserStateAtIndex(index) &&
user_name == GetUserNameOfBrowserStateAtIndex(index)) {
return;
}
auto info = base::MakeUnique<base::DictionaryValue>(
*GetInfoForBrowserStateAtIndex(index));
info->SetString(kGAIAIdKey, gaia_id);
info->SetString(kUserNameKey, user_name);
SetInfoForBrowserStateAtIndex(index, std::move(info));
}
void BrowserStateInfoCache::SetBrowserStateIsAuthErrorAtIndex(size_t index,
bool value) {
if (value == BrowserStateIsAuthErrorAtIndex(index))
return;
auto info = base::MakeUnique<base::DictionaryValue>(
*GetInfoForBrowserStateAtIndex(index));
info->SetBoolean(kIsAuthErrorKey, value);
SetInfoForBrowserStateAtIndex(index, std::move(info));
}
const base::FilePath& BrowserStateInfoCache::GetUserDataDir() const {
return user_data_dir_;
}
// static
void BrowserStateInfoCache::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(prefs::kBrowserStateInfoCache);
}
const base::DictionaryValue*
BrowserStateInfoCache::GetInfoForBrowserStateAtIndex(size_t index) const {
DCHECK_LT(index, GetNumberOfBrowserStates());
const base::DictionaryValue* cache =
prefs_->GetDictionary(prefs::kBrowserStateInfoCache);
const base::DictionaryValue* info = nullptr;
cache->GetDictionaryWithoutPathExpansion(sorted_keys_[index], &info);
return info;
}
void BrowserStateInfoCache::SetInfoForBrowserStateAtIndex(
size_t index,
std::unique_ptr<base::DictionaryValue> info) {
DictionaryPrefUpdate update(prefs_, prefs::kBrowserStateInfoCache);
base::DictionaryValue* cache = update.Get();
cache->SetWithoutPathExpansion(sorted_keys_[index], std::move(info));
}
std::string BrowserStateInfoCache::CacheKeyFromBrowserStatePath(
const base::FilePath& browser_state_path) const {
DCHECK(user_data_dir_ == browser_state_path.DirName());
base::FilePath base_name = browser_state_path.BaseName();
return base_name.MaybeAsASCII();
}
void BrowserStateInfoCache::AddBrowserStateCacheKey(const std::string& key) {
sorted_keys_.insert(
std::upper_bound(sorted_keys_.begin(), sorted_keys_.end(), key), key);
}