summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 20:18:04 +0000
committersail@chromium.org <sail@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 20:18:04 +0000
commitcb114f14b97f51eb35991e98f4483a944ef1c323 (patch)
treef138832b59c0a6459feb02c141cd1ab9a223663c /chrome
parent74e8dc38735eabd488c05f663a5f641c1103d249 (diff)
downloadchromium_src-cb114f14b97f51eb35991e98f4483a944ef1c323.zip
chromium_src-cb114f14b97f51eb35991e98f4483a944ef1c323.tar.gz
chromium_src-cb114f14b97f51eb35991e98f4483a944ef1c323.tar.bz2
Add GAIA info to profile info cache
BUG=91241 TEST= Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=111254 Review URL: http://codereview.chromium.org/8587023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111401 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/profiles/profile_info_cache.cc273
-rw-r--r--chrome/browser/profiles/profile_info_cache.h36
-rw-r--r--chrome/browser/profiles/profile_info_cache_unittest.cc264
-rw-r--r--chrome/browser/profiles/profile_info_interface.h11
-rw-r--r--chrome/common/chrome_notification_types.h4
-rw-r--r--chrome/test/base/testing_profile_manager.cc4
-rw-r--r--chrome/test/base/testing_profile_manager.h4
7 files changed, 567 insertions, 29 deletions
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index c3b20e0..8b71dbb 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"
@@ -17,19 +21,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,
@@ -87,6 +102,59 @@ const int kDefaultNames[] = {
IDS_DEFAULT_AVATAR_NAME_25
};
+typedef std::vector<unsigned char> ImageData;
+
+// Writes |data| to disk and takes ownership of the pointer. On completion
+// |success| is set to true on success and false on failure.
+void SaveBitmap(ImageData* data,
+ FilePath image_path,
+ bool* success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ scoped_ptr<ImageData> data_owner(data);
+ *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;
+ }
+
+ if (file_util::WriteFile(image_path,
+ reinterpret_cast<char*>(&(*data)[0]),
+ data->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,
@@ -108,6 +176,8 @@ ProfileInfoCache::ProfileInfoCache(PrefService* prefs,
}
ProfileInfoCache::~ProfileInfoCache() {
+ STLDeleteContainerPairSecondPointers(
+ gaia_pictures_.begin(), gaia_pictures_.end());
}
void ProfileInfoCache::AddProfileToCache(const FilePath& profile_path,
@@ -186,19 +256,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 {
@@ -209,6 +276,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);
@@ -222,6 +292,76 @@ 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);
+ delete gaia_pictures_[key];
+ gaia_pictures_[key] = *image;
+ }
+ delete image;
+
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
+ content::NotificationService::AllSources(),
+ content::NotificationService::NoDetails());
+}
+
+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;
@@ -236,40 +376,28 @@ 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());
string16 old_name;
info->GetString(kNameKey, &old_name);
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);
+ UpdateSortForProfileIndex(index);
FOR_EACH_OBSERVER(ProfileInfoCacheObserver,
observer_list_,
OnProfileNameChanged(old_name, name));
-
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
- content::NotificationService::AllSources(),
- content::NotificationService::NoDetails());
}
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());
@@ -294,6 +422,64 @@ 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);
+
+ scoped_ptr<ImageData> data(new ImageData);
+ if (!gfx::PNGEncodedDataFromImage(image, data.get())) {
+ LOG(ERROR) << "Failed to PNG encode the image.";
+ } else {
+ FilePath image_path = path.AppendASCII(kGAIAPictureFileName);
+ bool* success = new bool;
+ BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&SaveBitmap, data.release(), image_path, success),
+ base::Bind(&ProfileInfoCache::OnGAIAPictureSaved, AsWeakPtr(),
+ path, 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) {
@@ -320,6 +506,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)
@@ -438,8 +640,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) {
@@ -451,6 +655,23 @@ std::vector<std::string>::iterator ProfileInfoCache::FindPositionForProfile(
return sorted_keys_.end();
}
+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());
+}
+
// static
std::vector<string16> ProfileInfoCache::GetProfileNames() {
std::vector<string16> names;
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h
index 63e08ff..9687910 100644
--- a/chrome/browser/profiles/profile_info_cache.h
+++ b/chrome/browser/profiles/profile_info_cache.h
@@ -6,12 +6,14 @@
#define CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_H_
#pragma once
+#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/string16.h"
#include "chrome/browser/profiles/profile_info_cache_observer.h"
@@ -30,7 +32,8 @@ class PrefService;
// This class saves various information about profiles to local preferences.
// This cache can be used to display a list of profiles without having to
// actually load the profiles from disk.
-class ProfileInfoCache : public ProfileInfoInterface {
+class ProfileInfoCache : public ProfileInfoInterface,
+ public base::SupportsWeakPtr<ProfileInfoCache> {
public:
ProfileInfoCache(PrefService* prefs, const FilePath& user_data_dir);
virtual ~ProfileInfoCache();
@@ -54,6 +57,12 @@ class ProfileInfoCache : public ProfileInfoInterface {
size_t index) const OVERRIDE;
virtual bool GetBackgroundStatusOfProfileAtIndex(
size_t index) const OVERRIDE;
+ virtual string16 GetGAIANameOfProfileAtIndex(size_t index) const OVERRIDE;
+ virtual bool IsUsingGAIANameOfProfileAtIndex(size_t index) const OVERRIDE;
+ virtual const gfx::Image& GetGAIAPictureOfProfileAtIndex(
+ size_t index) const OVERRIDE;
+ virtual bool IsUsingGAIAPictureOfProfileAtIndex(
+ size_t index) const OVERRIDE;
size_t GetAvatarIconIndexOfProfileAtIndex(size_t index) const;
@@ -62,10 +71,24 @@ class ProfileInfoCache : public ProfileInfoInterface {
void SetAvatarIconOfProfileAtIndex(size_t index, size_t icon_index);
void SetBackgroundStatusOfProfileAtIndex(size_t index,
bool running_background_apps);
+ void SetGAIANameOfProfileAtIndex(size_t index, const string16& name);
+ void SetIsUsingGAIANameOfProfileAtIndex(size_t index, bool value);
+ void SetGAIAPictureOfProfileAtIndex(size_t index, const gfx::Image& image);
+ void SetIsUsingGAIAPictureOfProfileAtIndex(size_t index, bool value);
// Returns unique name that can be assigned to a newly created profile.
string16 ChooseNameForNewProfile(size_t icon_index);
+ // Checks if the given profile has switched to using GAIA information
+ // for the profile name and picture. This pref is used to switch over
+ // to GAIA info the first time it is available. Afterwards this pref is
+ // checked to prevent clobbering the user's custom settings.
+ bool GetHasMigratedToGAIAInfoOfProfileAtIndex(size_t index) const;
+
+ // Marks the given profile as having switched to using GAIA information
+ // for the profile name and picture.
+ void SetHasMigratedToGAIAInfoOfProfileAtIndex(size_t index, bool value);
+
// Returns an avatar icon index that can be assigned to a newly created
// profile. Note that the icon may not be unique since there are a limited
// set of default icons.
@@ -116,12 +139,23 @@ class ProfileInfoCache : public ProfileInfoInterface {
bool must_be_unique,
size_t* out_icon_index) const;
+ // Updates the position of the profile at the given index so that the list
+ // of profiles is still sorted.
+ void UpdateSortForProfileIndex(size_t index);
+
+ void OnGAIAPictureLoaded(FilePath path, gfx::Image** image) const;
+ void OnGAIAPictureSaved(FilePath path, bool* success) const;
+
PrefService* prefs_;
std::vector<std::string> sorted_keys_;
FilePath user_data_dir_;
ObserverList<ProfileInfoCacheObserver> observer_list_;
+ // A cache of gaia profile pictures. This cache is updated lazily so it needs
+ // to be mutable.
+ mutable std::map<std::string, gfx::Image*> gaia_pictures_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileInfoCache);
};
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc
index be03de0..b6227e0 100644
--- a/chrome/browser/profiles/profile_info_cache_unittest.cc
+++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -8,25 +8,78 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_pref_service.h"
#include "chrome/test/base/testing_profile_manager.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
+using content::BrowserThread;
+
namespace {
+bool IsEqual(const gfx::Image& image1,
+ const gfx::Image& image2) {
+ const SkBitmap& bmp1 = *image1.ToSkBitmap();
+ const SkBitmap& bmp2 = *image2.ToSkBitmap();
+
+ if (bmp1.width() != bmp2.width() ||
+ bmp1.height() != bmp2.height() ||
+ bmp1.config() != SkBitmap::kARGB_8888_Config ||
+ bmp2.config() != SkBitmap::kARGB_8888_Config) {
+ return false;
+ }
+
+ SkAutoLockPixels lock1(bmp1);
+ SkAutoLockPixels lock2(bmp2);
+ if (!bmp1.getPixels() || !bmp2.getPixels())
+ return false;
+
+ for (int y = 0; y < bmp1.height(); ++y) {
+ for (int x = 0; x < bmp1.width(); ++x) {
+ if (*bmp1.getAddr32(x,y) != *bmp2.getAddr32(x,y))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+gfx::Image CreateTestImage() {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 50);
+ bitmap.allocPixels();
+ bitmap.eraseRGB(0xff, 0, 0);
+ return gfx::Image(new SkBitmap(bitmap));
+}
+
class ProfileInfoCacheUnittests : public testing::Test {
protected:
ProfileInfoCacheUnittests()
: testing_profile_manager_(
- static_cast<TestingBrowserProcess*>(g_browser_process)) {
+ static_cast<TestingBrowserProcess*>(g_browser_process)),
+ ui_thread_(BrowserThread::UI, &ui_loop_),
+ file_thread_(BrowserThread::FILE) {
}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(testing_profile_manager_.SetUp());
+ file_thread_.Start();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ // Process all tasks on the FILE thread.
+ file_thread_.Stop();
+ // The FILE thread might post tasks back to the UI thread so drain the UI
+ // thread too.
+ ui_loop_.RunAllPending();
}
ProfileInfoCache* GetCache() {
@@ -45,8 +98,15 @@ class ProfileInfoCacheUnittests : public testing::Test {
#endif
}
+ void ResetCache() {
+ testing_profile_manager_.DeleteProfileInfoCache();
+ }
+
private:
+ MessageLoopForUI ui_loop_;
TestingProfileManager testing_profile_manager_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread file_thread_;
};
TEST_F(ProfileInfoCacheUnittests, AddProfiles) {
@@ -60,7 +120,10 @@ TEST_F(ProfileInfoCacheUnittests, AddProfiles) {
const SkBitmap& icon = ResourceBundle::GetSharedInstance().GetImageNamed(
ProfileInfoCache::GetDefaultAvatarIconResourceIDAtIndex(i));
- GetCache()->AddProfileToCache(profile_path, profile_name, string16(), 0);
+ GetCache()->AddProfileToCache(profile_path, profile_name, string16(), i);
+ GetCache()->SetBackgroundStatusOfProfileAtIndex(i, true);
+ string16 gaia_name = ASCIIToUTF16(StringPrintf("gaia_%ud", i));
+ GetCache()->SetGAIANameOfProfileAtIndex(i, gaia_name);
EXPECT_EQ(i + 1, GetCache()->GetNumberOfProfiles());
EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(i));
@@ -69,6 +132,23 @@ TEST_F(ProfileInfoCacheUnittests, AddProfiles) {
EXPECT_EQ(icon.width(), actual_icon.width());
EXPECT_EQ(icon.height(), actual_icon.height());
}
+
+ // Reset the cache and test the it reloads correctly.
+ ResetCache();
+
+ EXPECT_EQ(4u, GetCache()->GetNumberOfProfiles());
+ for (uint32 i = 0; i < 4; ++i) {
+ std::string base_name = StringPrintf("path_%ud", i);
+ FilePath profile_path =
+ GetUserDataDir().Append(StringToFilePath(base_name));
+ EXPECT_EQ(i, GetCache()->GetIndexOfProfileWithPath(profile_path));
+ string16 profile_name = ASCIIToUTF16(StringPrintf("name_%ud", i));
+ EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(i));
+ EXPECT_EQ(i, GetCache()->GetAvatarIconIndexOfProfileAtIndex(i));
+ EXPECT_EQ(true, GetCache()->GetBackgroundStatusOfProfileAtIndex(i));
+ string16 gaia_name = ASCIIToUTF16(StringPrintf("gaia_%ud", i));
+ EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(i));
+ }
}
TEST_F(ProfileInfoCacheUnittests, DeleteProfile) {
@@ -114,6 +194,47 @@ TEST_F(ProfileInfoCacheUnittests, MutateProfile) {
GetCache()->GetAvatarIconOfProfileAtIndex(1);
}
+TEST_F(ProfileInfoCacheUnittests, Sort) {
+ string16 name_a = ASCIIToUTF16("apple");
+ GetCache()->AddProfileToCache(GetUserDataDir().Append(
+ StringToFilePath("path_a")), name_a, string16(), 0);
+
+ string16 name_c = ASCIIToUTF16("cat");
+ GetCache()->AddProfileToCache(GetUserDataDir().Append(
+ StringToFilePath("path_c")), name_c, string16(), 0);
+
+ // Sanity check the initial order.
+ EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(0));
+ EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(1));
+
+ // Add a new profile (start with a capital to test case insensitive sorting.
+ string16 name_b = ASCIIToUTF16("Banana");
+ GetCache()->AddProfileToCache(GetUserDataDir().Append(
+ StringToFilePath("path_b")), name_b, string16(), 0);
+
+ // Verify the new order.
+ EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(0));
+ EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(1));
+ EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(2));
+
+ // Change the name of an existing profile.
+ name_a = UTF8ToUTF16("dog");
+ GetCache()->SetNameOfProfileAtIndex(0, name_a);
+
+ // Verify the new order.
+ EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(0));
+ EXPECT_EQ(name_c, GetCache()->GetNameOfProfileAtIndex(1));
+ EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(2));
+
+ // Delete a profile.
+ GetCache()->DeleteProfileFromCache(GetUserDataDir().Append(
+ StringToFilePath("path_c")));
+
+ // Verify the new order.
+ EXPECT_EQ(name_b, GetCache()->GetNameOfProfileAtIndex(0));
+ EXPECT_EQ(name_a, GetCache()->GetNameOfProfileAtIndex(1));
+}
+
TEST_F(ProfileInfoCacheUnittests, BackgroundModeStatus) {
GetCache()->AddProfileToCache(
GetUserDataDir().Append(StringToFilePath("path_1")),
@@ -141,4 +262,143 @@ TEST_F(ProfileInfoCacheUnittests, BackgroundModeStatus) {
EXPECT_FALSE(GetCache()->GetBackgroundStatusOfProfileAtIndex(1));
}
+TEST_F(ProfileInfoCacheUnittests, HasMigrated) {
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_1")),
+ ASCIIToUTF16("name_1"), string16(), 0);
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_2")),
+ ASCIIToUTF16("name_2"), string16(), 0);
+
+ // Sanity check.
+ EXPECT_FALSE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(0));
+ EXPECT_FALSE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(1));
+
+ // Set migrated state for 2nd profile.
+ GetCache()->SetHasMigratedToGAIAInfoOfProfileAtIndex(1, true);
+ EXPECT_FALSE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(0));
+ EXPECT_TRUE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(1));
+
+ // Set migrated state for 1st profile.
+ GetCache()->SetHasMigratedToGAIAInfoOfProfileAtIndex(0, true);
+ EXPECT_TRUE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(0));
+ EXPECT_TRUE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(1));
+
+ // Unset migrated state for 2nd profile.
+ GetCache()->SetHasMigratedToGAIAInfoOfProfileAtIndex(1, false);
+ EXPECT_TRUE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(0));
+ EXPECT_FALSE(GetCache()->GetHasMigratedToGAIAInfoOfProfileAtIndex(1));
+}
+
+TEST_F(ProfileInfoCacheUnittests, GAIAName) {
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_1")),
+ ASCIIToUTF16("name_1"), string16(), 0);
+ string16 profile_name(ASCIIToUTF16("profile name 2"));
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_2")),
+ profile_name, string16(), 0);
+
+ // Sanity check.
+ EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(0).empty());
+ EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(1).empty());
+ EXPECT_FALSE(GetCache()->IsUsingGAIANameOfProfileAtIndex(0));
+ EXPECT_FALSE(GetCache()->IsUsingGAIANameOfProfileAtIndex(1));
+
+ // Set GAIA name.
+ string16 gaia_name(ASCIIToUTF16("Pat Smith"));
+ GetCache()->SetGAIANameOfProfileAtIndex(1, gaia_name);
+ EXPECT_TRUE(GetCache()->GetGAIANameOfProfileAtIndex(0).empty());
+ EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(1));
+ EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(1));
+
+ // Use GAIA name as profile name.
+ GetCache()->SetIsUsingGAIANameOfProfileAtIndex(1, true);
+
+ EXPECT_EQ(gaia_name, GetCache()->GetNameOfProfileAtIndex(1));
+ EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(1));
+
+ // Don't use GAIA name as profile name.
+ GetCache()->SetIsUsingGAIANameOfProfileAtIndex(1, false);
+ EXPECT_EQ(profile_name, GetCache()->GetNameOfProfileAtIndex(1));
+ EXPECT_EQ(gaia_name, GetCache()->GetGAIANameOfProfileAtIndex(1));
+}
+
+TEST_F(ProfileInfoCacheUnittests, GAIAPicture) {
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_1")),
+ ASCIIToUTF16("name_1"), string16(), 0);
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_2")),
+ ASCIIToUTF16("name_2"), string16(), 0);
+
+ // Sanity check.
+ EXPECT_TRUE(
+ GetCache()->GetGAIAPictureOfProfileAtIndex(0).ToSkBitmap()->isNull());
+ EXPECT_TRUE(
+ GetCache()->GetGAIAPictureOfProfileAtIndex(1).ToSkBitmap()->isNull());
+ EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(0));
+ EXPECT_FALSE(GetCache()->IsUsingGAIAPictureOfProfileAtIndex(1));
+
+ // The profile icon should be the default one.
+ int id = ProfileInfoCache::GetDefaultAvatarIconResourceIDAtIndex(0);
+ const gfx::Image& profile_image(
+ ResourceBundle::GetSharedInstance().GetImageNamed(id));
+ EXPECT_TRUE(IsEqual(
+ profile_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
+
+ // Set GAIA picture.
+ gfx::Image gaia_image(CreateTestImage());
+ GetCache()->SetGAIAPictureOfProfileAtIndex(1, gaia_image);
+ EXPECT_TRUE(
+ GetCache()->GetGAIAPictureOfProfileAtIndex(0).ToSkBitmap()->isNull());
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
+ EXPECT_TRUE(IsEqual(
+ profile_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
+
+ // Use GAIA picture as profile picture.
+ GetCache()->SetIsUsingGAIAPictureOfProfileAtIndex(1, true);
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
+
+ // Don't use GAIA picture as profile picture.
+ GetCache()->SetIsUsingGAIAPictureOfProfileAtIndex(1, false);
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetGAIAPictureOfProfileAtIndex(1)));
+ EXPECT_TRUE(IsEqual(
+ profile_image, GetCache()->GetAvatarIconOfProfileAtIndex(1)));
+}
+
+TEST_F(ProfileInfoCacheUnittests, PersistGAIAPicture) {
+ GetCache()->AddProfileToCache(
+ GetUserDataDir().Append(StringToFilePath("path_1")),
+ ASCIIToUTF16("name_1"), string16(), 0);
+ gfx::Image gaia_image(CreateTestImage());
+
+ ui_test_utils::WindowedNotificationObserver save_observer(
+ chrome::NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
+ content::NotificationService::AllSources());
+ GetCache()->SetGAIAPictureOfProfileAtIndex(0, gaia_image);
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetGAIAPictureOfProfileAtIndex(0)));
+
+ // Wait for the file to be written to disk then reset the cache.
+ save_observer.Wait();
+ ResetCache();
+
+ // Try to get the GAIA picture. This should return NULL until the read from
+ // disk is done.
+ ui_test_utils::WindowedNotificationObserver read_observer(
+ chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
+ content::NotificationService::AllSources());
+ EXPECT_TRUE(
+ GetCache()->GetGAIAPictureOfProfileAtIndex(0).ToSkBitmap()->isNull());
+ read_observer.Wait();
+ EXPECT_TRUE(IsEqual(
+ gaia_image, GetCache()->GetGAIAPictureOfProfileAtIndex(0)));
+}
+
} // namespace
diff --git a/chrome/browser/profiles/profile_info_interface.h b/chrome/browser/profiles/profile_info_interface.h
index 6a08f9a..a7318de 100644
--- a/chrome/browser/profiles/profile_info_interface.h
+++ b/chrome/browser/profiles/profile_info_interface.h
@@ -36,6 +36,17 @@ class ProfileInfoInterface {
virtual bool GetBackgroundStatusOfProfileAtIndex(
size_t index) const = 0;
+ virtual string16 GetGAIANameOfProfileAtIndex(size_t index) const = 0;
+
+ // Checks if the GAIA name should be used as the profile's name.
+ virtual bool IsUsingGAIANameOfProfileAtIndex(size_t index) const = 0;
+
+ virtual const gfx::Image& GetGAIAPictureOfProfileAtIndex(
+ size_t index) const = 0;
+
+ // Checks if the GAIA picture should be used as the profile's avatar icon.
+ virtual bool IsUsingGAIAPictureOfProfileAtIndex(size_t index) const = 0;
+
protected:
virtual ~ProfileInfoInterface() {}
};
diff --git a/chrome/common/chrome_notification_types.h b/chrome/common/chrome_notification_types.h
index e1ad04d..5e96ad8 100644
--- a/chrome/common/chrome_notification_types.h
+++ b/chrome/common/chrome_notification_types.h
@@ -929,6 +929,10 @@ enum NotificationType {
// Sent when the cached profile info has changed.
NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
+ // Sent when the cached profile has finished writing a profile picture to
+ // disk.
+ NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
+
// Sent when the browser enters or exits fullscreen mode.
NOTIFICATION_FULLSCREEN_CHANGED,
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index f8273ee..328617a 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -97,6 +97,10 @@ ProfileInfoCache* TestingProfileManager::profile_info_cache() {
return &profile_manager_->GetProfileInfoCache();
}
+void TestingProfileManager::DeleteProfileInfoCache() {
+ profile_manager_->profile_info_cache_.reset(NULL);
+}
+
void TestingProfileManager::SetUpInternal() {
ASSERT_FALSE(browser_process_->profile_manager())
<< "ProfileManager already exists";
diff --git a/chrome/test/base/testing_profile_manager.h b/chrome/test/base/testing_profile_manager.h
index ae6a0ed..c055f34 100644
--- a/chrome/test/base/testing_profile_manager.h
+++ b/chrome/test/base/testing_profile_manager.h
@@ -52,6 +52,10 @@ class TestingProfileManager {
// Deletes a TestingProfile from the profile subsystem.
void DeleteTestingProfile(const std::string& profile_name);
+ // Deletes the cache instance. This is useful for testing that the cache is
+ // properly persisting data.
+ void DeleteProfileInfoCache();
+
// Helper accessors.
ProfileManager* profile_manager();
ProfileInfoCache* profile_info_cache();