blob: 8d1db48577c388866205ae510f4c0d08489366b4 [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/hash/hash.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.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/browser/ui/ui_features.h"
#include "chrome/common/pref_names.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/profile_metrics/state.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/native_theme/native_theme.h"
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#endif
#if !defined(OS_ANDROID)
#include "chrome/browser/themes/theme_properties.h"
#endif
namespace {
const char kGAIAGivenNameKey[] = "gaia_given_name";
const char kGAIANameKey[] = "gaia_name";
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";
const char kMetricsBucketIndex[] = "metrics_bucket_index";
const char kSigninRequiredKey[] = "signin_required";
const char kHostedDomain[] = "hosted_domain";
// Profile colors info.
const char kProfileHighlightColorKey[] = "profile_highlight_color";
const char kDefaultAvatarFillColorKey[] = "default_avatar_fill_color";
const char kDefaultAvatarStrokeColorKey[] = "default_avatar_stroke_color";
// Low-entropy accounts info, for metrics only.
const char kFirstAccountNameHash[] = "first_account_name_hash";
const char kHasMultipleAccountNames[] = "has_multiple_account_names";
const char kAccountCategories[] = "account_categories";
// Local state pref to keep track of the next available profile bucket.
const char kNextMetricsBucketIndex[] = "profile.metrics.next_bucket_index";
constexpr int kIntegerNotSet = -1;
// Persisted in prefs.
constexpr int kAccountCategoriesConsumerOnly = 0;
constexpr int kAccountCategoriesEnterpriseOnly = 1;
constexpr int kAccountCategoriesBoth = 2;
// Number of distinct low-entropy hash values. Changing this value invalidates
// existing persisted hashes.
constexpr int kNumberOfLowEntropyHashValues = 1024;
// Returns the next available metrics bucket index and increases the index
// counter. I.e. two consecutive calls will return two consecutive numbers.
int NextAvailableMetricsBucketIndex() {
PrefService* local_prefs = g_browser_process->local_state();
int next_index = local_prefs->GetInteger(kNextMetricsBucketIndex);
DCHECK_GT(next_index, 0);
local_prefs->SetInteger(kNextMetricsBucketIndex, next_index + 1);
return next_index;
}
int GetLowEntropyHashValue(const std::string& value) {
return base::PersistentHash(value) % kNumberOfLowEntropyHashValues;
}
} // namespace
bool ProfileThemeColors::operator==(const ProfileThemeColors& other) const {
return std::tie(this->profile_highlight_color,
this->default_avatar_fill_color,
this->default_avatar_stroke_color) ==
std::tie(other.profile_highlight_color,
other.default_avatar_fill_color,
other.default_avatar_stroke_color);
}
bool ProfileThemeColors::operator!=(const ProfileThemeColors& other) const {
return !(*this == other);
}
const char ProfileAttributesEntry::kSupervisedUserId[] = "managed_user_id";
const char ProfileAttributesEntry::kIsOmittedFromProfileListKey[] =
"is_omitted_from_profile_list";
const char ProfileAttributesEntry::kAvatarIconKey[] = "avatar_icon";
const char ProfileAttributesEntry::kBackgroundAppsKey[] = "background_apps";
const char ProfileAttributesEntry::kProfileIsEphemeral[] = "is_ephemeral";
const char ProfileAttributesEntry::kUserNameKey[] = "user_name";
const char ProfileAttributesEntry::kGAIAIdKey[] = "gaia_id";
const char ProfileAttributesEntry::kIsConsentedPrimaryAccountKey[] =
"is_consented_primary_account";
const char ProfileAttributesEntry::kNameKey[] = "name";
const char ProfileAttributesEntry::kIsUsingDefaultNameKey[] =
"is_using_default_name";
// static
void ProfileAttributesEntry::RegisterLocalStatePrefs(
PrefRegistrySimple* registry) {
// Bucket 0 is reserved for the guest profile, so start new bucket indices
// at 1.
registry->RegisterIntegerPref(kNextMetricsBucketIndex, 1);
}
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();
const base::Value* entry_data = GetEntryData();
if (entry_data) {
if (!entry_data->FindKey(kIsConsentedPrimaryAccountKey)) {
SetBool(kIsConsentedPrimaryAccountKey,
!GetGAIAId().empty() || !GetUserName().empty());
}
}
is_force_signin_enabled_ = signin_util::IsForceSigninEnabled();
if (is_force_signin_enabled_) {
if (!IsAuthenticated())
is_force_signin_profile_locked_ = true;
#if defined(OS_MAC) || 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(), false);
SetIsSigninRequired(false);
#endif
}
DCHECK(last_name_to_display_.empty());
last_name_to_display_ = GetName();
}
base::string16 ProfileAttributesEntry::GetLocalProfileName() const {
return GetString16(kNameKey);
}
base::string16 ProfileAttributesEntry::GetGAIANameToDisplay() const {
base::string16 gaia_given_name = GetGAIAGivenName();
return gaia_given_name.empty() ? GetGAIAName() : gaia_given_name;
}
bool ProfileAttributesEntry::ShouldShowProfileLocalName(
const base::string16& gaia_name_to_display) const {
// Never show the profile name if it is equal to GAIA given name,
// e.g. Matt (Matt), in that case we should only show the GAIA name.
if (base::EqualsCaseInsensitiveASCII(gaia_name_to_display,
GetLocalProfileName())) {
return false;
}
// Customized profile name that is not equal to Gaia name, e.g. Matt (Work).
if (!IsUsingDefaultName())
return true;
// The profile local name is a default profile name : Person n.
std::vector<ProfileAttributesEntry*> entries =
profile_info_cache_->GetAllProfilesAttributes();
for (ProfileAttributesEntry* entry : entries) {
if (entry == this)
continue;
base::string16 other_gaia_name_to_display = entry->GetGAIANameToDisplay();
if (other_gaia_name_to_display.empty() ||
other_gaia_name_to_display != gaia_name_to_display)
continue;
// Another profile with the same GAIA name.
bool other_profile_name_equal_GAIA_name = base::EqualsCaseInsensitiveASCII(
other_gaia_name_to_display, entry->GetLocalProfileName());
// If for the other profile, the profile name is equal to GAIA name then it
// will not be shown. For disambiguation, show for the current profile the
// profile name even if it is Person n.
if (other_profile_name_equal_GAIA_name)
return true;
bool other_is_using_default_name = entry->IsUsingDefaultName();
// Both profiles have a default profile name,
// e.g. Matt (Person 1), Matt (Person 2).
if (other_is_using_default_name) {
return true;
}
}
return false;
}
base::string16 ProfileAttributesEntry::GetLastNameToDisplay() const {
return last_name_to_display_;
}
bool ProfileAttributesEntry::HasProfileNameChanged() {
base::string16 name = GetName();
if (last_name_to_display_ == name)
return false;
last_name_to_display_ = name;
return true;
}
NameForm ProfileAttributesEntry::GetNameForm() const {
base::string16 name_to_display = GetGAIANameToDisplay();
if (name_to_display.empty())
return NameForm::kLocalName;
if (!ShouldShowProfileLocalName(name_to_display))
return NameForm::kGaiaName;
return NameForm::kGaiaAndLocalName;
}
base::string16 ProfileAttributesEntry::GetName() const {
switch (GetNameForm()) {
case NameForm::kGaiaName:
return GetGAIANameToDisplay();
case NameForm::kLocalName:
return GetLocalProfileName();
case NameForm::kGaiaAndLocalName:
return GetGAIANameToDisplay() + base::UTF8ToUTF16(" (") +
GetLocalProfileName() + base::UTF8ToUTF16(")");
}
}
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_ANDROID)
// Use the high resolution version of the avatar if it exists. Mobile doesn'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 GetString16(kGAIANameKey);
}
base::string16 ProfileAttributesEntry::GetGAIAGivenName() const {
return GetString16(kGAIAGivenNameKey);
}
std::string ProfileAttributesEntry::GetGAIAId() const {
return GetString(ProfileAttributesEntry::kGAIAIdKey);
}
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 !GetSupervisedUserId().empty();
}
bool ProfileAttributesEntry::IsChild() const {
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
return GetSupervisedUserId() == supervised_users::kChildAccountSUID;
#else
return false;
#endif
}
bool ProfileAttributesEntry::IsLegacySupervised() const {
return IsSupervised() && !IsChild();
}
bool ProfileAttributesEntry::IsOmitted() const {
return GetBool(kIsOmittedFromProfileListKey);
}
bool ProfileAttributesEntry::IsSigninRequired() const {
return GetBool(kSigninRequiredKey) || is_force_signin_profile_locked_;
}
std::string ProfileAttributesEntry::GetSupervisedUserId() const {
return GetString(kSupervisedUserId);
}
bool ProfileAttributesEntry::IsEphemeral() const {
return GetBool(kProfileIsEphemeral);
}
bool ProfileAttributesEntry::IsUsingDefaultName() const {
return GetBool(kIsUsingDefaultNameKey);
}
SigninState ProfileAttributesEntry::GetSigninState() const {
bool is_consented_primary_account = GetBool(kIsConsentedPrimaryAccountKey);
if (!GetGAIAId().empty() || !GetUserName().empty()) {
return is_consented_primary_account
? SigninState::kSignedInWithConsentedPrimaryAccount
: SigninState::kSignedInWithUnconsentedPrimaryAccount;
}
DCHECK(!is_consented_primary_account);
return SigninState::kNotSignedIn;
}
bool ProfileAttributesEntry::IsAuthenticated() const {
return GetBool(kIsConsentedPrimaryAccountKey);
}
bool ProfileAttributesEntry::IsUsingDefaultAvatar() const {
return profile_info_cache_->ProfileIsUsingDefaultAvatarAtIndex(
profile_index());
}
bool ProfileAttributesEntry::IsAuthError() const {
return GetBool(kIsAuthErrorKey);
}
bool ProfileAttributesEntry::IsSignedInWithCredentialProvider() const {
return GetBool(prefs::kSignedInWithCredentialProvider);
}
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;
}
ProfileThemeColors ProfileAttributesEntry::GetProfileThemeColors() const {
base::Optional<SkColor> profile_highlight_color =
GetProfileThemeColor(kProfileHighlightColorKey);
base::Optional<SkColor> default_avatar_fill_color =
GetProfileThemeColor(kDefaultAvatarFillColorKey);
base::Optional<SkColor> default_avatar_stroke_color =
GetProfileThemeColor(kDefaultAvatarStrokeColorKey);
if (!profile_highlight_color.has_value()) {
DCHECK(!default_avatar_fill_color.has_value() &&
!default_avatar_stroke_color.has_value());
return GetDefaultProfileThemeColors(
ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors());
}
DCHECK(default_avatar_fill_color.has_value() &&
default_avatar_stroke_color.has_value());
ProfileThemeColors colors;
colors.profile_highlight_color = profile_highlight_color.value();
colors.default_avatar_fill_color = default_avatar_fill_color.value();
colors.default_avatar_stroke_color = default_avatar_stroke_color.value();
return colors;
}
size_t ProfileAttributesEntry::GetMetricsBucketIndex() {
int bucket_index = GetInteger(kMetricsBucketIndex);
if (bucket_index == kIntegerNotSet) {
bucket_index = NextAvailableMetricsBucketIndex();
SetInteger(kMetricsBucketIndex, bucket_index);
}
return bucket_index;
}
std::string ProfileAttributesEntry::GetHostedDomain() const {
return GetString(kHostedDomain);
}
void ProfileAttributesEntry::SetLocalProfileName(const base::string16& name) {
if (SetString16(kNameKey, name))
profile_info_cache_->NotifyIfProfileNamesHaveChanged();
}
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) {
if (SetBool(kIsOmittedFromProfileListKey, is_omitted))
profile_info_cache_->NotifyProfileIsOmittedChanged(GetPath());
}
void ProfileAttributesEntry::SetSupervisedUserId(const std::string& id) {
if (SetString(kSupervisedUserId, id))
profile_info_cache_->NotifyProfileSupervisedUserIdChanged(GetPath());
}
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) {
if (SetString16(kGAIANameKey, name))
profile_info_cache_->NotifyIfProfileNamesHaveChanged();
}
void ProfileAttributesEntry::SetGAIAGivenName(const base::string16& name) {
if (SetString16(kGAIAGivenNameKey, name))
profile_info_cache_->NotifyIfProfileNamesHaveChanged();
}
void ProfileAttributesEntry::SetGAIAPicture(
const std::string& image_url_with_size,
gfx::Image image) {
profile_info_cache_->SetGAIAPictureOfProfileAtIndex(
profile_index(), image_url_with_size, image);
}
void ProfileAttributesEntry::SetIsUsingGAIAPicture(bool value) {
profile_info_cache_->SetIsUsingGAIAPictureOfProfileAtIndex(
profile_index(), value);
}
void ProfileAttributesEntry::SetIsSigninRequired(bool value) {
if (value != GetBool(kSigninRequiredKey)) {
SetBool(kSigninRequiredKey, value);
profile_info_cache_->NotifyIsSigninRequiredChanged(GetPath());
}
if (is_force_signin_enabled_)
LockForceSigninProfile(value);
}
void ProfileAttributesEntry::SetSignedInWithCredentialProvider(bool value) {
if (value != GetBool(prefs::kSignedInWithCredentialProvider)) {
SetBool(prefs::kSignedInWithCredentialProvider, 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(GetPath());
}
void ProfileAttributesEntry::RecordAccountMetrics() const {
RecordAccountCategoriesMetric();
RecordAccountNamesMetric();
}
void ProfileAttributesEntry::SetIsEphemeral(bool value) {
SetBool(kProfileIsEphemeral, value);
}
void ProfileAttributesEntry::SetIsUsingDefaultName(bool value) {
if (SetBool(kIsUsingDefaultNameKey, value))
profile_info_cache_->NotifyIfProfileNamesHaveChanged();
}
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::SetProfileThemeColors(
const base::Optional<ProfileThemeColors>& colors) {
if (colors.has_value()) {
SetInteger(kProfileHighlightColorKey, colors->profile_highlight_color);
SetInteger(kDefaultAvatarFillColorKey, colors->default_avatar_fill_color);
SetInteger(kDefaultAvatarStrokeColorKey,
colors->default_avatar_stroke_color);
} else {
ClearValue(kProfileHighlightColorKey);
ClearValue(kDefaultAvatarFillColorKey);
ClearValue(kDefaultAvatarStrokeColorKey);
}
}
void ProfileAttributesEntry::SetHostedDomain(std::string hosted_domain) {
SetString(kHostedDomain, hosted_domain);
}
void ProfileAttributesEntry::SetAuthInfo(const std::string& gaia_id,
const base::string16& user_name,
bool is_consented_primary_account) {
// If gaia_id, username and consent state are unchanged, abort early.
if (GetBool(kIsConsentedPrimaryAccountKey) == is_consented_primary_account &&
gaia_id == GetGAIAId() && user_name == GetUserName()) {
return;
}
const base::Value* old_data = GetEntryData();
base::Value new_data = old_data ? GetEntryData()->Clone()
: base::Value(base::Value::Type::DICTIONARY);
new_data.SetStringKey(kGAIAIdKey, gaia_id);
new_data.SetStringKey(kUserNameKey, user_name);
DCHECK(!is_consented_primary_account || !gaia_id.empty() ||
!user_name.empty());
new_data.SetBoolKey(kIsConsentedPrimaryAccountKey,
is_consented_primary_account);
SetEntryData(std::move(new_data));
profile_info_cache_->NotifyProfileAuthInfoChanged(profile_path_);
}
void ProfileAttributesEntry::AddAccountName(const std::string& name) {
int hash = GetLowEntropyHashValue(name);
int first_hash = GetInteger(kFirstAccountNameHash);
if (first_hash == kIntegerNotSet) {
SetInteger(kFirstAccountNameHash, hash);
return;
}
if (first_hash != hash) {
SetBool(kHasMultipleAccountNames, true);
}
}
void ProfileAttributesEntry::AddAccountCategory(AccountCategory category) {
int current_categories = GetInteger(kAccountCategories);
if (current_categories == kAccountCategoriesBoth)
return;
int new_category = category == AccountCategory::kConsumer
? kAccountCategoriesConsumerOnly
: kAccountCategoriesEnterpriseOnly;
if (current_categories == kIntegerNotSet) {
SetInteger(kAccountCategories, new_category);
} else if (current_categories != new_category) {
SetInteger(kAccountCategories, kAccountCategoriesBoth);
}
}
void ProfileAttributesEntry::ClearAccountNames() {
ClearValue(kFirstAccountNameHash);
ClearValue(kHasMultipleAccountNames);
}
void ProfileAttributesEntry::ClearAccountCategories() {
ClearValue(kAccountCategories);
}
size_t ProfileAttributesEntry::profile_index() const {
size_t index = profile_info_cache_->GetIndexOfProfileWithPath(profile_path_);
DCHECK(index < profile_info_cache_->GetNumberOfProfiles());
return index;
}
// static
ProfileThemeColors ProfileAttributesEntry::GetDefaultProfileThemeColors(
bool dark_mode) {
#if defined(OS_ANDROID)
// Profile theme colors shouldn't be queried on Android.
NOTREACHED();
return {SK_ColorRED, SK_ColorRED, SK_ColorRED};
#else
ProfileThemeColors default_colors;
// TODO(https://crbug.com/1102384): update this with the right colors, once we
// have them.
default_colors.profile_highlight_color = ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_FRAME_ACTIVE, /*incognito=*/false, dark_mode);
default_colors.default_avatar_fill_color = ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_FRAME_ACTIVE, /*incognito=*/false, dark_mode);
default_colors.default_avatar_stroke_color = ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_TOOLBAR, /*incognito=*/false, dark_mode);
return default_colors;
#endif
}
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);
}
bool ProfileAttributesEntry::HasMultipleAccountNames() const {
// If the value is not set, GetBool() returns false.
return GetBool(kHasMultipleAccountNames);
}
bool ProfileAttributesEntry::HasBothAccountCategories() const {
// If the value is not set, GetInteger returns kIntegerNotSet which does not
// equal kAccountTypeBoth.
return GetInteger(kAccountCategories) == kAccountCategoriesBoth;
}
void ProfileAttributesEntry::RecordAccountCategoriesMetric() const {
if (HasBothAccountCategories()) {
if (IsAuthenticated()) {
bool consumer_syncing = GetHostedDomain() == kNoHostedDomainFound;
profile_metrics::LogProfileAllAccountsCategories(
consumer_syncing ? profile_metrics::AllAccountsCategories::
kBothConsumerAndEnterpriseSyncingConsumer
: profile_metrics::AllAccountsCategories::
kBothConsumerAndEnterpriseSyncingEnterprise);
} else {
profile_metrics::LogProfileAllAccountsCategories(
profile_metrics::AllAccountsCategories::
kBothConsumerAndEnterpriseNoSync);
}
} else {
profile_metrics::LogProfileAllAccountsCategories(
profile_metrics::AllAccountsCategories::kSingleCategory);
}
}
void ProfileAttributesEntry::RecordAccountNamesMetric() const {
if (HasMultipleAccountNames()) {
profile_metrics::LogProfileAllAccountsNames(
IsAuthenticated()
? profile_metrics::AllAccountsNames::kMultipleNamesWithSync
: profile_metrics::AllAccountsNames::kMultipleNamesWithoutSync);
} else {
profile_metrics::LogProfileAllAccountsNames(
profile_metrics::AllAccountsNames::kLikelySingleName);
}
}
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();
}
int ProfileAttributesEntry::GetInteger(const char* key) const {
const base::Value* value = GetValue(key);
if (!value || !value->is_int())
return kIntegerNotSet;
return value->GetInt();
}
base::Optional<SkColor> ProfileAttributesEntry::GetProfileThemeColor(
const char* key) const {
const base::Value* value = GetValue(key);
if (!value || !value->is_int())
return base::nullopt;
return value->GetInt();
}
// 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;
}
bool ProfileAttributesEntry::SetInteger(const char* key, int 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_int() && old_value->GetInt() == 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::ClearValue(const char* key) {
const base::Value* old_data = GetEntryData();
if (!old_data || !old_data->FindKey(key))
return false;
base::Value new_data = GetEntryData()->Clone();
new_data.RemoveKey(key);
SetEntryData(std::move(new_data));
return true;
}