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..c39a6ab8fa2a271e28d7e7c4a11d4f81577e952b 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,30 @@ |
#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/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 Profile Picture.png"; |
const int kDefaultAvatarIconResources[] = { |
IDR_PROFILE_AVATAR_0, |
@@ -86,6 +101,62 @@ const int kDefaultNames[] = { |
IDS_DEFAULT_AVATAR_NAME_25 |
}; |
+// Writes the given bitmap as a PNG to disk. On completion |success| is set to |
+// true on success and false on failure. |
+void SaveBitmap(gfx::Image image, |
+ FilePath image_path, |
+ bool *success) { |
Robert Sesek
2011/11/22 21:26:37
^T[ *]
sail
2011/11/22 21:43:23
Done.
|
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ *success = false; |
+ |
+ // Make sure the destination directory exists. |
+ FilePath dir = image_path.DirName(); |
+ if (!file_util::DirectoryExists(dir) && !file_util::CreateDirectory(dir)) { |
+ LOG(ERROR) << "Failed to create parent directory."; |
+ return; |
+ } |
+ |
+ std::vector<unsigned char> encoded_image; |
+ if (!gfx::PNGEncodedDataFromImage(image, &encoded_image)) { |
+ LOG(ERROR) << "Failed to PNG encode the image."; |
+ 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."; |
+ return; |
+ } |
+ |
+ *success = true; |
+} |
+ |
+// Reads a PNG from disk and decodes it. If the bitmap was successfully read |
+// from disk the then |out_image| will contain the bitmap image, otherwise it |
+// will be NULL. |
+void ReadBitmap(FilePath image_path, |
+ gfx::Image** out_image) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ *out_image = NULL; |
+ |
+ std::string image_data; |
+ if (!file_util::ReadFileToString(image_path, &image_data)) { |
+ LOG(ERROR) << "Failed to read PNG file from disk."; |
+ 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."; |
+ return; |
+ } |
+ |
+ *out_image = image; |
+} |
+ |
} // namespace |
ProfileInfoCache::ProfileInfoCache(PrefService* prefs, |
@@ -107,6 +178,8 @@ ProfileInfoCache::ProfileInfoCache(PrefService* prefs, |
} |
ProfileInfoCache::~ProfileInfoCache() { |
+ STLDeleteContainerPairSecondPointers( |
+ gaia_pictures_.begin(), gaia_pictures_.end()); |
} |
void ProfileInfoCache::AddProfileToCache(const FilePath& profile_path, |
@@ -164,19 +237,16 @@ size_t ProfileInfoCache::GetIndexOfProfileWithPath( |
} |
string16 ProfileInfoCache::GetNameOfProfileAtIndex(size_t index) const { |
+ if (IsUsingGAIANameOfProfileAtIndex(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 +257,9 @@ string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(size_t index) const { |
const gfx::Image& ProfileInfoCache::GetAvatarIconOfProfileAtIndex( |
size_t index) const { |
+ if (IsUsingGAIAPictureOfProfileAtIndex(index)) |
+ return GetGAIAPictureOfProfileAtIndex(index); |
+ |
int resource_id = GetDefaultAvatarIconResourceIDAtIndex( |
GetAvatarIconIndexOfProfileAtIndex(index)); |
return ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); |
@@ -200,6 +273,75 @@ 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::IsUsingGAIANameOfProfileAtIndex(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); |
+ gfx::Image** image = new gfx::Image*; |
+ BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&ReadBitmap, image_path, image), |
+ base::Bind(&ProfileInfoCache::OnGAIAPictureLoaded, |
+ const_cast<ProfileInfoCache*>(this)->AsWeakPtr(), path, image)); |
+ |
+ return *gaia_pictures_[key]; |
+} |
+ |
+void ProfileInfoCache::OnGAIAPictureLoaded(FilePath path, |
+ gfx::Image** image) const { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (*image) { |
+ std::string key = CacheKeyFromProfilePath(path); |
+ gaia_pictures_[key] = *image; |
+ |
+ content::NotificationService::current()->Notify( |
+ chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
+ content::NotificationService::AllSources(), |
+ content::NotificationService::NoDetails()); |
+ } |
+ delete image; |
+} |
+ |
+void ProfileInfoCache::OnGAIAPictureSaved(FilePath path, bool* success) const { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (*success) { |
+ content::NotificationService::current()->Notify( |
+ chrome::NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED, |
+ content::NotificationService::AllSources(), |
+ content::NotificationService::NoDetails()); |
+ } |
+ delete success; |
+} |
+ |
+bool ProfileInfoCache::IsUsingGAIAPictureOfProfileAtIndex( |
+ 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 +356,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 +396,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 == IsUsingGAIANameOfProfileAtIndex(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); |
+ bool* success = new bool; |
+ BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, |
+ base::Bind(&SaveBitmap, image, image_path, success), |
+ base::Bind(&ProfileInfoCache::OnGAIAPictureSaved, AsWeakPtr(), path, |
Robert Sesek
2011/11/22 21:26:37
I'd wrap this by breaking before path and aligning
sail
2011/11/22 21:43:23
Done.
|
+ success)); |
+ |
+ content::NotificationService::current()->Notify( |
+ chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, |
+ 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 +475,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 +609,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 +627,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, |
+ content::NotificationService::AllSources(), |
+ content::NotificationService::NoDetails()); |
+} |