Chromium Code Reviews| Index: chrome/browser/profiles/profile_info_cache.cc |
| diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc |
| index c0966da348b2ab04e09c279767c0bc8a1308188f..2678ead749ea6f0536266469b3de7ea29b006960 100644 |
| --- a/chrome/browser/profiles/profile_info_cache.cc |
| +++ b/chrome/browser/profiles/profile_info_cache.cc |
| @@ -4,10 +4,14 @@ |
| #include "chrome/browser/profiles/profile_info_cache.h" |
| +#include "base/bind.h" |
| +#include "base/file_util.h" |
| #include "base/format_macros.h" |
| +#include "base/i18n/case_conversion.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/rand_util.h" |
| +#include "base/stl_util.h" |
| #include "base/string_number_conversions.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| @@ -16,19 +20,31 @@ |
| #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/pref_names.h" |
| +#include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_service.h" |
| #include "grit/generated_resources.h" |
| #include "grit/theme_resources.h" |
| +#include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| +#include "ui/gfx/codec/png_codec.h" |
| +#include "ui/gfx/image/image.h" |
| +#include "ui/gfx/image/image_util.h" |
| + |
| +using content::BrowserThread; |
| namespace { |
| const char kNameKey[] = "name"; |
| +const char kGAIANameKey[] = "gaia_name"; |
| +const char kUseGAIANameKey[] = "use_gaia_name"; |
| const char kUserNameKey[] = "user_name"; |
| const char kAvatarIconKey[] = "avatar_icon"; |
| +const char kUseGAIAPictureKey[] = "use_gaia_picture"; |
| const char kBackgroundAppsKey[] = "background_apps"; |
| +const char kHasMigratedToGAIAInfoKey[] = "has_migrated_to_gaia_info"; |
| const char kDefaultUrlPrefix[] = "chrome://theme/IDR_PROFILE_AVATAR_"; |
| +const char kGAIAPictureFileName[] = "Google Picture.png"; |
| const int kDefaultAvatarIconResources[] = { |
| IDR_PROFILE_AVATAR_0, |
| @@ -86,6 +102,56 @@ const int kDefaultNames[] = { |
| IDS_DEFAULT_AVATAR_NAME_25 |
| }; |
|
Miranda Callahan
2011/11/17 15:21:10
These two methods seem really out of place in Prof
sail
2011/11/21 23:52:47
I think this is a good idea. Mind if I do this lat
|
| +// Writes the given bitmap as a PNG to disk. |callback| is invoked |
| +// on completion with true on success and false on failure. |
| +void SaveBitmap(gfx::Image image, |
| + FilePath image_path, |
| + base::Callback<void(bool)> callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + std::vector<unsigned char> encoded_image; |
| + if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, true, &encoded_image)) { |
| + LOG(ERROR) << "Failed to PNG encode the image."; |
| + callback.Run(false); |
| + return; |
| + } |
| + |
| + if (file_util::WriteFile(image_path, |
| + reinterpret_cast<char*>(&encoded_image[0]), |
| + encoded_image.size()) == -1) { |
| + LOG(ERROR) << "Failed to save image to file."; |
| + callback.Run(false); |
| + return; |
| + } |
| + |
| + callback.Run(true); |
| +} |
| + |
| +// Reads a PNG from disk and decodes it. |callback| is invoked on |
| +// completion. If the bitmap was successfully read from disk the then callback |
| +// parameter will contain the bitmap image, otherwise it will be NULL. |
| +void ReadBitmap(FilePath image_path, |
| + base::Callback<void(gfx::Image*)> callback) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + |
| + std::string image_data; |
| + if (!file_util::ReadFileToString(image_path, &image_data)) { |
| + LOG(ERROR) << "Failed to read PNG file from disk."; |
| + callback.Run(NULL); |
| + return; |
| + } |
| + |
| + const unsigned char* data = |
| + reinterpret_cast<const unsigned char*>(image_data.data()); |
| + gfx::Image* image = gfx::ImageFromPNGEncodedData(data, image_data.length()); |
| + if (image == NULL) { |
| + LOG(ERROR) << "Failed to decode PNG file."; |
| + callback.Run(NULL); |
| + return; |
| + } |
| + |
| + callback.Run(image); |
| +} |
| + |
| } // namespace |
| ProfileInfoCache::ProfileInfoCache(PrefService* prefs, |
| @@ -107,6 +173,8 @@ ProfileInfoCache::ProfileInfoCache(PrefService* prefs, |
| } |
| ProfileInfoCache::~ProfileInfoCache() { |
| + STLDeleteContainerPairSecondPointers( |
| + gaia_pictures_.begin(), gaia_pictures_.end()); |
| } |
| void ProfileInfoCache::AddProfileToCache(const FilePath& profile_path, |
| @@ -164,19 +232,16 @@ size_t ProfileInfoCache::GetIndexOfProfileWithPath( |
| } |
| string16 ProfileInfoCache::GetNameOfProfileAtIndex(size_t index) const { |
| + if (GetIsUsingGAIANameOfProfileAtIndex(index)) |
| + return GetGAIANameOfProfileAtIndex(index); |
| + |
| string16 name; |
| GetInfoForProfileAtIndex(index)->GetString(kNameKey, &name); |
| return name; |
| } |
| FilePath ProfileInfoCache::GetPathOfProfileAtIndex(size_t index) const { |
| - FilePath::StringType base_name; |
| -#if defined(OS_POSIX) |
| - base_name = sorted_keys_[index]; |
| -#elif defined(OS_WIN) |
| - base_name = ASCIIToWide(sorted_keys_[index]); |
| -#endif |
| - return user_data_dir_.Append(base_name); |
| + return user_data_dir_.AppendASCII(sorted_keys_[index]); |
| } |
| string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(size_t index) const { |
| @@ -187,6 +252,9 @@ string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(size_t index) const { |
| const gfx::Image& ProfileInfoCache::GetAvatarIconOfProfileAtIndex( |
| size_t index) const { |
| + if (GetIsUsingGAIAPictureOfProfileAtIndex(index)) |
| + return GetGAIAPictureOfProfileAtIndex(index); |
| + |
| int resource_id = GetDefaultAvatarIconResourceIDAtIndex( |
| GetAvatarIconIndexOfProfileAtIndex(index)); |
| return ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); |
| @@ -200,6 +268,70 @@ bool ProfileInfoCache::GetBackgroundStatusOfProfileAtIndex( |
| return background_app_status; |
| } |
| +string16 ProfileInfoCache::GetGAIANameOfProfileAtIndex(size_t index) const { |
| + string16 name; |
| + GetInfoForProfileAtIndex(index)->GetString(kGAIANameKey, &name); |
| + return name; |
| +} |
| + |
| +bool ProfileInfoCache::GetIsUsingGAIANameOfProfileAtIndex(size_t index) const { |
| + bool value = false; |
| + GetInfoForProfileAtIndex(index)->GetBoolean(kUseGAIANameKey, &value); |
| + return value; |
| +} |
| + |
| +const gfx::Image& ProfileInfoCache::GetGAIAPictureOfProfileAtIndex( |
| + size_t index) const { |
| + FilePath path = GetPathOfProfileAtIndex(index); |
| + std::string key = CacheKeyFromProfilePath(path); |
| + if (gaia_pictures_.count(key)) { |
| + return *gaia_pictures_[key]; |
| + } |
| + |
| + // The GAIA picture is not in the cache yet. Load it from disk and return |
| + // a blank picture for now. |
| + gaia_pictures_[key] = new gfx::Image(new SkBitmap()); |
| + |
| + FilePath image_path = path.AppendASCII(kGAIAPictureFileName); |
| + base::Callback<void(gfx::Image*)> callback = base::Bind( |
| + &ProfileInfoCache::OnGAIAPictureLoaded, base::Unretained(this), path); |
|
Miranda Callahan
2011/11/17 15:21:10
Could we be heading for trouble by using "Unretain
Robert Sesek
2011/11/17 20:42:04
Definitely. You need to use WeakPtrFactory.
sail
2011/11/21 23:52:47
Done.
|
| + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| + base::Bind(&ReadBitmap, image_path, callback)); |
| + |
| + return *gaia_pictures_[key]; |
| +} |
| + |
| +void ProfileInfoCache::OnGAIAPictureLoaded(FilePath path, |
| + gfx::Image* image) const { |
| + if (!image) |
| + return; |
| + |
| + std::string key = CacheKeyFromProfilePath(path); |
| + gaia_pictures_[key] = image; |
| + |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
|
Robert Sesek
2011/11/17 20:42:04
nit: indent 4
sail
2011/11/21 23:52:47
Done.
|
| + content::NotificationService::AllSources(), |
| + content::NotificationService::NoDetails()); |
| +} |
| + |
| +void ProfileInfoCache::OnGAIAPictureSaved(FilePath path, bool success) const { |
| + if (!success) |
| + return; |
| + |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED, |
|
Robert Sesek
2011/11/17 20:42:04
nit: indent 4
sail
2011/11/21 23:52:47
Done.
|
| + content::NotificationService::AllSources(), |
| + content::NotificationService::NoDetails()); |
| +} |
| + |
| +bool ProfileInfoCache::GetIsUsingGAIAPictureOfProfileAtIndex( |
| + size_t index) const { |
| + bool value = false; |
| + GetInfoForProfileAtIndex(index)->GetBoolean(kUseGAIAPictureKey, &value); |
| + return value; |
| +} |
| + |
| size_t ProfileInfoCache::GetAvatarIconIndexOfProfileAtIndex(size_t index) |
| const { |
| std::string icon_url; |
| @@ -214,34 +346,22 @@ size_t ProfileInfoCache::GetAvatarIconIndexOfProfileAtIndex(size_t index) |
| void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index, |
| const string16& name) { |
| + if (name == GetNameOfProfileAtIndex(index)) |
| + return; |
| + |
| scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| info->SetString(kNameKey, name); |
| // This takes ownership of |info|. |
| SetInfoForProfileAtIndex(index, info.release()); |
| - |
| - // Remove and reinsert key in |sorted_keys_| to alphasort. |
| - std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index)); |
| - std::vector<std::string>::iterator key_it = |
| - std::find(sorted_keys_.begin(), sorted_keys_.end(), key); |
| - DCHECK(key_it != sorted_keys_.end()); |
| - sorted_keys_.erase(key_it); |
| - sorted_keys_.insert(FindPositionForProfile(key, name), key); |
| - |
| - content::NotificationService::current()->Notify( |
| - chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
| - content::NotificationService::AllSources(), |
| - content::NotificationService::NoDetails()); |
| + UpdateSortForProfileIndex(index); |
| } |
| void ProfileInfoCache::SetUserNameOfProfileAtIndex(size_t index, |
| const string16& user_name) { |
| - string16 old_user_name; |
| - const base::DictionaryValue* old_info = GetInfoForProfileAtIndex(index); |
| - old_info->GetString(kUserNameKey, &old_user_name); |
| - if (old_user_name == user_name) |
| + if (user_name == GetUserNameOfProfileAtIndex(index)) |
| return; |
| - scoped_ptr<DictionaryValue> info(old_info->DeepCopy()); |
| + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| info->SetString(kUserNameKey, user_name); |
| // This takes ownership of |info|. |
| SetInfoForProfileAtIndex(index, info.release()); |
| @@ -266,6 +386,59 @@ void ProfileInfoCache::SetBackgroundStatusOfProfileAtIndex( |
| SetInfoForProfileAtIndex(index, info.release()); |
| } |
| +void ProfileInfoCache::SetGAIANameOfProfileAtIndex(size_t index, |
| + const string16& name) { |
| + if (name == GetGAIANameOfProfileAtIndex(index)) |
| + return; |
| + |
| + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| + info->SetString(kGAIANameKey, name); |
| + // This takes ownership of |info|. |
| + SetInfoForProfileAtIndex(index, info.release()); |
| + UpdateSortForProfileIndex(index); |
| +} |
| + |
| +void ProfileInfoCache::SetIsUsingGAIANameOfProfileAtIndex(size_t index, |
| + bool value) { |
| + if (value == GetIsUsingGAIANameOfProfileAtIndex(index)) |
| + return; |
| + |
| + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| + info->SetBoolean(kUseGAIANameKey, value); |
| + // This takes ownership of |info|. |
| + SetInfoForProfileAtIndex(index, info.release()); |
| + UpdateSortForProfileIndex(index); |
| +} |
| + |
| +void ProfileInfoCache::SetGAIAPictureOfProfileAtIndex(size_t index, |
| + const gfx::Image& image) { |
| + FilePath path = GetPathOfProfileAtIndex(index); |
| + std::string key = CacheKeyFromProfilePath(path); |
| + |
| + delete gaia_pictures_[key]; |
| + gaia_pictures_[key] = new gfx::Image(image); |
| + |
| + FilePath image_path = path.AppendASCII(kGAIAPictureFileName); |
| + base::Callback<void(bool)> callback = base::Bind( |
| + &ProfileInfoCache::OnGAIAPictureSaved, base::Unretained(this), path); |
| + BrowserThread::PostTask(BrowserThread::FILE, |
| + FROM_HERE, |
| + base::Bind(&SaveBitmap, image, image_path, callback)); |
| + |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
|
Robert Sesek
2011/11/17 20:42:04
nit: indent 4
sail
2011/11/21 23:52:47
Done.
|
| + content::NotificationService::AllSources(), |
| + content::NotificationService::NoDetails()); |
| +} |
| + |
| +void ProfileInfoCache::SetIsUsingGAIAPictureOfProfileAtIndex(size_t index, |
| + bool value) { |
| + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| + info->SetBoolean(kUseGAIAPictureKey, value); |
| + // This takes ownership of |info|. |
| + SetInfoForProfileAtIndex(index, info.release()); |
| +} |
| + |
| string16 ProfileInfoCache::ChooseNameForNewProfile(size_t icon_index) { |
| string16 name; |
| for (int name_index = 1; ; ++name_index) { |
| @@ -292,6 +465,22 @@ string16 ProfileInfoCache::ChooseNameForNewProfile(size_t icon_index) { |
| } |
| } |
| +bool ProfileInfoCache::GetHasMigratedToGAIAInfoOfProfileAtIndex( |
| + size_t index) const { |
| + bool value = false; |
| + GetInfoForProfileAtIndex(index)->GetBoolean( |
| + kHasMigratedToGAIAInfoKey, &value); |
| + return value; |
| +} |
| + |
| +void ProfileInfoCache::SetHasMigratedToGAIAInfoOfProfileAtIndex( |
| + size_t index, bool value) { |
| + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); |
| + info->SetBoolean(kHasMigratedToGAIAInfoKey, value); |
| + // This takes ownership of |info|. |
| + SetInfoForProfileAtIndex(index, info.release()); |
| +} |
| + |
| bool ProfileInfoCache::IconIndexIsUnique(size_t icon_index) const { |
| for (size_t i = 0; i < GetNumberOfProfiles(); ++i) { |
| if (GetAvatarIconIndexOfProfileAtIndex(i) == icon_index) |
| @@ -410,8 +599,10 @@ std::string ProfileInfoCache::CacheKeyFromProfilePath( |
| std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile( |
| std::string search_key, |
| const string16& search_name) { |
| + string16 search_name_l = base::i18n::ToLower(search_name); |
| for (size_t i = 0; i < GetNumberOfProfiles(); ++i) { |
| - int name_compare = search_name.compare(GetNameOfProfileAtIndex(i)); |
| + string16 name_l = base::i18n::ToLower(GetNameOfProfileAtIndex(i)); |
| + int name_compare = search_name_l.compare(name_l); |
| if (name_compare < 0) |
| return sorted_keys_.begin() + i; |
| if (name_compare == 0) { |
| @@ -426,3 +617,20 @@ std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile( |
| void ProfileInfoCache::RegisterPrefs(PrefService* prefs) { |
| prefs->RegisterDictionaryPref(prefs::kProfileInfoCache); |
| } |
| + |
| +void ProfileInfoCache::UpdateSortForProfileIndex(size_t index) { |
| + string16 name = GetNameOfProfileAtIndex(index); |
| + |
| + // Remove and reinsert key in |sorted_keys_| to alphasort. |
| + std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index)); |
| + std::vector<std::string>::iterator key_it = |
| + std::find(sorted_keys_.begin(), sorted_keys_.end(), key); |
| + DCHECK(key_it != sorted_keys_.end()); |
| + sorted_keys_.erase(key_it); |
| + sorted_keys_.insert(FindPositionForProfile(key, name), key); |
| + |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
|
Robert Sesek
2011/11/17 20:42:04
nit: indent 4
sail
2011/11/21 23:52:47
Done.
|
| + content::NotificationService::AllSources(), |
| + content::NotificationService::NoDetails()); |
| +} |