blob: 5982e11d425ff8872b88958ee4fdd889a4a1c8f9 [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 <utility>
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "ui/base/resource/resource_bundle.h"
namespace {
const char kShortcutNameKey[] = "shortcut_name";
const char kActiveTimeKey[] = "active_time";
const char kAuthCredentialsKey[] = "local_auth_credentials";
const char kPasswordTokenKey[] = "gaia_password_token";
const char kIsAuthErrorKey[] = "is_auth_error";
} // namespace
const char ProfileAttributesEntry::kAvatarIconKey[] = "avatar_icon";
const char ProfileAttributesEntry::kBackgroundAppsKey[] = "background_apps";
const char ProfileAttributesEntry::kProfileIsEphemeral[] = "is_ephemeral";
const char ProfileAttributesEntry::kUserNameKey[] = "user_name";
ProfileAttributesEntry::ProfileAttributesEntry()
: profile_info_cache_(nullptr),
prefs_(nullptr),
profile_path_(base::FilePath()) {}
void ProfileAttributesEntry::Initialize(ProfileInfoCache* cache,
const base::FilePath& path,
PrefService* prefs) {
DCHECK(!profile_info_cache_);
DCHECK(cache);
profile_info_cache_ = cache;
DCHECK(profile_path_.empty());
DCHECK(!path.empty());
profile_path_ = path;
DCHECK(!prefs_);
DCHECK(prefs);
prefs_ = prefs;
DCHECK(profile_info_cache_->GetUserDataDir() == profile_path_.DirName());
storage_key_ = profile_path_.BaseName().MaybeAsASCII();
is_force_signin_enabled_ = signin_util::IsForceSigninEnabled();
if (is_force_signin_enabled_) {
if (!IsAuthenticated())
is_force_signin_profile_locked_ = true;
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN)
} else if (IsSigninRequired()) {
// Profiles that require signin in the absence of an enterprise policy are
// left-overs from legacy supervised users. Just unlock them, so users can
// keep using them.
SetLocalAuthCredentials(std::string());
SetAuthInfo(std::string(), base::string16());
SetIsSigninRequired(false);
#endif
}
}
base::string16 ProfileAttributesEntry::GetName() const {
return profile_info_cache_->GetNameOfProfileAtIndex(profile_index());
}
base::string16 ProfileAttributesEntry::GetShortcutName() const {
return GetString16(kShortcutNameKey);
}
base::FilePath ProfileAttributesEntry::GetPath() const {
return profile_path_;
}
base::Time ProfileAttributesEntry::GetActiveTime() const {
if (IsDouble(kActiveTimeKey)) {
return base::Time::FromDoubleT(GetDouble(kActiveTimeKey));
} else {
return base::Time();
}
}
base::string16 ProfileAttributesEntry::GetUserName() const {
return GetString16(kUserNameKey);
}
const gfx::Image& ProfileAttributesEntry::GetAvatarIcon() const {
if (IsUsingGAIAPicture()) {
const gfx::Image* image = GetGAIAPicture();
if (image)
return *image;
}
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
// Use the high resolution version of the avatar if it exists. Mobile and
// ChromeOS don't need the high resolution version so no need to fetch it.
const gfx::Image* image = GetHighResAvatar();
if (image)
return *image;
#endif
int resource_id =
profiles::GetDefaultAvatarIconResourceIDAtIndex(GetAvatarIconIndex());
return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
resource_id);
}
std::string ProfileAttributesEntry::GetLocalAuthCredentials() const {
return GetString(kAuthCredentialsKey);
}
std::string ProfileAttributesEntry::GetPasswordChangeDetectionToken() const {
return GetString(kPasswordTokenKey);
}
bool ProfileAttributesEntry::GetBackgroundStatus() const {
return GetBool(kBackgroundAppsKey);
}
base::string16 ProfileAttributesEntry::GetGAIAName() const {
return profile_info_cache_->GetGAIANameOfProfileAtIndex(profile_index());
}
base::string16 ProfileAttributesEntry::GetGAIAGivenName() const {
return profile_info_cache_->GetGAIAGivenNameOfProfileAtIndex(profile_index());
}
std::string ProfileAttributesEntry::GetGAIAId() const {
return profile_info_cache_->GetGAIAIdOfProfileAtIndex(profile_index());
}
const gfx::Image* ProfileAttributesEntry::GetGAIAPicture() const {
return profile_info_cache_->GetGAIAPictureOfProfileAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsUsingGAIAPicture() const {
return profile_info_cache_->IsUsingGAIAPictureOfProfileAtIndex(
profile_index());
}
bool ProfileAttributesEntry::IsGAIAPictureLoaded() const {
return profile_info_cache_->IsGAIAPictureOfProfileAtIndexLoaded(
profile_index());
}
bool ProfileAttributesEntry::IsSupervised() const {
return profile_info_cache_->ProfileIsSupervisedAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsChild() const {
return profile_info_cache_->ProfileIsChildAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsLegacySupervised() const {
return profile_info_cache_->ProfileIsLegacySupervisedAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsOmitted() const {
return profile_info_cache_->IsOmittedProfileAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsSigninRequired() const {
return profile_info_cache_->ProfileIsSigninRequiredAtIndex(profile_index()) ||
is_force_signin_profile_locked_;
}
std::string ProfileAttributesEntry::GetSupervisedUserId() const {
return profile_info_cache_->GetSupervisedUserIdOfProfileAtIndex(
profile_index());
}
bool ProfileAttributesEntry::IsEphemeral() const {
return GetBool(kProfileIsEphemeral);
}
bool ProfileAttributesEntry::IsUsingDefaultName() const {
return profile_info_cache_->ProfileIsUsingDefaultNameAtIndex(profile_index());
}
bool ProfileAttributesEntry::IsAuthenticated() const {
// The profile 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 profile has not been loaded yet and the
// gaia_id property has not yet been written.
return !GetGAIAId().empty() || !GetUserName().empty();
}
bool ProfileAttributesEntry::IsUsingDefaultAvatar() const {
return profile_info_cache_->ProfileIsUsingDefaultAvatarAtIndex(
profile_index());
}
bool ProfileAttributesEntry::IsAuthError() const {
return GetBool(kIsAuthErrorKey);
}
size_t ProfileAttributesEntry::GetAvatarIconIndex() const {
std::string icon_url = GetString(kAvatarIconKey);
size_t icon_index = 0;
if (!profiles::IsDefaultAvatarIconUrl(icon_url, &icon_index))
DLOG(WARNING) << "Unknown avatar icon: " << icon_url;
return icon_index;
}
void ProfileAttributesEntry::SetName(const base::string16& name) {
profile_info_cache_->SetNameOfProfileAtIndex(profile_index(), name);
}
void ProfileAttributesEntry::SetShortcutName(const base::string16& name) {
SetString16(kShortcutNameKey, name);
}
void ProfileAttributesEntry::SetActiveTimeToNow() {
if (IsDouble(kActiveTimeKey) &&
base::Time::Now() - GetActiveTime() < base::TimeDelta::FromHours(1)) {
return;
}
SetDouble(kActiveTimeKey, base::Time::Now().ToDoubleT());
}
void ProfileAttributesEntry::SetIsOmitted(bool is_omitted) {
profile_info_cache_->SetIsOmittedProfileAtIndex(profile_index(), is_omitted);
}
void ProfileAttributesEntry::SetSupervisedUserId(const std::string& id) {
profile_info_cache_->SetSupervisedUserIdOfProfileAtIndex(profile_index(), id);
}
void ProfileAttributesEntry::SetLocalAuthCredentials(const std::string& auth) {
SetString(kAuthCredentialsKey, auth);
}
void ProfileAttributesEntry::SetPasswordChangeDetectionToken(
const std::string& token) {
SetString(kPasswordTokenKey, token);
}
void ProfileAttributesEntry::SetBackgroundStatus(bool running_background_apps) {
SetBool(kBackgroundAppsKey, running_background_apps);
}
void ProfileAttributesEntry::SetGAIAName(const base::string16& name) {
profile_info_cache_->SetGAIANameOfProfileAtIndex(profile_index(), name);
}
void ProfileAttributesEntry::SetGAIAGivenName(const base::string16& name) {
profile_info_cache_->SetGAIAGivenNameOfProfileAtIndex(profile_index(), name);
}
void ProfileAttributesEntry::SetGAIAPicture(const gfx::Image* image) {
profile_info_cache_->SetGAIAPictureOfProfileAtIndex(profile_index(), image);
}
void ProfileAttributesEntry::SetIsUsingGAIAPicture(bool value) {
profile_info_cache_->SetIsUsingGAIAPictureOfProfileAtIndex(
profile_index(), value);
}
void ProfileAttributesEntry::SetIsSigninRequired(bool value) {
profile_info_cache_->SetProfileSigninRequiredAtIndex(profile_index(), value);
if (is_force_signin_enabled_)
LockForceSigninProfile(value);
}
void ProfileAttributesEntry::LockForceSigninProfile(bool is_lock) {
DCHECK(is_force_signin_enabled_);
if (is_force_signin_profile_locked_ == is_lock)
return;
is_force_signin_profile_locked_ = is_lock;
profile_info_cache_->NotifyIsSigninRequiredChanged(profile_path_);
}
void ProfileAttributesEntry::SetIsEphemeral(bool value) {
SetBool(kProfileIsEphemeral, value);
}
void ProfileAttributesEntry::SetIsUsingDefaultName(bool value) {
profile_info_cache_->SetProfileIsUsingDefaultNameAtIndex(
profile_index(), value);
}
void ProfileAttributesEntry::SetIsUsingDefaultAvatar(bool value) {
profile_info_cache_->SetProfileIsUsingDefaultAvatarAtIndex(
profile_index(), value);
}
void ProfileAttributesEntry::SetIsAuthError(bool value) {
SetBool(kIsAuthErrorKey, value);
}
void ProfileAttributesEntry::SetAvatarIconIndex(size_t icon_index) {
if (!profiles::IsDefaultAvatarIconIndex(icon_index)) {
DLOG(WARNING) << "Unknown avatar icon index: " << icon_index;
// switch to generic avatar
icon_index = 0;
}
std::string default_avatar_icon_url =
profiles::GetDefaultAvatarIconUrl(icon_index);
if (default_avatar_icon_url == GetString(kAvatarIconKey)) {
// On Windows, Taskbar and Desktop icons are refreshed every time
// |OnProfileAvatarChanged| notification is fired.
// As the current avatar icon is already set to |default_avatar_icon_url|,
// it is important to avoid firing |OnProfileAvatarChanged| in this case.
// See http://crbug.com/900374
return;
}
SetString(kAvatarIconKey, default_avatar_icon_url);
base::FilePath profile_path = GetPath();
if (!profile_info_cache_->GetDisableAvatarDownloadForTesting()) {
profile_info_cache_->DownloadHighResAvatarIfNeeded(icon_index,
profile_path);
}
profile_info_cache_->NotifyOnProfileAvatarChanged(profile_path);
}
void ProfileAttributesEntry::SetAuthInfo(
const std::string& gaia_id, const base::string16& user_name) {
profile_info_cache_->SetAuthInfoOfProfileAtIndex(
profile_index(), gaia_id, user_name);
}
size_t ProfileAttributesEntry::profile_index() const {
size_t index = profile_info_cache_->GetIndexOfProfileWithPath(profile_path_);
DCHECK(index < profile_info_cache_->GetNumberOfProfiles());
return index;
}
const gfx::Image* ProfileAttributesEntry::GetHighResAvatar() const {
const size_t avatar_index = GetAvatarIconIndex();
// If this is the placeholder avatar, it is already included in the
// resources, so it doesn't need to be downloaded.
if (avatar_index == profiles::GetPlaceholderAvatarIndex()) {
return &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
profiles::GetPlaceholderAvatarIconResourceID());
}
const std::string key =
profiles::GetDefaultAvatarIconFileNameAtIndex(avatar_index);
const base::FilePath image_path =
profiles::GetPathOfHighResAvatarAtIndex(avatar_index);
return profile_info_cache_->LoadAvatarPictureFromPath(GetPath(), key,
image_path);
}
const base::Value* ProfileAttributesEntry::GetEntryData() const {
const base::DictionaryValue* cache =
prefs_->GetDictionary(prefs::kProfileInfoCache);
return cache->FindKeyOfType(storage_key_, base::Value::Type::DICTIONARY);
}
void ProfileAttributesEntry::SetEntryData(base::Value data) {
DCHECK(data.is_dict());
DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
base::DictionaryValue* cache = update.Get();
cache->SetKey(storage_key_, std::move(data));
}
const base::Value* ProfileAttributesEntry::GetValue(const char* key) const {
const base::Value* entry_data = GetEntryData();
return entry_data ? entry_data->FindKey(key) : nullptr;
}
std::string ProfileAttributesEntry::GetString(const char* key) const {
const base::Value* value = GetValue(key);
if (!value || !value->is_string())
return std::string();
return value->GetString();
}
base::string16 ProfileAttributesEntry::GetString16(const char* key) const {
const base::Value* value = GetValue(key);
if (!value || !value->is_string())
return base::string16();
return base::UTF8ToUTF16(value->GetString());
}
double ProfileAttributesEntry::GetDouble(const char* key) const {
const base::Value* value = GetValue(key);
if (!value || !value->is_double())
return 0.0;
return value->GetDouble();
}
bool ProfileAttributesEntry::GetBool(const char* key) const {
const base::Value* value = GetValue(key);
return value && value->is_bool() && value->GetBool();
}
// Type checking. Only IsDouble is implemented because others do not have
// callsites.
bool ProfileAttributesEntry::IsDouble(const char* key) const {
const base::Value* value = GetValue(key);
return value && value->is_double();
}
// Internal setters using keys;
bool ProfileAttributesEntry::SetString(const char* key, std::string value) {
const base::Value* old_data = GetEntryData();
if (old_data) {
const base::Value* old_value = old_data->FindKey(key);
if (old_value && old_value->is_string() && old_value->GetString() == value)
return false;
}
base::Value new_data = old_data ? GetEntryData()->Clone()
: base::Value(base::Value::Type::DICTIONARY);
new_data.SetKey(key, base::Value(value));
SetEntryData(std::move(new_data));
return true;
}
bool ProfileAttributesEntry::SetString16(const char* key,
base::string16 value) {
const base::Value* old_data = GetEntryData();
if (old_data) {
const base::Value* old_value = old_data->FindKey(key);
if (old_value && old_value->is_string() &&
base::UTF8ToUTF16(old_value->GetString()) == value)
return false;
}
base::Value new_data = old_data ? GetEntryData()->Clone()
: base::Value(base::Value::Type::DICTIONARY);
new_data.SetKey(key, base::Value(value));
SetEntryData(std::move(new_data));
return true;
}
bool ProfileAttributesEntry::SetDouble(const char* key, double value) {
const base::Value* old_data = GetEntryData();
if (old_data) {
const base::Value* old_value = old_data->FindKey(key);
if (old_value && old_value->is_double() && old_value->GetDouble() == value)
return false;
}
base::Value new_data = old_data ? GetEntryData()->Clone()
: base::Value(base::Value::Type::DICTIONARY);
new_data.SetKey(key, base::Value(value));
SetEntryData(std::move(new_data));
return true;
}
bool ProfileAttributesEntry::SetBool(const char* key, bool value) {
const base::Value* old_data = GetEntryData();
if (old_data) {
const base::Value* old_value = old_data->FindKey(key);
if (old_value && old_value->is_bool() && old_value->GetBool() == value)
return false;
}
base::Value new_data = old_data ? GetEntryData()->Clone()
: base::Value(base::Value::Type::DICTIONARY);
new_data.SetKey(key, base::Value(value));
SetEntryData(std::move(new_data));
return true;
}