Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profiles / profile_info_cache.cc
blob652c0f1ce8ab7945f4d922fe289f0bc1b5ffbed3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/profiles/profile_info_cache.h"
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/i18n/case_conversion.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/rand_util.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/profiles/profile_avatar_downloader.h"
24 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
25 #include "chrome/browser/profiles/profiles_state.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/signin/core/common/profile_management_switches.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/gfx/image/image.h"
33 #include "ui/gfx/image/image_util.h"
35 #if defined(ENABLE_SUPERVISED_USERS)
36 #include "chrome/browser/supervised_user/supervised_user_constants.h"
37 #endif
39 using content::BrowserThread;
41 namespace {
43 const char kNameKey[] = "name";
44 const char kShortcutNameKey[] = "shortcut_name";
45 const char kGAIANameKey[] = "gaia_name";
46 const char kGAIAGivenNameKey[] = "gaia_given_name";
47 const char kGAIAIdKey[] = "gaia_id";
48 const char kUserNameKey[] = "user_name";
49 const char kIsUsingDefaultNameKey[] = "is_using_default_name";
50 const char kIsUsingDefaultAvatarKey[] = "is_using_default_avatar";
51 const char kAvatarIconKey[] = "avatar_icon";
52 const char kAuthCredentialsKey[] = "local_auth_credentials";
53 const char kPasswordTokenKey[] = "gaia_password_token";
54 const char kUseGAIAPictureKey[] = "use_gaia_picture";
55 const char kBackgroundAppsKey[] = "background_apps";
56 const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name";
57 const char kIsOmittedFromProfileListKey[] = "is_omitted_from_profile_list";
58 const char kSigninRequiredKey[] = "signin_required";
59 const char kSupervisedUserId[] = "managed_user_id";
60 const char kProfileIsEphemeral[] = "is_ephemeral";
61 const char kActiveTimeKey[] = "active_time";
62 const char kIsAuthErrorKey[] = "is_auth_error";
64 // First eight are generic icons, which use IDS_NUMBERED_PROFILE_NAME.
65 const int kDefaultNames[] = {
66 IDS_DEFAULT_AVATAR_NAME_8,
67 IDS_DEFAULT_AVATAR_NAME_9,
68 IDS_DEFAULT_AVATAR_NAME_10,
69 IDS_DEFAULT_AVATAR_NAME_11,
70 IDS_DEFAULT_AVATAR_NAME_12,
71 IDS_DEFAULT_AVATAR_NAME_13,
72 IDS_DEFAULT_AVATAR_NAME_14,
73 IDS_DEFAULT_AVATAR_NAME_15,
74 IDS_DEFAULT_AVATAR_NAME_16,
75 IDS_DEFAULT_AVATAR_NAME_17,
76 IDS_DEFAULT_AVATAR_NAME_18,
77 IDS_DEFAULT_AVATAR_NAME_19,
78 IDS_DEFAULT_AVATAR_NAME_20,
79 IDS_DEFAULT_AVATAR_NAME_21,
80 IDS_DEFAULT_AVATAR_NAME_22,
81 IDS_DEFAULT_AVATAR_NAME_23,
82 IDS_DEFAULT_AVATAR_NAME_24,
83 IDS_DEFAULT_AVATAR_NAME_25,
84 IDS_DEFAULT_AVATAR_NAME_26
87 typedef std::vector<unsigned char> ImageData;
89 // Writes |data| to disk and takes ownership of the pointer. On successful
90 // completion, it runs |callback|.
91 void SaveBitmap(scoped_ptr<ImageData> data,
92 const base::FilePath& image_path,
93 const base::Closure& callback) {
94 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
96 // Make sure the destination directory exists.
97 base::FilePath dir = image_path.DirName();
98 if (!base::DirectoryExists(dir) && !base::CreateDirectory(dir)) {
99 LOG(ERROR) << "Failed to create parent directory.";
100 return;
103 if (base::WriteFile(image_path, reinterpret_cast<char*>(&(*data)[0]),
104 data->size()) == -1) {
105 LOG(ERROR) << "Failed to save image to file.";
106 return;
109 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
112 // Reads a PNG from disk and decodes it. If the bitmap was successfully read
113 // from disk the then |out_image| will contain the bitmap image, otherwise it
114 // will be NULL.
115 void ReadBitmap(const base::FilePath& image_path,
116 gfx::Image** out_image) {
117 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
118 *out_image = NULL;
120 // If the path doesn't exist, don't even try reading it.
121 if (!base::PathExists(image_path))
122 return;
124 std::string image_data;
125 if (!base::ReadFileToString(image_path, &image_data)) {
126 LOG(ERROR) << "Failed to read PNG file from disk.";
127 return;
130 gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
131 base::RefCountedString::TakeString(&image_data));
132 if (image.IsEmpty()) {
133 LOG(ERROR) << "Failed to decode PNG file.";
134 return;
137 *out_image = new gfx::Image(image);
140 void RunCallbackIfFileMissing(const base::FilePath& file_path,
141 const base::Closure& callback) {
142 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
143 if (!base::PathExists(file_path))
144 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
147 void DeleteBitmap(const base::FilePath& image_path) {
148 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
149 base::DeleteFile(image_path, false);
152 } // namespace
154 ProfileInfoCache::ProfileInfoCache(PrefService* prefs,
155 const base::FilePath& user_data_dir)
156 : prefs_(prefs),
157 user_data_dir_(user_data_dir),
158 disable_avatar_download_for_testing_(false) {
159 // Populate the cache
160 DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
161 base::DictionaryValue* cache = update.Get();
162 for (base::DictionaryValue::Iterator it(*cache);
163 !it.IsAtEnd(); it.Advance()) {
164 base::DictionaryValue* info = NULL;
165 cache->GetDictionaryWithoutPathExpansion(it.key(), &info);
166 base::string16 name;
167 info->GetString(kNameKey, &name);
168 sorted_keys_.insert(FindPositionForProfile(it.key(), name), it.key());
170 bool using_default_name;
171 if (!info->GetBoolean(kIsUsingDefaultNameKey, &using_default_name)) {
172 // If the preference hasn't been set, and the name is default, assume
173 // that the user hasn't done this on purpose.
174 using_default_name = IsDefaultProfileName(name);
175 info->SetBoolean(kIsUsingDefaultNameKey, using_default_name);
178 // For profiles that don't have the "using default avatar" state set yet,
179 // assume it's the same as the "using default name" state.
180 if (!info->HasKey(kIsUsingDefaultAvatarKey)) {
181 info->SetBoolean(kIsUsingDefaultAvatarKey, using_default_name);
185 // If needed, start downloading the high-res avatars and migrate any legacy
186 // profile names.
187 if (switches::IsNewAvatarMenu() && !disable_avatar_download_for_testing_)
188 MigrateLegacyProfileNamesAndDownloadAvatars();
191 ProfileInfoCache::~ProfileInfoCache() {
192 STLDeleteContainerPairSecondPointers(
193 cached_avatar_images_.begin(), cached_avatar_images_.end());
194 STLDeleteContainerPairSecondPointers(
195 avatar_images_downloads_in_progress_.begin(),
196 avatar_images_downloads_in_progress_.end());
199 void ProfileInfoCache::AddProfileToCache(
200 const base::FilePath& profile_path,
201 const base::string16& name,
202 const std::string& gaia_id,
203 const base::string16& user_name,
204 size_t icon_index,
205 const std::string& supervised_user_id) {
206 std::string key = CacheKeyFromProfilePath(profile_path);
207 DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
208 base::DictionaryValue* cache = update.Get();
210 scoped_ptr<base::DictionaryValue> info(new base::DictionaryValue);
211 info->SetString(kNameKey, name);
212 info->SetString(kGAIAIdKey, gaia_id);
213 info->SetString(kUserNameKey, user_name);
214 info->SetString(kAvatarIconKey,
215 profiles::GetDefaultAvatarIconUrl(icon_index));
216 // Default value for whether background apps are running is false.
217 info->SetBoolean(kBackgroundAppsKey, false);
218 info->SetString(kSupervisedUserId, supervised_user_id);
219 info->SetBoolean(kIsOmittedFromProfileListKey, !supervised_user_id.empty());
220 info->SetBoolean(kProfileIsEphemeral, false);
221 info->SetBoolean(kIsUsingDefaultNameKey, IsDefaultProfileName(name));
222 // Assume newly created profiles use a default avatar.
223 info->SetBoolean(kIsUsingDefaultAvatarKey, true);
224 cache->SetWithoutPathExpansion(key, info.release());
226 sorted_keys_.insert(FindPositionForProfile(key, name), key);
228 if (switches::IsNewAvatarMenu() && !disable_avatar_download_for_testing_)
229 DownloadHighResAvatarIfNeeded(icon_index, profile_path);
231 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
232 observer_list_,
233 OnProfileAdded(profile_path));
236 void ProfileInfoCache::AddObserver(ProfileInfoCacheObserver* obs) {
237 observer_list_.AddObserver(obs);
240 void ProfileInfoCache::RemoveObserver(ProfileInfoCacheObserver* obs) {
241 observer_list_.RemoveObserver(obs);
244 void ProfileInfoCache::DeleteProfileFromCache(
245 const base::FilePath& profile_path) {
246 size_t profile_index = GetIndexOfProfileWithPath(profile_path);
247 if (profile_index == std::string::npos) {
248 NOTREACHED();
249 return;
251 base::string16 name = GetNameOfProfileAtIndex(profile_index);
253 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
254 observer_list_,
255 OnProfileWillBeRemoved(profile_path));
257 DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
258 base::DictionaryValue* cache = update.Get();
259 std::string key = CacheKeyFromProfilePath(profile_path);
260 cache->Remove(key, NULL);
261 sorted_keys_.erase(std::find(sorted_keys_.begin(), sorted_keys_.end(), key));
262 profile_attributes_entries_.erase(profile_path);
264 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
265 observer_list_,
266 OnProfileWasRemoved(profile_path, name));
269 size_t ProfileInfoCache::GetNumberOfProfiles() const {
270 return sorted_keys_.size();
273 size_t ProfileInfoCache::GetIndexOfProfileWithPath(
274 const base::FilePath& profile_path) const {
275 if (profile_path.DirName() != user_data_dir_)
276 return std::string::npos;
277 std::string search_key = CacheKeyFromProfilePath(profile_path);
278 for (size_t i = 0; i < sorted_keys_.size(); ++i) {
279 if (sorted_keys_[i] == search_key)
280 return i;
282 return std::string::npos;
285 base::string16 ProfileInfoCache::GetNameOfProfileAtIndex(size_t index) const {
286 base::string16 name;
287 // Unless the user has customized the profile name, we should use the
288 // profile's Gaia given name, if it's available.
289 if (ProfileIsUsingDefaultNameAtIndex(index)) {
290 base::string16 given_name = GetGAIAGivenNameOfProfileAtIndex(index);
291 name = given_name.empty() ? GetGAIANameOfProfileAtIndex(index) : given_name;
293 if (name.empty())
294 GetInfoForProfileAtIndex(index)->GetString(kNameKey, &name);
295 return name;
298 base::string16 ProfileInfoCache::GetShortcutNameOfProfileAtIndex(size_t index)
299 const {
300 base::string16 shortcut_name;
301 GetInfoForProfileAtIndex(index)->GetString(
302 kShortcutNameKey, &shortcut_name);
303 return shortcut_name;
306 base::FilePath ProfileInfoCache::GetPathOfProfileAtIndex(size_t index) const {
307 return user_data_dir_.AppendASCII(sorted_keys_[index]);
310 base::Time ProfileInfoCache::GetProfileActiveTimeAtIndex(size_t index) const {
311 double dt;
312 if (GetInfoForProfileAtIndex(index)->GetDouble(kActiveTimeKey, &dt)) {
313 return base::Time::FromDoubleT(dt);
314 } else {
315 return base::Time();
319 base::string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(
320 size_t index) const {
321 base::string16 user_name;
322 GetInfoForProfileAtIndex(index)->GetString(kUserNameKey, &user_name);
323 return user_name;
326 const gfx::Image& ProfileInfoCache::GetAvatarIconOfProfileAtIndex(
327 size_t index) {
328 if (IsUsingGAIAPictureOfProfileAtIndex(index)) {
329 const gfx::Image* image = GetGAIAPictureOfProfileAtIndex(index);
330 if (image)
331 return *image;
334 // Use the high resolution version of the avatar if it exists.
335 if (switches::IsNewAvatarMenu()) {
336 const gfx::Image* image = GetHighResAvatarOfProfileAtIndex(index);
337 if (image)
338 return *image;
341 int resource_id = profiles::GetDefaultAvatarIconResourceIDAtIndex(
342 GetAvatarIconIndexOfProfileAtIndex(index));
343 return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
346 std::string ProfileInfoCache::GetLocalAuthCredentialsOfProfileAtIndex(
347 size_t index) const {
348 std::string credentials;
349 GetInfoForProfileAtIndex(index)->GetString(kAuthCredentialsKey, &credentials);
350 return credentials;
353 std::string ProfileInfoCache::GetPasswordChangeDetectionTokenAtIndex(
354 size_t index) const {
355 std::string token;
356 GetInfoForProfileAtIndex(index)->GetString(kPasswordTokenKey, &token);
357 return token;
360 bool ProfileInfoCache::GetBackgroundStatusOfProfileAtIndex(
361 size_t index) const {
362 bool background_app_status;
363 if (!GetInfoForProfileAtIndex(index)->GetBoolean(kBackgroundAppsKey,
364 &background_app_status)) {
365 return false;
367 return background_app_status;
370 base::string16 ProfileInfoCache::GetGAIANameOfProfileAtIndex(
371 size_t index) const {
372 base::string16 name;
373 GetInfoForProfileAtIndex(index)->GetString(kGAIANameKey, &name);
374 return name;
377 base::string16 ProfileInfoCache::GetGAIAGivenNameOfProfileAtIndex(
378 size_t index) const {
379 base::string16 name;
380 GetInfoForProfileAtIndex(index)->GetString(kGAIAGivenNameKey, &name);
381 return name;
384 std::string ProfileInfoCache::GetGAIAIdOfProfileAtIndex(
385 size_t index) const {
386 std::string gaia_id;
387 GetInfoForProfileAtIndex(index)->GetString(kGAIAIdKey, &gaia_id);
388 return gaia_id;
391 const gfx::Image* ProfileInfoCache::GetGAIAPictureOfProfileAtIndex(
392 size_t index) const {
393 base::FilePath path = GetPathOfProfileAtIndex(index);
394 std::string key = CacheKeyFromProfilePath(path);
396 std::string file_name;
397 GetInfoForProfileAtIndex(index)->GetString(
398 kGAIAPictureFileNameKey, &file_name);
400 // If the picture is not on disk then return NULL.
401 if (file_name.empty())
402 return NULL;
404 base::FilePath image_path = path.AppendASCII(file_name);
405 return LoadAvatarPictureFromPath(path, key, image_path);
408 bool ProfileInfoCache::IsUsingGAIAPictureOfProfileAtIndex(size_t index) const {
409 bool value = false;
410 GetInfoForProfileAtIndex(index)->GetBoolean(kUseGAIAPictureKey, &value);
411 if (!value) {
412 // Prefer the GAIA avatar over a non-customized avatar.
413 value = ProfileIsUsingDefaultAvatarAtIndex(index) &&
414 GetGAIAPictureOfProfileAtIndex(index);
416 return value;
419 bool ProfileInfoCache::ProfileIsSupervisedAtIndex(size_t index) const {
420 return !GetSupervisedUserIdOfProfileAtIndex(index).empty();
423 bool ProfileInfoCache::ProfileIsChildAtIndex(size_t index) const {
424 #if defined(ENABLE_SUPERVISED_USERS)
425 return GetSupervisedUserIdOfProfileAtIndex(index) ==
426 supervised_users::kChildAccountSUID;
427 #else
428 return false;
429 #endif
432 bool ProfileInfoCache::ProfileIsLegacySupervisedAtIndex(size_t index) const {
433 return ProfileIsSupervisedAtIndex(index) && !ProfileIsChildAtIndex(index);
436 bool ProfileInfoCache::IsOmittedProfileAtIndex(size_t index) const {
437 bool value = false;
438 GetInfoForProfileAtIndex(index)->GetBoolean(kIsOmittedFromProfileListKey,
439 &value);
440 return value;
443 bool ProfileInfoCache::ProfileIsSigninRequiredAtIndex(size_t index) const {
444 bool value = false;
445 GetInfoForProfileAtIndex(index)->GetBoolean(kSigninRequiredKey, &value);
446 return value;
449 std::string ProfileInfoCache::GetSupervisedUserIdOfProfileAtIndex(
450 size_t index) const {
451 std::string supervised_user_id;
452 GetInfoForProfileAtIndex(index)->GetString(kSupervisedUserId,
453 &supervised_user_id);
454 return supervised_user_id;
457 bool ProfileInfoCache::ProfileIsEphemeralAtIndex(size_t index) const {
458 bool value = false;
459 GetInfoForProfileAtIndex(index)->GetBoolean(kProfileIsEphemeral, &value);
460 return value;
463 bool ProfileInfoCache::ProfileIsUsingDefaultNameAtIndex(size_t index) const {
464 bool value = false;
465 GetInfoForProfileAtIndex(index)->GetBoolean(kIsUsingDefaultNameKey, &value);
466 return value;
469 bool ProfileInfoCache::ProfileIsAuthenticatedAtIndex(size_t index) const {
470 // The profile is authenticated if the gaia_id of the info is not empty.
471 // If it is empty, also check if the user name is not empty. This latter
472 // check is needed in case the profile has not been loaded yet and the
473 // gaia_id property has not yet been written.
474 return !GetGAIAIdOfProfileAtIndex(index).empty() ||
475 !GetUserNameOfProfileAtIndex(index).empty();
478 bool ProfileInfoCache::ProfileIsUsingDefaultAvatarAtIndex(size_t index) const {
479 bool value = false;
480 GetInfoForProfileAtIndex(index)->GetBoolean(kIsUsingDefaultAvatarKey, &value);
481 return value;
484 bool ProfileInfoCache::ProfileIsAuthErrorAtIndex(size_t index) const {
485 bool value = false;
486 GetInfoForProfileAtIndex(index)->GetBoolean(kIsAuthErrorKey, &value);
487 return value;
490 size_t ProfileInfoCache::GetAvatarIconIndexOfProfileAtIndex(size_t index)
491 const {
492 std::string icon_url;
493 GetInfoForProfileAtIndex(index)->GetString(kAvatarIconKey, &icon_url);
494 size_t icon_index = 0;
495 if (!profiles::IsDefaultAvatarIconUrl(icon_url, &icon_index))
496 DLOG(WARNING) << "Unknown avatar icon: " << icon_url;
498 return icon_index;
501 void ProfileInfoCache::SetProfileActiveTimeAtIndex(size_t index) {
502 if (base::Time::Now() - GetProfileActiveTimeAtIndex(index) <
503 base::TimeDelta::FromHours(1)) {
504 return;
507 scoped_ptr<base::DictionaryValue> info(
508 GetInfoForProfileAtIndex(index)->DeepCopy());
509 info->SetDouble(kActiveTimeKey, base::Time::Now().ToDoubleT());
510 // This takes ownership of |info|.
511 SetInfoForProfileAtIndex(index, info.release());
514 void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index,
515 const base::string16& name) {
516 scoped_ptr<base::DictionaryValue> info(
517 GetInfoForProfileAtIndex(index)->DeepCopy());
518 base::string16 current_name;
519 info->GetString(kNameKey, &current_name);
520 if (name == current_name)
521 return;
523 base::string16 old_display_name = GetNameOfProfileAtIndex(index);
524 info->SetString(kNameKey, name);
526 // This takes ownership of |info|.
527 SetInfoForProfileAtIndex(index, info.release());
529 base::string16 new_display_name = GetNameOfProfileAtIndex(index);
530 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
531 UpdateSortForProfileIndex(index);
533 if (old_display_name != new_display_name) {
534 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
535 observer_list_,
536 OnProfileNameChanged(profile_path, old_display_name));
540 void ProfileInfoCache::SetShortcutNameOfProfileAtIndex(
541 size_t index,
542 const base::string16& shortcut_name) {
543 if (shortcut_name == GetShortcutNameOfProfileAtIndex(index))
544 return;
545 scoped_ptr<base::DictionaryValue> info(
546 GetInfoForProfileAtIndex(index)->DeepCopy());
547 info->SetString(kShortcutNameKey, shortcut_name);
548 // This takes ownership of |info|.
549 SetInfoForProfileAtIndex(index, info.release());
552 void ProfileInfoCache::SetAuthInfoOfProfileAtIndex(
553 size_t index,
554 const std::string& gaia_id,
555 const base::string16& user_name) {
556 // If both gaia_id and username are unchanged, abort early.
557 if (gaia_id == GetGAIAIdOfProfileAtIndex(index) &&
558 user_name == GetUserNameOfProfileAtIndex(index)) {
559 return;
562 scoped_ptr<base::DictionaryValue> info(
563 GetInfoForProfileAtIndex(index)->DeepCopy());
565 info->SetString(kGAIAIdKey, gaia_id);
566 info->SetString(kUserNameKey, user_name);
568 // This takes ownership of |info|.
569 SetInfoForProfileAtIndex(index, info.release());
571 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
572 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
573 observer_list_,
574 OnProfileAuthInfoChanged(profile_path));
577 void ProfileInfoCache::SetAvatarIconOfProfileAtIndex(size_t index,
578 size_t icon_index) {
579 scoped_ptr<base::DictionaryValue> info(
580 GetInfoForProfileAtIndex(index)->DeepCopy());
581 info->SetString(kAvatarIconKey,
582 profiles::GetDefaultAvatarIconUrl(icon_index));
583 // This takes ownership of |info|.
584 SetInfoForProfileAtIndex(index, info.release());
586 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
588 if (switches::IsNewAvatarMenu() && !disable_avatar_download_for_testing_)
589 DownloadHighResAvatarIfNeeded(icon_index, profile_path);
591 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
592 observer_list_,
593 OnProfileAvatarChanged(profile_path));
596 void ProfileInfoCache::SetIsOmittedProfileAtIndex(size_t index,
597 bool is_omitted) {
598 if (IsOmittedProfileAtIndex(index) == is_omitted)
599 return;
600 scoped_ptr<base::DictionaryValue> info(
601 GetInfoForProfileAtIndex(index)->DeepCopy());
602 info->SetBoolean(kIsOmittedFromProfileListKey, is_omitted);
603 // This takes ownership of |info|.
604 SetInfoForProfileAtIndex(index, info.release());
606 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
607 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
608 observer_list_,
609 OnProfileIsOmittedChanged(profile_path));
612 void ProfileInfoCache::SetSupervisedUserIdOfProfileAtIndex(
613 size_t index,
614 const std::string& id) {
615 if (GetSupervisedUserIdOfProfileAtIndex(index) == id)
616 return;
617 scoped_ptr<base::DictionaryValue> info(
618 GetInfoForProfileAtIndex(index)->DeepCopy());
619 info->SetString(kSupervisedUserId, id);
620 // This takes ownership of |info|.
621 SetInfoForProfileAtIndex(index, info.release());
623 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
624 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
625 observer_list_,
626 OnProfileSupervisedUserIdChanged(profile_path));
629 void ProfileInfoCache::SetLocalAuthCredentialsOfProfileAtIndex(
630 size_t index,
631 const std::string& credentials) {
632 scoped_ptr<base::DictionaryValue> info(
633 GetInfoForProfileAtIndex(index)->DeepCopy());
634 info->SetString(kAuthCredentialsKey, credentials);
635 // This takes ownership of |info|.
636 SetInfoForProfileAtIndex(index, info.release());
639 void ProfileInfoCache::SetPasswordChangeDetectionTokenAtIndex(
640 size_t index,
641 const std::string& token) {
642 scoped_ptr<base::DictionaryValue> info(
643 GetInfoForProfileAtIndex(index)->DeepCopy());
644 info->SetString(kPasswordTokenKey, token);
645 // This takes ownership of |info|.
646 SetInfoForProfileAtIndex(index, info.release());
649 void ProfileInfoCache::SetBackgroundStatusOfProfileAtIndex(
650 size_t index,
651 bool running_background_apps) {
652 if (GetBackgroundStatusOfProfileAtIndex(index) == running_background_apps)
653 return;
654 scoped_ptr<base::DictionaryValue> info(
655 GetInfoForProfileAtIndex(index)->DeepCopy());
656 info->SetBoolean(kBackgroundAppsKey, running_background_apps);
657 // This takes ownership of |info|.
658 SetInfoForProfileAtIndex(index, info.release());
661 void ProfileInfoCache::SetGAIANameOfProfileAtIndex(size_t index,
662 const base::string16& name) {
663 if (name == GetGAIANameOfProfileAtIndex(index))
664 return;
666 base::string16 old_display_name = GetNameOfProfileAtIndex(index);
667 scoped_ptr<base::DictionaryValue> info(
668 GetInfoForProfileAtIndex(index)->DeepCopy());
669 info->SetString(kGAIANameKey, name);
670 // This takes ownership of |info|.
671 SetInfoForProfileAtIndex(index, info.release());
672 base::string16 new_display_name = GetNameOfProfileAtIndex(index);
673 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
674 UpdateSortForProfileIndex(index);
676 if (old_display_name != new_display_name) {
677 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
678 observer_list_,
679 OnProfileNameChanged(profile_path, old_display_name));
683 void ProfileInfoCache::SetGAIAGivenNameOfProfileAtIndex(
684 size_t index,
685 const base::string16& name) {
686 if (name == GetGAIAGivenNameOfProfileAtIndex(index))
687 return;
689 base::string16 old_display_name = GetNameOfProfileAtIndex(index);
690 scoped_ptr<base::DictionaryValue> info(
691 GetInfoForProfileAtIndex(index)->DeepCopy());
692 info->SetString(kGAIAGivenNameKey, name);
693 // This takes ownership of |info|.
694 SetInfoForProfileAtIndex(index, info.release());
695 base::string16 new_display_name = GetNameOfProfileAtIndex(index);
696 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
697 UpdateSortForProfileIndex(index);
699 if (old_display_name != new_display_name) {
700 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
701 observer_list_,
702 OnProfileNameChanged(profile_path, old_display_name));
706 void ProfileInfoCache::SetGAIAPictureOfProfileAtIndex(size_t index,
707 const gfx::Image* image) {
708 base::FilePath path = GetPathOfProfileAtIndex(index);
709 std::string key = CacheKeyFromProfilePath(path);
711 // Delete the old bitmap from cache.
712 std::map<std::string, gfx::Image*>::iterator it =
713 cached_avatar_images_.find(key);
714 if (it != cached_avatar_images_.end()) {
715 delete it->second;
716 cached_avatar_images_.erase(it);
719 std::string old_file_name;
720 GetInfoForProfileAtIndex(index)->GetString(
721 kGAIAPictureFileNameKey, &old_file_name);
722 std::string new_file_name;
724 if (!image) {
725 // Delete the old bitmap from disk.
726 if (!old_file_name.empty()) {
727 base::FilePath image_path = path.AppendASCII(old_file_name);
728 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
729 base::Bind(&DeleteBitmap, image_path));
731 } else {
732 // Save the new bitmap to disk.
733 new_file_name =
734 old_file_name.empty() ? profiles::kGAIAPictureFileName : old_file_name;
735 base::FilePath image_path = path.AppendASCII(new_file_name);
736 SaveAvatarImageAtPath(
737 image, key, image_path, GetPathOfProfileAtIndex(index));
740 scoped_ptr<base::DictionaryValue> info(
741 GetInfoForProfileAtIndex(index)->DeepCopy());
742 info->SetString(kGAIAPictureFileNameKey, new_file_name);
743 // This takes ownership of |info|.
744 SetInfoForProfileAtIndex(index, info.release());
746 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
747 observer_list_,
748 OnProfileAvatarChanged(path));
751 void ProfileInfoCache::SetIsUsingGAIAPictureOfProfileAtIndex(size_t index,
752 bool value) {
753 scoped_ptr<base::DictionaryValue> info(
754 GetInfoForProfileAtIndex(index)->DeepCopy());
755 info->SetBoolean(kUseGAIAPictureKey, value);
756 // This takes ownership of |info|.
757 SetInfoForProfileAtIndex(index, info.release());
759 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
760 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
761 observer_list_,
762 OnProfileAvatarChanged(profile_path));
765 void ProfileInfoCache::SetProfileSigninRequiredAtIndex(size_t index,
766 bool value) {
767 if (value == ProfileIsSigninRequiredAtIndex(index))
768 return;
770 scoped_ptr<base::DictionaryValue> info(
771 GetInfoForProfileAtIndex(index)->DeepCopy());
772 info->SetBoolean(kSigninRequiredKey, value);
773 // This takes ownership of |info|.
774 SetInfoForProfileAtIndex(index, info.release());
776 base::FilePath profile_path = GetPathOfProfileAtIndex(index);
777 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
778 observer_list_,
779 OnProfileSigninRequiredChanged(profile_path));
782 void ProfileInfoCache::SetProfileIsEphemeralAtIndex(size_t index, bool value) {
783 if (value == ProfileIsEphemeralAtIndex(index))
784 return;
786 scoped_ptr<base::DictionaryValue> info(
787 GetInfoForProfileAtIndex(index)->DeepCopy());
788 info->SetBoolean(kProfileIsEphemeral, value);
789 // This takes ownership of |info|.
790 SetInfoForProfileAtIndex(index, info.release());
793 void ProfileInfoCache::SetProfileIsUsingDefaultNameAtIndex(
794 size_t index, bool value) {
795 if (value == ProfileIsUsingDefaultNameAtIndex(index))
796 return;
798 base::string16 old_display_name = GetNameOfProfileAtIndex(index);
800 scoped_ptr<base::DictionaryValue> info(
801 GetInfoForProfileAtIndex(index)->DeepCopy());
802 info->SetBoolean(kIsUsingDefaultNameKey, value);
803 // This takes ownership of |info|.
804 SetInfoForProfileAtIndex(index, info.release());
806 base::string16 new_display_name = GetNameOfProfileAtIndex(index);
807 const base::FilePath profile_path = GetPathOfProfileAtIndex(index);
809 if (old_display_name != new_display_name) {
810 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
811 observer_list_,
812 OnProfileNameChanged(profile_path, old_display_name));
816 void ProfileInfoCache::SetProfileIsUsingDefaultAvatarAtIndex(
817 size_t index, bool value) {
818 if (value == ProfileIsUsingDefaultAvatarAtIndex(index))
819 return;
821 scoped_ptr<base::DictionaryValue> info(
822 GetInfoForProfileAtIndex(index)->DeepCopy());
823 info->SetBoolean(kIsUsingDefaultAvatarKey, value);
824 // This takes ownership of |info|.
825 SetInfoForProfileAtIndex(index, info.release());
828 void ProfileInfoCache::SetProfileIsAuthErrorAtIndex(size_t index, bool value) {
829 if (value == ProfileIsAuthErrorAtIndex(index))
830 return;
832 scoped_ptr<base::DictionaryValue> info(
833 GetInfoForProfileAtIndex(index)->DeepCopy());
834 info->SetBoolean(kIsAuthErrorKey, value);
835 // This takes ownership of |info|.
836 SetInfoForProfileAtIndex(index, info.release());
839 bool ProfileInfoCache::IsDefaultProfileName(const base::string16& name) const {
840 // Check if it's a "First user" old-style name.
841 if (name == l10n_util::GetStringUTF16(IDS_DEFAULT_PROFILE_NAME) ||
842 name == l10n_util::GetStringUTF16(IDS_LEGACY_DEFAULT_PROFILE_NAME))
843 return true;
845 // Check if it's one of the old-style profile names.
846 for (size_t i = 0; i < arraysize(kDefaultNames); ++i) {
847 if (name == l10n_util::GetStringUTF16(kDefaultNames[i]))
848 return true;
851 // Check whether it's one of the "Person %d" style names.
852 std::string default_name_format = l10n_util::GetStringFUTF8(
853 IDS_NEW_NUMBERED_PROFILE_NAME, base::ASCIIToUTF16("%d"));
855 int generic_profile_number; // Unused. Just a placeholder for sscanf.
856 int assignments = sscanf(base::UTF16ToUTF8(name).c_str(),
857 default_name_format.c_str(),
858 &generic_profile_number);
859 // Unless it matched the format, this is a custom name.
860 return assignments == 1;
863 base::string16 ProfileInfoCache::ChooseNameForNewProfile(
864 size_t icon_index) const {
865 base::string16 name;
866 for (int name_index = 1; ; ++name_index) {
867 if (switches::IsNewAvatarMenu()) {
868 name = l10n_util::GetStringFUTF16Int(IDS_NEW_NUMBERED_PROFILE_NAME,
869 name_index);
870 } else if (icon_index < profiles::GetGenericAvatarIconCount()) {
871 name = l10n_util::GetStringFUTF16Int(IDS_NUMBERED_PROFILE_NAME,
872 name_index);
873 } else {
874 name = l10n_util::GetStringUTF16(
875 kDefaultNames[icon_index - profiles::GetGenericAvatarIconCount()]);
876 if (name_index > 1)
877 name.append(base::UTF8ToUTF16(base::IntToString(name_index)));
880 // Loop through previously named profiles to ensure we're not duplicating.
881 bool name_found = false;
882 for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
883 if (GetNameOfProfileAtIndex(i) == name) {
884 name_found = true;
885 break;
888 if (!name_found)
889 return name;
893 size_t ProfileInfoCache::ChooseAvatarIconIndexForNewProfile() const {
894 size_t icon_index = 0;
895 // Try to find a unique, non-generic icon.
896 if (ChooseAvatarIconIndexForNewProfile(false, true, &icon_index))
897 return icon_index;
898 // Try to find any unique icon.
899 if (ChooseAvatarIconIndexForNewProfile(true, true, &icon_index))
900 return icon_index;
901 // Settle for any random icon, even if it's not unique.
902 if (ChooseAvatarIconIndexForNewProfile(true, false, &icon_index))
903 return icon_index;
905 NOTREACHED();
906 return 0;
909 const base::FilePath& ProfileInfoCache::GetUserDataDir() const {
910 return user_data_dir_;
913 // static
914 void ProfileInfoCache::RegisterPrefs(PrefRegistrySimple* registry) {
915 registry->RegisterDictionaryPref(prefs::kProfileInfoCache);
918 void ProfileInfoCache::DownloadHighResAvatarIfNeeded(
919 size_t icon_index,
920 const base::FilePath& profile_path) {
921 // Downloading is only supported on desktop.
922 #if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_CHROMEOS)
923 return;
924 #endif
925 DCHECK(!disable_avatar_download_for_testing_);
927 // If this is the placeholder avatar, it is already included in the
928 // resources, so it doesn't need to be downloaded (and it will never be
929 // requested from disk by GetHighResAvatarOfProfileAtIndex).
930 if (icon_index == profiles::GetPlaceholderAvatarIndex())
931 return;
933 const base::FilePath& file_path =
934 profiles::GetPathOfHighResAvatarAtIndex(icon_index);
935 base::Closure callback =
936 base::Bind(&ProfileInfoCache::DownloadHighResAvatar,
937 AsWeakPtr(),
938 icon_index,
939 profile_path);
940 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
941 base::Bind(&RunCallbackIfFileMissing, file_path, callback));
944 void ProfileInfoCache::SaveAvatarImageAtPath(
945 const gfx::Image* image,
946 const std::string& key,
947 const base::FilePath& image_path,
948 const base::FilePath& profile_path) {
949 cached_avatar_images_[key] = new gfx::Image(*image);
951 scoped_ptr<ImageData> data(new ImageData);
952 scoped_refptr<base::RefCountedMemory> png_data = image->As1xPNGBytes();
953 data->assign(png_data->front(), png_data->front() + png_data->size());
955 // Remove the file from the list of downloads in progress. Note that this list
956 // only contains the high resolution avatars, and not the Gaia profile images.
957 auto downloader_iter = avatar_images_downloads_in_progress_.find(key);
958 if (downloader_iter != avatar_images_downloads_in_progress_.end()) {
959 // We mustn't delete the avatar downloader right here, since we're being
960 // called by it.
961 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
962 downloader_iter->second);
963 avatar_images_downloads_in_progress_.erase(downloader_iter);
966 if (!data->size()) {
967 LOG(ERROR) << "Failed to PNG encode the image.";
968 } else {
969 base::Closure callback = base::Bind(&ProfileInfoCache::OnAvatarPictureSaved,
970 AsWeakPtr(), key, profile_path);
971 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
972 base::Bind(&SaveBitmap, base::Passed(&data), image_path, callback));
976 const base::DictionaryValue* ProfileInfoCache::GetInfoForProfileAtIndex(
977 size_t index) const {
978 DCHECK_LT(index, GetNumberOfProfiles());
979 const base::DictionaryValue* cache =
980 prefs_->GetDictionary(prefs::kProfileInfoCache);
981 const base::DictionaryValue* info = NULL;
982 cache->GetDictionaryWithoutPathExpansion(sorted_keys_[index], &info);
983 return info;
986 void ProfileInfoCache::SetInfoForProfileAtIndex(size_t index,
987 base::DictionaryValue* info) {
988 DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
989 base::DictionaryValue* cache = update.Get();
990 cache->SetWithoutPathExpansion(sorted_keys_[index], info);
993 std::string ProfileInfoCache::CacheKeyFromProfilePath(
994 const base::FilePath& profile_path) const {
995 DCHECK(user_data_dir_ == profile_path.DirName());
996 base::FilePath base_name = profile_path.BaseName();
997 return base_name.MaybeAsASCII();
1000 std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile(
1001 const std::string& search_key,
1002 const base::string16& search_name) {
1003 base::string16 search_name_l = base::i18n::ToLower(search_name);
1004 for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
1005 base::string16 name_l = base::i18n::ToLower(GetNameOfProfileAtIndex(i));
1006 int name_compare = search_name_l.compare(name_l);
1007 if (name_compare < 0)
1008 return sorted_keys_.begin() + i;
1009 if (name_compare == 0) {
1010 int key_compare = search_key.compare(sorted_keys_[i]);
1011 if (key_compare < 0)
1012 return sorted_keys_.begin() + i;
1015 return sorted_keys_.end();
1018 bool ProfileInfoCache::IconIndexIsUnique(size_t icon_index) const {
1019 for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
1020 if (GetAvatarIconIndexOfProfileAtIndex(i) == icon_index)
1021 return false;
1023 return true;
1026 bool ProfileInfoCache::ChooseAvatarIconIndexForNewProfile(
1027 bool allow_generic_icon,
1028 bool must_be_unique,
1029 size_t* out_icon_index) const {
1030 // Always allow all icons for new profiles if using the
1031 // --new-avatar-menu flag.
1032 if (switches::IsNewAvatarMenu())
1033 allow_generic_icon = true;
1034 size_t start = allow_generic_icon ? 0 : profiles::GetGenericAvatarIconCount();
1035 size_t end = profiles::GetDefaultAvatarIconCount();
1036 size_t count = end - start;
1038 int rand = base::RandInt(0, count);
1039 for (size_t i = 0; i < count; ++i) {
1040 size_t icon_index = start + (rand + i) % count;
1041 if (!must_be_unique || IconIndexIsUnique(icon_index)) {
1042 *out_icon_index = icon_index;
1043 return true;
1047 return false;
1050 void ProfileInfoCache::UpdateSortForProfileIndex(size_t index) {
1051 base::string16 name = GetNameOfProfileAtIndex(index);
1053 // Remove and reinsert key in |sorted_keys_| to alphasort.
1054 std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index));
1055 std::vector<std::string>::iterator key_it =
1056 std::find(sorted_keys_.begin(), sorted_keys_.end(), key);
1057 DCHECK(key_it != sorted_keys_.end());
1058 sorted_keys_.erase(key_it);
1059 sorted_keys_.insert(FindPositionForProfile(key, name), key);
1062 const gfx::Image* ProfileInfoCache::GetHighResAvatarOfProfileAtIndex(
1063 size_t index) const {
1064 const size_t avatar_index = GetAvatarIconIndexOfProfileAtIndex(index);
1066 // If this is the placeholder avatar, it is already included in the
1067 // resources, so it doesn't need to be downloaded.
1068 if (avatar_index == profiles::GetPlaceholderAvatarIndex()) {
1069 return &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1070 profiles::GetPlaceholderAvatarIconResourceID());
1073 const std::string file_name =
1074 profiles::GetDefaultAvatarIconFileNameAtIndex(avatar_index);
1075 const base::FilePath image_path =
1076 profiles::GetPathOfHighResAvatarAtIndex(avatar_index);
1077 return LoadAvatarPictureFromPath(GetPathOfProfileAtIndex(index), file_name,
1078 image_path);
1081 void ProfileInfoCache::DownloadHighResAvatar(
1082 size_t icon_index,
1083 const base::FilePath& profile_path) {
1084 // Downloading is only supported on desktop.
1085 #if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_CHROMEOS)
1086 return;
1087 #endif
1088 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1089 // is fixed.
1090 tracked_objects::ScopedTracker tracking_profile1(
1091 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1092 "461175 ProfileInfoCache::DownloadHighResAvatar::GetFileName"));
1093 const char* file_name =
1094 profiles::GetDefaultAvatarIconFileNameAtIndex(icon_index);
1095 DCHECK(file_name);
1096 // If the file is already being downloaded, don't start another download.
1097 if (avatar_images_downloads_in_progress_.count(file_name))
1098 return;
1100 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1101 // is fixed.
1102 tracked_objects::ScopedTracker tracking_profile2(
1103 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1104 "461175 ProfileInfoCache::DownloadHighResAvatar::MakeDownloader"));
1105 // Start the download for this file. The cache takes ownership of the
1106 // |avatar_downloader|, which will be deleted when the download completes, or
1107 // if that never happens, when the ProfileInfoCache is destroyed.
1108 ProfileAvatarDownloader* avatar_downloader = new ProfileAvatarDownloader(
1109 icon_index,
1110 profile_path,
1111 this);
1112 avatar_images_downloads_in_progress_[file_name] = avatar_downloader;
1114 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1115 // is fixed.
1116 tracked_objects::ScopedTracker tracking_profile3(
1117 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1118 "461175 ProfileInfoCache::DownloadHighResAvatar::StartDownload"));
1119 avatar_downloader->Start();
1122 const gfx::Image* ProfileInfoCache::LoadAvatarPictureFromPath(
1123 const base::FilePath& profile_path,
1124 const std::string& key,
1125 const base::FilePath& image_path) const {
1126 // If the picture is already loaded then use it.
1127 if (cached_avatar_images_.count(key)) {
1128 if (cached_avatar_images_[key]->IsEmpty())
1129 return NULL;
1130 return cached_avatar_images_[key];
1133 // Don't download the image if downloading is disabled for tests.
1134 if (disable_avatar_download_for_testing_)
1135 return NULL;
1137 // If the picture is already being loaded then don't try loading it again.
1138 if (cached_avatar_images_loading_[key])
1139 return NULL;
1140 cached_avatar_images_loading_[key] = true;
1142 gfx::Image** image = new gfx::Image*;
1143 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
1144 base::Bind(&ReadBitmap, image_path, image),
1145 base::Bind(&ProfileInfoCache::OnAvatarPictureLoaded,
1146 const_cast<ProfileInfoCache*>(this)->AsWeakPtr(),
1147 profile_path, key, image));
1148 return NULL;
1151 void ProfileInfoCache::OnAvatarPictureLoaded(const base::FilePath& profile_path,
1152 const std::string& key,
1153 gfx::Image** image) const {
1154 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1155 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1156 // is fixed.
1157 tracked_objects::ScopedTracker tracking_profile1(
1158 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1159 "461175 ProfileInfoCache::OnAvatarPictureLoaded::Start"));
1161 cached_avatar_images_loading_[key] = false;
1162 delete cached_avatar_images_[key];
1164 if (*image) {
1165 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1166 // is fixed.
1167 tracked_objects::ScopedTracker tracking_profile2(
1168 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1169 "461175 ProfileInfoCache::OnAvatarPictureLoaded::SetImage"));
1170 cached_avatar_images_[key] = *image;
1171 } else {
1172 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1173 // is fixed.
1174 tracked_objects::ScopedTracker tracking_profile3(
1175 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1176 "461175 ProfileInfoCache::OnAvatarPictureLoaded::MakeEmptyImage"));
1177 // Place an empty image in the cache to avoid reloading it again.
1178 cached_avatar_images_[key] = new gfx::Image();
1180 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
1181 // is fixed.
1182 tracked_objects::ScopedTracker tracking_profile4(
1183 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1184 "461175 ProfileInfoCache::OnAvatarPictureLoaded::DeleteImage"));
1185 delete image;
1187 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
1188 observer_list_,
1189 OnProfileHighResAvatarLoaded(profile_path));
1192 void ProfileInfoCache::OnAvatarPictureSaved(
1193 const std::string& file_name,
1194 const base::FilePath& profile_path) {
1195 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1197 FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
1198 observer_list_,
1199 OnProfileHighResAvatarLoaded(profile_path));
1202 void ProfileInfoCache::MigrateLegacyProfileNamesAndDownloadAvatars() {
1203 DCHECK(switches::IsNewAvatarMenu());
1205 // Only do this on desktop platforms.
1206 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
1207 // Migrate any legacy profile names ("First user", "Default Profile") to
1208 // new style default names ("Person 1"). The problem here is that every
1209 // time you rename a profile, the ProfileInfoCache sorts itself, so
1210 // whatever you were iterating through is no longer valid. We need to
1211 // save a list of the profile paths (which thankfully do not change) that
1212 // need to be renamed. We also can't pre-compute the new names, as they
1213 // depend on the names of all the other profiles in the info cache, so they
1214 // need to be re-computed after each rename.
1215 std::vector<base::FilePath> profiles_to_rename;
1217 const base::string16 default_profile_name = base::i18n::ToLower(
1218 l10n_util::GetStringUTF16(IDS_DEFAULT_PROFILE_NAME));
1219 const base::string16 default_legacy_profile_name = base::i18n::ToLower(
1220 l10n_util::GetStringUTF16(IDS_LEGACY_DEFAULT_PROFILE_NAME));
1222 for (size_t i = 0; i < GetNumberOfProfiles(); i++) {
1223 DownloadHighResAvatarIfNeeded(GetAvatarIconIndexOfProfileAtIndex(i),
1224 GetPathOfProfileAtIndex(i));
1226 base::string16 name = base::i18n::ToLower(GetNameOfProfileAtIndex(i));
1227 if (name == default_profile_name || name == default_legacy_profile_name)
1228 profiles_to_rename.push_back(GetPathOfProfileAtIndex(i));
1231 // Rename the necessary profiles.
1232 std::vector<base::FilePath>::const_iterator it;
1233 for (it = profiles_to_rename.begin(); it != profiles_to_rename.end(); ++it) {
1234 size_t profile_index = GetIndexOfProfileWithPath(*it);
1235 SetProfileIsUsingDefaultNameAtIndex(profile_index, true);
1236 // This will assign a new "Person %d" type name and re-sort the cache.
1237 SetNameOfProfileAtIndex(profile_index, ChooseNameForNewProfile(
1238 GetAvatarIconIndexOfProfileAtIndex(profile_index)));
1240 #endif
1243 void ProfileInfoCache::AddProfile(
1244 const base::FilePath& profile_path,
1245 const base::string16& name,
1246 const std::string& gaia_id,
1247 const base::string16& user_name,
1248 size_t icon_index,
1249 const std::string& supervised_user_id) {
1250 AddProfileToCache(
1251 profile_path, name, gaia_id, user_name, icon_index, supervised_user_id);
1254 void ProfileInfoCache::RemoveProfile(const base::FilePath& profile_path) {
1255 DeleteProfileFromCache(profile_path);
1258 std::vector<ProfileAttributesEntry*>
1259 ProfileInfoCache::GetAllProfilesAttributes() {
1260 std::vector<ProfileAttributesEntry*> ret;
1261 for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
1262 ProfileAttributesEntry* entry;
1263 if (GetProfileAttributesWithPath(GetPathOfProfileAtIndex(i), &entry)) {
1264 ret.push_back(entry);
1267 return ret;
1270 bool ProfileInfoCache::GetProfileAttributesWithPath(
1271 const base::FilePath& path, ProfileAttributesEntry** entry) {
1272 if (GetNumberOfProfiles() == 0)
1273 return false;
1275 if (GetIndexOfProfileWithPath(path) == std::string::npos)
1276 return false;
1278 if (profile_attributes_entries_.find(path) ==
1279 profile_attributes_entries_.end()) {
1280 // The profile info is in the cache but its entry isn't created yet, insert
1281 // it in the map.
1282 scoped_ptr<ProfileAttributesEntry> new_entry(new ProfileAttributesEntry());
1283 profile_attributes_entries_.add(path, new_entry.Pass());
1284 profile_attributes_entries_.get(path)->Initialize(this, path);
1287 *entry = profile_attributes_entries_.get(path);
1288 return true;