Home | History | Annotate | Download | only in profiles
      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.
      4 
      5 #include "chrome/browser/profiles/profile_info_cache.h"
      6 
      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/rand_util.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_piece.h"
     19 #include "base/strings/utf_string_conversions.h"
     20 #include "base/values.h"
     21 #include "chrome/browser/browser_process.h"
     22 #include "chrome/browser/chrome_notification_types.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 "content/public/browser/notification_service.h"
     31 #include "ui/base/l10n/l10n_util.h"
     32 #include "ui/base/resource/resource_bundle.h"
     33 #include "ui/gfx/image/image.h"
     34 #include "ui/gfx/image/image_util.h"
     35 
     36 using content::BrowserThread;
     37 
     38 namespace {
     39 
     40 const char kNameKey[] = "name";
     41 const char kShortcutNameKey[] = "shortcut_name";
     42 const char kGAIANameKey[] = "gaia_name";
     43 const char kGAIAGivenNameKey[] = "gaia_given_name";
     44 const char kUserNameKey[] = "user_name";
     45 const char kIsUsingDefaultNameKey[] = "is_using_default_name";
     46 const char kIsUsingDefaultAvatarKey[] = "is_using_default_avatar";
     47 const char kAvatarIconKey[] = "avatar_icon";
     48 const char kAuthCredentialsKey[] = "local_auth_credentials";
     49 const char kUseGAIAPictureKey[] = "use_gaia_picture";
     50 const char kBackgroundAppsKey[] = "background_apps";
     51 const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name";
     52 const char kIsOmittedFromProfileListKey[] = "is_omitted_from_profile_list";
     53 const char kSigninRequiredKey[] = "signin_required";
     54 const char kSupervisedUserId[] = "managed_user_id";
     55 const char kProfileIsEphemeral[] = "is_ephemeral";
     56 const char kActiveTimeKey[] = "active_time";
     57 
     58 // First eight are generic icons, which use IDS_NUMBERED_PROFILE_NAME.
     59 const int kDefaultNames[] = {
     60   IDS_DEFAULT_AVATAR_NAME_8,
     61   IDS_DEFAULT_AVATAR_NAME_9,
     62   IDS_DEFAULT_AVATAR_NAME_10,
     63   IDS_DEFAULT_AVATAR_NAME_11,
     64   IDS_DEFAULT_AVATAR_NAME_12,
     65   IDS_DEFAULT_AVATAR_NAME_13,
     66   IDS_DEFAULT_AVATAR_NAME_14,
     67   IDS_DEFAULT_AVATAR_NAME_15,
     68   IDS_DEFAULT_AVATAR_NAME_16,
     69   IDS_DEFAULT_AVATAR_NAME_17,
     70   IDS_DEFAULT_AVATAR_NAME_18,
     71   IDS_DEFAULT_AVATAR_NAME_19,
     72   IDS_DEFAULT_AVATAR_NAME_20,
     73   IDS_DEFAULT_AVATAR_NAME_21,
     74   IDS_DEFAULT_AVATAR_NAME_22,
     75   IDS_DEFAULT_AVATAR_NAME_23,
     76   IDS_DEFAULT_AVATAR_NAME_24,
     77   IDS_DEFAULT_AVATAR_NAME_25,
     78   IDS_DEFAULT_AVATAR_NAME_26
     79 };
     80 
     81 typedef std::vector<unsigned char> ImageData;
     82 
     83 // Writes |data| to disk and takes ownership of the pointer. On successful
     84 // completion, it runs |callback|.
     85 void SaveBitmap(scoped_ptr<ImageData> data,
     86                 const base::FilePath& image_path,
     87                 const base::Closure& callback) {
     88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     89 
     90   // Make sure the destination directory exists.
     91   base::FilePath dir = image_path.DirName();
     92   if (!base::DirectoryExists(dir) && !base::CreateDirectory(dir)) {
     93     LOG(ERROR) << "Failed to create parent directory.";
     94     return;
     95   }
     96 
     97   if (base::WriteFile(image_path, reinterpret_cast<char*>(&(*data)[0]),
     98                       data->size()) == -1) {
     99     LOG(ERROR) << "Failed to save image to file.";
    100     return;
    101   }
    102 
    103   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
    104 }
    105 
    106 // Reads a PNG from disk and decodes it. If the bitmap was successfully read
    107 // from disk the then |out_image| will contain the bitmap image, otherwise it
    108 // will be NULL.
    109 void ReadBitmap(const base::FilePath& image_path,
    110                 gfx::Image** out_image) {
    111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    112   *out_image = NULL;
    113 
    114   // If the path doesn't exist, don't even try reading it.
    115   if (!base::PathExists(image_path))
    116     return;
    117 
    118   std::string image_data;
    119   if (!base::ReadFileToString(image_path, &image_data)) {
    120     LOG(ERROR) << "Failed to read PNG file from disk.";
    121     return;
    122   }
    123 
    124   gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
    125       base::RefCountedString::TakeString(&image_data));
    126   if (image.IsEmpty()) {
    127     LOG(ERROR) << "Failed to decode PNG file.";
    128     return;
    129   }
    130 
    131   *out_image = new gfx::Image(image);
    132 }
    133 
    134 void DeleteBitmap(const base::FilePath& image_path) {
    135   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    136   base::DeleteFile(image_path, false);
    137 }
    138 
    139 }  // namespace
    140 
    141 ProfileInfoCache::ProfileInfoCache(PrefService* prefs,
    142                                    const base::FilePath& user_data_dir)
    143     : prefs_(prefs),
    144       user_data_dir_(user_data_dir) {
    145   // Populate the cache
    146   DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
    147   base::DictionaryValue* cache = update.Get();
    148   for (base::DictionaryValue::Iterator it(*cache);
    149        !it.IsAtEnd(); it.Advance()) {
    150     base::DictionaryValue* info = NULL;
    151     cache->GetDictionaryWithoutPathExpansion(it.key(), &info);
    152     base::string16 name;
    153     info->GetString(kNameKey, &name);
    154     sorted_keys_.insert(FindPositionForProfile(it.key(), name), it.key());
    155 
    156     bool using_default_name;
    157     if (!info->GetBoolean(kIsUsingDefaultNameKey, &using_default_name)) {
    158       // If the preference hasn't been set, and the name is default, assume
    159       // that the user hasn't done this on purpose.
    160       using_default_name = IsDefaultProfileName(name);
    161       info->SetBoolean(kIsUsingDefaultNameKey, using_default_name);
    162     }
    163 
    164     // For profiles that don't have the "using default avatar" state set yet,
    165     // assume it's the same as the "using default name" state.
    166     if (!info->HasKey(kIsUsingDefaultAvatarKey)) {
    167       info->SetBoolean(kIsUsingDefaultAvatarKey, using_default_name);
    168     }
    169   }
    170 
    171   // If needed, start downloading the high-res avatars and migrate any legacy
    172   // profile names.
    173   if (switches::IsNewAvatarMenu())
    174     MigrateLegacyProfileNamesAndDownloadAvatars();
    175 }
    176 
    177 ProfileInfoCache::~ProfileInfoCache() {
    178   STLDeleteContainerPairSecondPointers(
    179       cached_avatar_images_.begin(), cached_avatar_images_.end());
    180   STLDeleteContainerPairSecondPointers(
    181       avatar_images_downloads_in_progress_.begin(),
    182       avatar_images_downloads_in_progress_.end());
    183 }
    184 
    185 void ProfileInfoCache::AddProfileToCache(
    186     const base::FilePath& profile_path,
    187     const base::string16& name,
    188     const base::string16& username,
    189     size_t icon_index,
    190     const std::string& supervised_user_id) {
    191   std::string key = CacheKeyFromProfilePath(profile_path);
    192   DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
    193   base::DictionaryValue* cache = update.Get();
    194 
    195   scoped_ptr<base::DictionaryValue> info(new base::DictionaryValue);
    196   info->SetString(kNameKey, name);
    197   info->SetString(kUserNameKey, username);
    198   info->SetString(kAvatarIconKey,
    199       profiles::GetDefaultAvatarIconUrl(icon_index));
    200   // Default value for whether background apps are running is false.
    201   info->SetBoolean(kBackgroundAppsKey, false);
    202   info->SetString(kSupervisedUserId, supervised_user_id);
    203   info->SetBoolean(kIsOmittedFromProfileListKey, !supervised_user_id.empty());
    204   info->SetBoolean(kProfileIsEphemeral, false);
    205   info->SetBoolean(kIsUsingDefaultNameKey, IsDefaultProfileName(name));
    206   // Assume newly created profiles use a default avatar.
    207   info->SetBoolean(kIsUsingDefaultAvatarKey, true);
    208   cache->SetWithoutPathExpansion(key, info.release());
    209 
    210   sorted_keys_.insert(FindPositionForProfile(key, name), key);
    211 
    212   if (switches::IsNewAvatarMenu())
    213     DownloadHighResAvatar(icon_index, profile_path);
    214 
    215   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    216                     observer_list_,
    217                     OnProfileAdded(profile_path));
    218 
    219   content::NotificationService::current()->Notify(
    220       chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
    221       content::NotificationService::AllSources(),
    222       content::NotificationService::NoDetails());
    223 }
    224 
    225 void ProfileInfoCache::AddObserver(ProfileInfoCacheObserver* obs) {
    226   observer_list_.AddObserver(obs);
    227 }
    228 
    229 void ProfileInfoCache::RemoveObserver(ProfileInfoCacheObserver* obs) {
    230   observer_list_.RemoveObserver(obs);
    231 }
    232 
    233 void ProfileInfoCache::DeleteProfileFromCache(
    234     const base::FilePath& profile_path) {
    235   size_t profile_index = GetIndexOfProfileWithPath(profile_path);
    236   if (profile_index == std::string::npos) {
    237     NOTREACHED();
    238     return;
    239   }
    240   base::string16 name = GetNameOfProfileAtIndex(profile_index);
    241 
    242   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    243                     observer_list_,
    244                     OnProfileWillBeRemoved(profile_path));
    245 
    246   DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
    247   base::DictionaryValue* cache = update.Get();
    248   std::string key = CacheKeyFromProfilePath(profile_path);
    249   cache->Remove(key, NULL);
    250   sorted_keys_.erase(std::find(sorted_keys_.begin(), sorted_keys_.end(), key));
    251 
    252   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    253                     observer_list_,
    254                     OnProfileWasRemoved(profile_path, name));
    255 
    256   content::NotificationService::current()->Notify(
    257       chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
    258       content::NotificationService::AllSources(),
    259       content::NotificationService::NoDetails());
    260 }
    261 
    262 size_t ProfileInfoCache::GetNumberOfProfiles() const {
    263   return sorted_keys_.size();
    264 }
    265 
    266 size_t ProfileInfoCache::GetIndexOfProfileWithPath(
    267     const base::FilePath& profile_path) const {
    268   if (profile_path.DirName() != user_data_dir_)
    269     return std::string::npos;
    270   std::string search_key = CacheKeyFromProfilePath(profile_path);
    271   for (size_t i = 0; i < sorted_keys_.size(); ++i) {
    272     if (sorted_keys_[i] == search_key)
    273       return i;
    274   }
    275   return std::string::npos;
    276 }
    277 
    278 base::string16 ProfileInfoCache::GetNameOfProfileAtIndex(size_t index) const {
    279   base::string16 name;
    280   // Unless the user has customized the profile name, we should use the
    281   // profile's Gaia given name, if it's available.
    282   if (ProfileIsUsingDefaultNameAtIndex(index)) {
    283     base::string16 given_name = GetGAIAGivenNameOfProfileAtIndex(index);
    284     name = given_name.empty() ? GetGAIANameOfProfileAtIndex(index) : given_name;
    285   }
    286   if (name.empty())
    287     GetInfoForProfileAtIndex(index)->GetString(kNameKey, &name);
    288   return name;
    289 }
    290 
    291 base::string16 ProfileInfoCache::GetShortcutNameOfProfileAtIndex(size_t index)
    292     const {
    293   base::string16 shortcut_name;
    294   GetInfoForProfileAtIndex(index)->GetString(
    295       kShortcutNameKey, &shortcut_name);
    296   return shortcut_name;
    297 }
    298 
    299 base::FilePath ProfileInfoCache::GetPathOfProfileAtIndex(size_t index) const {
    300   return user_data_dir_.AppendASCII(sorted_keys_[index]);
    301 }
    302 
    303 base::Time ProfileInfoCache::GetProfileActiveTimeAtIndex(size_t index) const {
    304   double dt;
    305   if (GetInfoForProfileAtIndex(index)->GetDouble(kActiveTimeKey, &dt)) {
    306     return base::Time::FromDoubleT(dt);
    307   } else {
    308     return base::Time();
    309   }
    310 }
    311 
    312 base::string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(
    313     size_t index) const {
    314   base::string16 user_name;
    315   GetInfoForProfileAtIndex(index)->GetString(kUserNameKey, &user_name);
    316   return user_name;
    317 }
    318 
    319 const gfx::Image& ProfileInfoCache::GetAvatarIconOfProfileAtIndex(
    320     size_t index) const {
    321   if (IsUsingGAIAPictureOfProfileAtIndex(index)) {
    322     const gfx::Image* image = GetGAIAPictureOfProfileAtIndex(index);
    323     if (image)
    324       return *image;
    325   }
    326 
    327   // Use the high resolution version of the avatar if it exists.
    328   if (switches::IsNewAvatarMenu()) {
    329     const gfx::Image* image = GetHighResAvatarOfProfileAtIndex(index);
    330     if (image)
    331       return *image;
    332   }
    333 
    334   int resource_id = profiles::GetDefaultAvatarIconResourceIDAtIndex(
    335       GetAvatarIconIndexOfProfileAtIndex(index));
    336   return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
    337 }
    338 
    339 std::string ProfileInfoCache::GetLocalAuthCredentialsOfProfileAtIndex(
    340     size_t index) const {
    341   std::string credentials;
    342   GetInfoForProfileAtIndex(index)->GetString(kAuthCredentialsKey, &credentials);
    343   return credentials;
    344 }
    345 
    346 bool ProfileInfoCache::GetBackgroundStatusOfProfileAtIndex(
    347     size_t index) const {
    348   bool background_app_status;
    349   if (!GetInfoForProfileAtIndex(index)->GetBoolean(kBackgroundAppsKey,
    350                                                    &background_app_status)) {
    351     return false;
    352   }
    353   return background_app_status;
    354 }
    355 
    356 base::string16 ProfileInfoCache::GetGAIANameOfProfileAtIndex(
    357     size_t index) const {
    358   base::string16 name;
    359   GetInfoForProfileAtIndex(index)->GetString(kGAIANameKey, &name);
    360   return name;
    361 }
    362 
    363 base::string16 ProfileInfoCache::GetGAIAGivenNameOfProfileAtIndex(
    364     size_t index) const {
    365   base::string16 name;
    366   GetInfoForProfileAtIndex(index)->GetString(kGAIAGivenNameKey, &name);
    367   return name;
    368 }
    369 
    370 const gfx::Image* ProfileInfoCache::GetGAIAPictureOfProfileAtIndex(
    371     size_t index) const {
    372   base::FilePath path = GetPathOfProfileAtIndex(index);
    373   std::string key = CacheKeyFromProfilePath(path);
    374 
    375   std::string file_name;
    376   GetInfoForProfileAtIndex(index)->GetString(
    377       kGAIAPictureFileNameKey, &file_name);
    378 
    379   // If the picture is not on disk then return NULL.
    380   if (file_name.empty())
    381     return NULL;
    382 
    383   base::FilePath image_path = path.AppendASCII(file_name);
    384   return LoadAvatarPictureFromPath(key, image_path);
    385 }
    386 
    387 bool ProfileInfoCache::IsUsingGAIAPictureOfProfileAtIndex(size_t index) const {
    388   bool value = false;
    389   GetInfoForProfileAtIndex(index)->GetBoolean(kUseGAIAPictureKey, &value);
    390   if (!value) {
    391     // Prefer the GAIA avatar over a non-customized avatar.
    392     value = ProfileIsUsingDefaultAvatarAtIndex(index) &&
    393         GetGAIAPictureOfProfileAtIndex(index);
    394   }
    395   return value;
    396 }
    397 
    398 bool ProfileInfoCache::ProfileIsSupervisedAtIndex(size_t index) const {
    399   return !GetSupervisedUserIdOfProfileAtIndex(index).empty();
    400 }
    401 
    402 bool ProfileInfoCache::IsOmittedProfileAtIndex(size_t index) const {
    403   bool value = false;
    404   GetInfoForProfileAtIndex(index)->GetBoolean(kIsOmittedFromProfileListKey,
    405                                               &value);
    406   return value;
    407 }
    408 
    409 bool ProfileInfoCache::ProfileIsSigninRequiredAtIndex(size_t index) const {
    410   bool value = false;
    411   GetInfoForProfileAtIndex(index)->GetBoolean(kSigninRequiredKey, &value);
    412   return value;
    413 }
    414 
    415 std::string ProfileInfoCache::GetSupervisedUserIdOfProfileAtIndex(
    416     size_t index) const {
    417   std::string supervised_user_id;
    418   GetInfoForProfileAtIndex(index)->GetString(kSupervisedUserId,
    419                                              &supervised_user_id);
    420   return supervised_user_id;
    421 }
    422 
    423 bool ProfileInfoCache::ProfileIsEphemeralAtIndex(size_t index) const {
    424   bool value = false;
    425   GetInfoForProfileAtIndex(index)->GetBoolean(kProfileIsEphemeral, &value);
    426   return value;
    427 }
    428 
    429 bool ProfileInfoCache::ProfileIsUsingDefaultNameAtIndex(size_t index) const {
    430   bool value = false;
    431   GetInfoForProfileAtIndex(index)->GetBoolean(kIsUsingDefaultNameKey, &value);
    432   return value;
    433 }
    434 
    435 bool ProfileInfoCache::ProfileIsUsingDefaultAvatarAtIndex(size_t index) const {
    436   bool value = false;
    437   GetInfoForProfileAtIndex(index)->GetBoolean(kIsUsingDefaultAvatarKey, &value);
    438   return value;
    439 }
    440 
    441 size_t ProfileInfoCache::GetAvatarIconIndexOfProfileAtIndex(size_t index)
    442     const {
    443   std::string icon_url;
    444   GetInfoForProfileAtIndex(index)->GetString(kAvatarIconKey, &icon_url);
    445   size_t icon_index = 0;
    446   if (!profiles::IsDefaultAvatarIconUrl(icon_url, &icon_index))
    447     DLOG(WARNING) << "Unknown avatar icon: " << icon_url;
    448 
    449   return icon_index;
    450 }
    451 
    452 void ProfileInfoCache::SetProfileActiveTimeAtIndex(size_t index) {
    453   scoped_ptr<base::DictionaryValue> info(
    454       GetInfoForProfileAtIndex(index)->DeepCopy());
    455   info->SetDouble(kActiveTimeKey, base::Time::Now().ToDoubleT());
    456   // This takes ownership of |info|.
    457   SetInfoQuietlyForProfileAtIndex(index, info.release());
    458 }
    459 
    460 void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index,
    461                                                const base::string16& name) {
    462   scoped_ptr<base::DictionaryValue> info(
    463       GetInfoForProfileAtIndex(index)->DeepCopy());
    464   base::string16 current_name;
    465   info->GetString(kNameKey, &current_name);
    466   if (name == current_name)
    467     return;
    468 
    469   base::string16 old_display_name = GetNameOfProfileAtIndex(index);
    470   info->SetString(kNameKey, name);
    471 
    472   // This takes ownership of |info|.
    473   SetInfoForProfileAtIndex(index, info.release());
    474 
    475   base::string16 new_display_name = GetNameOfProfileAtIndex(index);
    476   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    477   UpdateSortForProfileIndex(index);
    478 
    479   if (old_display_name != new_display_name) {
    480     FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    481                       observer_list_,
    482                       OnProfileNameChanged(profile_path, old_display_name));
    483   }
    484 }
    485 
    486 void ProfileInfoCache::SetShortcutNameOfProfileAtIndex(
    487     size_t index,
    488     const base::string16& shortcut_name) {
    489   if (shortcut_name == GetShortcutNameOfProfileAtIndex(index))
    490     return;
    491   scoped_ptr<base::DictionaryValue> info(
    492       GetInfoForProfileAtIndex(index)->DeepCopy());
    493   info->SetString(kShortcutNameKey, shortcut_name);
    494   // This takes ownership of |info|.
    495   SetInfoForProfileAtIndex(index, info.release());
    496 }
    497 
    498 void ProfileInfoCache::SetUserNameOfProfileAtIndex(
    499     size_t index,
    500     const base::string16& user_name) {
    501   if (user_name == GetUserNameOfProfileAtIndex(index))
    502     return;
    503 
    504   scoped_ptr<base::DictionaryValue> info(
    505       GetInfoForProfileAtIndex(index)->DeepCopy());
    506   info->SetString(kUserNameKey, user_name);
    507   // This takes ownership of |info|.
    508   SetInfoForProfileAtIndex(index, info.release());
    509 }
    510 
    511 void ProfileInfoCache::SetAvatarIconOfProfileAtIndex(size_t index,
    512                                                      size_t icon_index) {
    513   scoped_ptr<base::DictionaryValue> info(
    514       GetInfoForProfileAtIndex(index)->DeepCopy());
    515   info->SetString(kAvatarIconKey,
    516       profiles::GetDefaultAvatarIconUrl(icon_index));
    517   // This takes ownership of |info|.
    518   SetInfoForProfileAtIndex(index, info.release());
    519 
    520   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    521 
    522   // If needed, start downloading the high-res avatar.
    523   if (switches::IsNewAvatarMenu())
    524     DownloadHighResAvatar(icon_index, profile_path);
    525 
    526   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    527                     observer_list_,
    528                     OnProfileAvatarChanged(profile_path));
    529 }
    530 
    531 void ProfileInfoCache::SetIsOmittedProfileAtIndex(size_t index,
    532                                                   bool is_omitted) {
    533   if (IsOmittedProfileAtIndex(index) == is_omitted)
    534     return;
    535   scoped_ptr<base::DictionaryValue> info(
    536       GetInfoForProfileAtIndex(index)->DeepCopy());
    537   info->SetBoolean(kIsOmittedFromProfileListKey, is_omitted);
    538   // This takes ownership of |info|.
    539   SetInfoForProfileAtIndex(index, info.release());
    540 }
    541 
    542 void ProfileInfoCache::SetSupervisedUserIdOfProfileAtIndex(
    543     size_t index,
    544     const std::string& id) {
    545   if (GetSupervisedUserIdOfProfileAtIndex(index) == id)
    546     return;
    547   scoped_ptr<base::DictionaryValue> info(
    548       GetInfoForProfileAtIndex(index)->DeepCopy());
    549   info->SetString(kSupervisedUserId, id);
    550   // This takes ownership of |info|.
    551   SetInfoForProfileAtIndex(index, info.release());
    552 
    553   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    554   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    555                     observer_list_,
    556                     OnProfileSupervisedUserIdChanged(profile_path));
    557 }
    558 
    559 void ProfileInfoCache::SetLocalAuthCredentialsOfProfileAtIndex(
    560     size_t index,
    561     const std::string& credentials) {
    562   scoped_ptr<base::DictionaryValue> info(
    563       GetInfoForProfileAtIndex(index)->DeepCopy());
    564   info->SetString(kAuthCredentialsKey, credentials);
    565   // This takes ownership of |info|.
    566   SetInfoForProfileAtIndex(index, info.release());
    567 }
    568 
    569 void ProfileInfoCache::SetBackgroundStatusOfProfileAtIndex(
    570     size_t index,
    571     bool running_background_apps) {
    572   if (GetBackgroundStatusOfProfileAtIndex(index) == running_background_apps)
    573     return;
    574   scoped_ptr<base::DictionaryValue> info(
    575       GetInfoForProfileAtIndex(index)->DeepCopy());
    576   info->SetBoolean(kBackgroundAppsKey, running_background_apps);
    577   // This takes ownership of |info|.
    578   SetInfoForProfileAtIndex(index, info.release());
    579 }
    580 
    581 void ProfileInfoCache::SetGAIANameOfProfileAtIndex(size_t index,
    582                                                    const base::string16& name) {
    583   if (name == GetGAIANameOfProfileAtIndex(index))
    584     return;
    585 
    586   base::string16 old_display_name = GetNameOfProfileAtIndex(index);
    587   scoped_ptr<base::DictionaryValue> info(
    588       GetInfoForProfileAtIndex(index)->DeepCopy());
    589   info->SetString(kGAIANameKey, name);
    590   // This takes ownership of |info|.
    591   SetInfoForProfileAtIndex(index, info.release());
    592   base::string16 new_display_name = GetNameOfProfileAtIndex(index);
    593   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    594   UpdateSortForProfileIndex(index);
    595 
    596   if (old_display_name != new_display_name) {
    597     FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    598                       observer_list_,
    599                       OnProfileNameChanged(profile_path, old_display_name));
    600   }
    601 }
    602 
    603 void ProfileInfoCache::SetGAIAGivenNameOfProfileAtIndex(
    604     size_t index,
    605     const base::string16& name) {
    606   if (name == GetGAIAGivenNameOfProfileAtIndex(index))
    607     return;
    608 
    609   base::string16 old_display_name = GetNameOfProfileAtIndex(index);
    610   scoped_ptr<base::DictionaryValue> info(
    611       GetInfoForProfileAtIndex(index)->DeepCopy());
    612   info->SetString(kGAIAGivenNameKey, name);
    613   // This takes ownership of |info|.
    614   SetInfoForProfileAtIndex(index, info.release());
    615   base::string16 new_display_name = GetNameOfProfileAtIndex(index);
    616   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    617   UpdateSortForProfileIndex(index);
    618 
    619   if (old_display_name != new_display_name) {
    620     FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    621                       observer_list_,
    622                       OnProfileNameChanged(profile_path, old_display_name));
    623   }
    624 }
    625 
    626 void ProfileInfoCache::SetGAIAPictureOfProfileAtIndex(size_t index,
    627                                                       const gfx::Image* image) {
    628   base::FilePath path = GetPathOfProfileAtIndex(index);
    629   std::string key = CacheKeyFromProfilePath(path);
    630 
    631   // Delete the old bitmap from cache.
    632   std::map<std::string, gfx::Image*>::iterator it =
    633       cached_avatar_images_.find(key);
    634   if (it != cached_avatar_images_.end()) {
    635     delete it->second;
    636     cached_avatar_images_.erase(it);
    637   }
    638 
    639   std::string old_file_name;
    640   GetInfoForProfileAtIndex(index)->GetString(
    641       kGAIAPictureFileNameKey, &old_file_name);
    642   std::string new_file_name;
    643 
    644   if (!image) {
    645     // Delete the old bitmap from disk.
    646     if (!old_file_name.empty()) {
    647       base::FilePath image_path = path.AppendASCII(old_file_name);
    648       BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    649                               base::Bind(&DeleteBitmap, image_path));
    650     }
    651   } else {
    652     // Save the new bitmap to disk.
    653     new_file_name =
    654         old_file_name.empty() ? profiles::kGAIAPictureFileName : old_file_name;
    655     base::FilePath image_path = path.AppendASCII(new_file_name);
    656     SaveAvatarImageAtPath(
    657         image, key, image_path, GetPathOfProfileAtIndex(index));
    658   }
    659 
    660   scoped_ptr<base::DictionaryValue> info(
    661       GetInfoForProfileAtIndex(index)->DeepCopy());
    662   info->SetString(kGAIAPictureFileNameKey, new_file_name);
    663   // This takes ownership of |info|.
    664   SetInfoForProfileAtIndex(index, info.release());
    665 
    666   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    667                     observer_list_,
    668                     OnProfileAvatarChanged(path));
    669 }
    670 
    671 void ProfileInfoCache::SetIsUsingGAIAPictureOfProfileAtIndex(size_t index,
    672                                                              bool value) {
    673   scoped_ptr<base::DictionaryValue> info(
    674       GetInfoForProfileAtIndex(index)->DeepCopy());
    675   info->SetBoolean(kUseGAIAPictureKey, value);
    676   // This takes ownership of |info|.
    677   SetInfoForProfileAtIndex(index, info.release());
    678 
    679   // Retrieve some info to update observers who care about avatar changes.
    680   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    681   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    682                     observer_list_,
    683                     OnProfileAvatarChanged(profile_path));
    684 }
    685 
    686 void ProfileInfoCache::SetProfileSigninRequiredAtIndex(size_t index,
    687                                                        bool value) {
    688   if (value == ProfileIsSigninRequiredAtIndex(index))
    689     return;
    690 
    691   scoped_ptr<base::DictionaryValue> info(
    692       GetInfoForProfileAtIndex(index)->DeepCopy());
    693   info->SetBoolean(kSigninRequiredKey, value);
    694   // This takes ownership of |info|.
    695   SetInfoForProfileAtIndex(index, info.release());
    696 
    697   base::FilePath profile_path = GetPathOfProfileAtIndex(index);
    698   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
    699                     observer_list_,
    700                     OnProfileSigninRequiredChanged(profile_path));
    701 }
    702 
    703 void ProfileInfoCache::SetProfileIsEphemeralAtIndex(size_t index, bool value) {
    704   if (value == ProfileIsEphemeralAtIndex(index))
    705     return;
    706 
    707   scoped_ptr<base::DictionaryValue> info(
    708       GetInfoForProfileAtIndex(index)->DeepCopy());
    709   info->SetBoolean(kProfileIsEphemeral, value);
    710   // This takes ownership of |info|.
    711   SetInfoForProfileAtIndex(index, info.release());
    712 }
    713 
    714 void ProfileInfoCache::SetProfileIsUsingDefaultNameAtIndex(
    715     size_t index, bool value) {
    716   if (value == ProfileIsUsingDefaultNameAtIndex(index))
    717     return;
    718 
    719   scoped_ptr<base::DictionaryValue> info(
    720       GetInfoForProfileAtIndex(index)->DeepCopy());
    721   info->SetBoolean(kIsUsingDefaultNameKey, value);
    722   // This takes ownership of |info|.
    723   SetInfoForProfileAtIndex(index, info.release());
    724 }
    725 
    726 void ProfileInfoCache::SetProfileIsUsingDefaultAvatarAtIndex(
    727     size_t index, bool value) {
    728   if (value == ProfileIsUsingDefaultAvatarAtIndex(index))
    729     return;
    730 
    731   scoped_ptr<base::DictionaryValue> info(
    732       GetInfoForProfileAtIndex(index)->DeepCopy());
    733   info->SetBoolean(kIsUsingDefaultAvatarKey, value);
    734   // This takes ownership of |info|.
    735   SetInfoForProfileAtIndex(index, info.release());
    736 }
    737 
    738 bool ProfileInfoCache::IsDefaultProfileName(const base::string16& name) const {
    739   // Check if it's a "First user" old-style name.
    740   if (name == l10n_util::GetStringUTF16(IDS_DEFAULT_PROFILE_NAME) ||
    741       name == l10n_util::GetStringUTF16(IDS_LEGACY_DEFAULT_PROFILE_NAME))
    742     return true;
    743 
    744   // Check if it's one of the old-style profile names.
    745   for (size_t i = 0; i < arraysize(kDefaultNames); ++i) {
    746     if (name == l10n_util::GetStringUTF16(kDefaultNames[i]))
    747       return true;
    748   }
    749 
    750   // Check whether it's one of the "Person %d" style names.
    751   std::string default_name_format = l10n_util::GetStringFUTF8(
    752       IDS_NEW_NUMBERED_PROFILE_NAME, base::ASCIIToUTF16("%d"));
    753 
    754   int generic_profile_number;  // Unused. Just a placeholder for sscanf.
    755   int assignments = sscanf(base::UTF16ToUTF8(name).c_str(),
    756                            default_name_format.c_str(),
    757                            &generic_profile_number);
    758   // Unless it matched the format, this is a custom name.
    759   return assignments == 1;
    760 }
    761 
    762 base::string16 ProfileInfoCache::ChooseNameForNewProfile(
    763     size_t icon_index) const {
    764   base::string16 name;
    765   for (int name_index = 1; ; ++name_index) {
    766     if (switches::IsNewAvatarMenu()) {
    767       name = l10n_util::GetStringFUTF16Int(IDS_NEW_NUMBERED_PROFILE_NAME,
    768                                            name_index);
    769     } else if (icon_index < profiles::GetGenericAvatarIconCount()) {
    770       name = l10n_util::GetStringFUTF16Int(IDS_NUMBERED_PROFILE_NAME,
    771                                            name_index);
    772     } else {
    773       name = l10n_util::GetStringUTF16(
    774           kDefaultNames[icon_index - profiles::GetGenericAvatarIconCount()]);
    775       if (name_index > 1)
    776         name.append(base::UTF8ToUTF16(base::IntToString(name_index)));
    777     }
    778 
    779     // Loop through previously named profiles to ensure we're not duplicating.
    780     bool name_found = false;
    781     for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
    782       if (GetNameOfProfileAtIndex(i) == name) {
    783         name_found = true;
    784         break;
    785       }
    786     }
    787     if (!name_found)
    788       return name;
    789   }
    790 }
    791 
    792 size_t ProfileInfoCache::ChooseAvatarIconIndexForNewProfile() const {
    793   size_t icon_index = 0;
    794   // Try to find a unique, non-generic icon.
    795   if (ChooseAvatarIconIndexForNewProfile(false, true, &icon_index))
    796     return icon_index;
    797   // Try to find any unique icon.
    798   if (ChooseAvatarIconIndexForNewProfile(true, true, &icon_index))
    799     return icon_index;
    800   // Settle for any random icon, even if it's not unique.
    801   if (ChooseAvatarIconIndexForNewProfile(true, false, &icon_index))
    802     return icon_index;
    803 
    804   NOTREACHED();
    805   return 0;
    806 }
    807 
    808 const base::FilePath& ProfileInfoCache::GetUserDataDir() const {
    809   return user_data_dir_;
    810 }
    811 
    812 // static
    813 std::vector<base::string16> ProfileInfoCache::GetProfileNames() {
    814   std::vector<base::string16> names;
    815   PrefService* local_state = g_browser_process->local_state();
    816   const base::DictionaryValue* cache = local_state->GetDictionary(
    817       prefs::kProfileInfoCache);
    818   base::string16 name;
    819   for (base::DictionaryValue::Iterator it(*cache); !it.IsAtEnd();
    820        it.Advance()) {
    821     const base::DictionaryValue* info = NULL;
    822     it.value().GetAsDictionary(&info);
    823     info->GetString(kNameKey, &name);
    824     names.push_back(name);
    825   }
    826   return names;
    827 }
    828 
    829 // static
    830 void ProfileInfoCache::RegisterPrefs(PrefRegistrySimple* registry) {
    831   registry->RegisterDictionaryPref(prefs::kProfileInfoCache);
    832 }
    833 
    834 void ProfileInfoCache::DownloadHighResAvatar(
    835     size_t icon_index,
    836     const base::FilePath& profile_path) {
    837   // Downloading is only supported on desktop.
    838 #if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_CHROMEOS)
    839   return;
    840 #endif
    841 
    842   // TODO(noms): We should check whether the file already exists on disk
    843   // before trying to re-download it. For now, since this is behind a flag and
    844   // the resources are still changing, re-download it every time the profile
    845   // avatar changes, to make sure we have the latest copy.
    846   std::string file_name = profiles::GetDefaultAvatarIconFileNameAtIndex(
    847       icon_index);
    848   // If the file is already being downloaded, don't start another download.
    849   if (avatar_images_downloads_in_progress_[file_name])
    850     return;
    851 
    852   // Start the download for this file. The cache takes ownership of the
    853   // |avatar_downloader|, which will be deleted when the download completes, or
    854   // if that never happens, when the ProfileInfoCache is destroyed.
    855   ProfileAvatarDownloader* avatar_downloader = new ProfileAvatarDownloader(
    856       icon_index,
    857       profile_path,
    858       this);
    859   avatar_images_downloads_in_progress_[file_name] = avatar_downloader;
    860   avatar_downloader->Start();
    861 }
    862 
    863 void ProfileInfoCache::SaveAvatarImageAtPath(
    864     const gfx::Image* image,
    865     const std::string& key,
    866     const base::FilePath& image_path,
    867     const base::FilePath& profile_path) {
    868   cached_avatar_images_[key] = new gfx::Image(*image);
    869 
    870   scoped_ptr<ImageData> data(new ImageData);
    871   scoped_refptr<base::RefCountedMemory> png_data = image->As1xPNGBytes();
    872   data->assign(png_data->front(), png_data->front() + png_data->size());
    873 
    874   if (!data->size()) {
    875     LOG(ERROR) << "Failed to PNG encode the image.";
    876   } else {
    877     base::Closure callback = base::Bind(&ProfileInfoCache::OnAvatarPictureSaved,
    878         AsWeakPtr(), key, profile_path);
    879 
    880     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
    881         base::Bind(&SaveBitmap, base::Passed(&data), image_path, callback));
    882   }
    883 }
    884 
    885 const base::DictionaryValue* ProfileInfoCache::GetInfoForProfileAtIndex(
    886     size_t index) const {
    887   DCHECK_LT(index, GetNumberOfProfiles());
    888   const base::DictionaryValue* cache =
    889       prefs_->GetDictionary(prefs::kProfileInfoCache);
    890   const base::DictionaryValue* info = NULL;
    891   cache->GetDictionaryWithoutPathExpansion(sorted_keys_[index], &info);
    892   return info;
    893 }
    894 
    895 void ProfileInfoCache::SetInfoQuietlyForProfileAtIndex(
    896     size_t index, base::DictionaryValue* info) {
    897   DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
    898   base::DictionaryValue* cache = update.Get();
    899   cache->SetWithoutPathExpansion(sorted_keys_[index], info);
    900 }
    901 
    902 // TODO(noms): Switch to newer notification system.
    903 void ProfileInfoCache::SetInfoForProfileAtIndex(size_t index,
    904                                                 base::DictionaryValue* info) {
    905   SetInfoQuietlyForProfileAtIndex(index, info);
    906 
    907   content::NotificationService::current()->Notify(
    908       chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
    909       content::NotificationService::AllSources(),
    910       content::NotificationService::NoDetails());
    911 }
    912 
    913 std::string ProfileInfoCache::CacheKeyFromProfilePath(
    914     const base::FilePath& profile_path) const {
    915   DCHECK(user_data_dir_ == profile_path.DirName());
    916   base::FilePath base_name = profile_path.BaseName();
    917   return base_name.MaybeAsASCII();
    918 }
    919 
    920 std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile(
    921     const std::string& search_key,
    922     const base::string16& search_name) {
    923   base::string16 search_name_l = base::i18n::ToLower(search_name);
    924   for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
    925     base::string16 name_l = base::i18n::ToLower(GetNameOfProfileAtIndex(i));
    926     int name_compare = search_name_l.compare(name_l);
    927     if (name_compare < 0)
    928       return sorted_keys_.begin() + i;
    929     if (name_compare == 0) {
    930       int key_compare = search_key.compare(sorted_keys_[i]);
    931       if (key_compare < 0)
    932         return sorted_keys_.begin() + i;
    933     }
    934   }
    935   return sorted_keys_.end();
    936 }
    937 
    938 bool ProfileInfoCache::IconIndexIsUnique(size_t icon_index) const {
    939   for (size_t i = 0; i < GetNumberOfProfiles(); ++i) {
    940     if (GetAvatarIconIndexOfProfileAtIndex(i) == icon_index)
    941       return false;
    942   }
    943   return true;
    944 }
    945 
    946 bool ProfileInfoCache::ChooseAvatarIconIndexForNewProfile(
    947     bool allow_generic_icon,
    948     bool must_be_unique,
    949     size_t* out_icon_index) const {
    950   // Always allow all icons for new profiles if using the
    951   // --new-avatar-menu flag.
    952   if (switches::IsNewAvatarMenu())
    953     allow_generic_icon = true;
    954   size_t start = allow_generic_icon ? 0 : profiles::GetGenericAvatarIconCount();
    955   size_t end = profiles::GetDefaultAvatarIconCount();
    956   size_t count = end - start;
    957 
    958   int rand = base::RandInt(0, count);
    959   for (size_t i = 0; i < count; ++i) {
    960     size_t icon_index = start + (rand + i) %  count;
    961     if (!must_be_unique || IconIndexIsUnique(icon_index)) {
    962       *out_icon_index = icon_index;
    963       return true;
    964     }
    965   }
    966 
    967   return false;
    968 }
    969 
    970 void ProfileInfoCache::UpdateSortForProfileIndex(size_t index) {
    971   base::string16 name = GetNameOfProfileAtIndex(index);
    972 
    973   // Remove and reinsert key in |sorted_keys_| to alphasort.
    974   std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index));
    975   std::vector<std::string>::iterator key_it =
    976       std::find(sorted_keys_.begin(), sorted_keys_.end(), key);
    977   DCHECK(key_it != sorted_keys_.end());
    978   sorted_keys_.erase(key_it);
    979   sorted_keys_.insert(FindPositionForProfile(key, name), key);
    980 
    981   content::NotificationService::current()->Notify(
    982       chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
    983       content::NotificationService::AllSources(),
    984       content::NotificationService::NoDetails());
    985 }
    986 
    987 const gfx::Image* ProfileInfoCache::GetHighResAvatarOfProfileAtIndex(
    988     size_t index) const {
    989   int avatar_index = GetAvatarIconIndexOfProfileAtIndex(index);
    990   std::string key = profiles::GetDefaultAvatarIconFileNameAtIndex(avatar_index);
    991 
    992   if (!strcmp(key.c_str(), profiles::GetNoHighResAvatarFileName()))
    993       return NULL;
    994 
    995   base::FilePath image_path =
    996       profiles::GetPathOfHighResAvatarAtIndex(avatar_index);
    997   return LoadAvatarPictureFromPath(key, image_path);
    998 }
    999 
   1000 const gfx::Image* ProfileInfoCache::LoadAvatarPictureFromPath(
   1001     const std::string& key,
   1002     const base::FilePath& image_path) const {
   1003   // If the picture is already loaded then use it.
   1004   if (cached_avatar_images_.count(key)) {
   1005     if (cached_avatar_images_[key]->IsEmpty())
   1006       return NULL;
   1007     return cached_avatar_images_[key];
   1008   }
   1009 
   1010   // If the picture is already being loaded then don't try loading it again.
   1011   if (cached_avatar_images_loading_[key])
   1012     return NULL;
   1013   cached_avatar_images_loading_[key] = true;
   1014 
   1015   gfx::Image** image = new gfx::Image*;
   1016   BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
   1017       base::Bind(&ReadBitmap, image_path, image),
   1018       base::Bind(&ProfileInfoCache::OnAvatarPictureLoaded,
   1019           const_cast<ProfileInfoCache*>(this)->AsWeakPtr(), key, image));
   1020   return NULL;
   1021 }
   1022 
   1023 void ProfileInfoCache::OnAvatarPictureLoaded(const std::string& key,
   1024                                              gfx::Image** image) const {
   1025   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1026 
   1027   cached_avatar_images_loading_[key] = false;
   1028   delete cached_avatar_images_[key];
   1029 
   1030   if (*image) {
   1031     cached_avatar_images_[key] = *image;
   1032   } else {
   1033     // Place an empty image in the cache to avoid reloading it again.
   1034     cached_avatar_images_[key] = new gfx::Image();
   1035   }
   1036   delete image;
   1037 
   1038   content::NotificationService::current()->Notify(
   1039       chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
   1040       content::NotificationService::AllSources(),
   1041       content::NotificationService::NoDetails());
   1042 }
   1043 
   1044 void ProfileInfoCache::OnAvatarPictureSaved(
   1045       const std::string& file_name,
   1046       const base::FilePath& profile_path) {
   1047   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1048 
   1049   content::NotificationService::current()->Notify(
   1050       chrome::NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
   1051       content::NotificationService::AllSources(),
   1052       content::NotificationService::NoDetails());
   1053 
   1054   FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
   1055                     observer_list_,
   1056                     OnProfileAvatarChanged(profile_path));
   1057 
   1058   // Remove the file from the list of downloads in progress. Note that this list
   1059   // only contains the high resolution avatars, and not the Gaia profile images.
   1060   if (!avatar_images_downloads_in_progress_[file_name])
   1061     return;
   1062 
   1063   delete avatar_images_downloads_in_progress_[file_name];
   1064   avatar_images_downloads_in_progress_[file_name] = NULL;
   1065 }
   1066 
   1067 void ProfileInfoCache::MigrateLegacyProfileNamesAndDownloadAvatars() {
   1068   DCHECK(switches::IsNewAvatarMenu());
   1069 
   1070   // Only do this on desktop platforms.
   1071 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
   1072   // Migrate any legacy profile names ("First user", "Default Profile") to
   1073   // new style default names ("Person 1"). The problem here is that every
   1074   // time you rename a profile, the ProfileInfoCache sorts itself, so
   1075   // whatever you were iterating through is no longer valid. We need to
   1076   // save a list of the profile paths (which thankfully do not change) that
   1077   // need to be renamed. We also can't pre-compute the new names, as they
   1078   // depend on the names of all the other profiles in the info cache, so they
   1079   // need to be re-computed after each rename.
   1080   std::vector<base::FilePath> profiles_to_rename;
   1081 
   1082   const base::string16 default_profile_name = base::i18n::ToLower(
   1083       l10n_util::GetStringUTF16(IDS_DEFAULT_PROFILE_NAME));
   1084   const base::string16 default_legacy_profile_name = base::i18n::ToLower(
   1085       l10n_util::GetStringUTF16(IDS_LEGACY_DEFAULT_PROFILE_NAME));
   1086 
   1087   for (size_t i = 0; i < GetNumberOfProfiles(); i++) {
   1088     // If needed, start downloading the high-res avatar for this profile.
   1089     DownloadHighResAvatar(GetAvatarIconIndexOfProfileAtIndex(i),
   1090                           GetPathOfProfileAtIndex(i));
   1091 
   1092     base::string16 name = base::i18n::ToLower(GetNameOfProfileAtIndex(i));
   1093     if (name == default_profile_name || name == default_legacy_profile_name)
   1094       profiles_to_rename.push_back(GetPathOfProfileAtIndex(i));
   1095   }
   1096 
   1097   // Rename the necessary profiles.
   1098   std::vector<base::FilePath>::const_iterator it;
   1099   for (it = profiles_to_rename.begin(); it != profiles_to_rename.end(); ++it) {
   1100     size_t profile_index = GetIndexOfProfileWithPath(*it);
   1101     SetProfileIsUsingDefaultNameAtIndex(profile_index, true);
   1102     // This will assign a new "Person %d" type name and re-sort the cache.
   1103     SetNameOfProfileAtIndex(profile_index, ChooseNameForNewProfile(
   1104         GetAvatarIconIndexOfProfileAtIndex(profile_index)));
   1105   }
   1106 #endif
   1107 }
   1108