summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-15 15:53:45 +0000
committerivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-15 15:53:45 +0000
commitc4e418facea4f437f1a497f08c5adce76105725b (patch)
tree1f8e0c54dee8c46876286d328566cc06611beb53
parent3acc325be40dff489fa048673a9da41fbf3d425c (diff)
downloadchromium_src-c4e418facea4f437f1a497f08c5adce76105725b.zip
chromium_src-c4e418facea4f437f1a497f08c5adce76105725b.tar.gz
chromium_src-c4e418facea4f437f1a497f08c5adce76105725b.tar.bz2
[cros] Migrate user avatars from PNG to JPG format.
Also: *) Decoupled image handling code from UserManager to UserImageManager (lots of refactoring). *) Force Local State store on user login (and session start, for new users). BUG=145613,154048,154370,154365,154366 Review URL: https://chromiumcodereview.appspot.com/11027064 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161860 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/automation/automation_provider_observers_chromeos.cc9
-rw-r--r--chrome/browser/automation/testing_automation_provider_chromeos.cc10
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser.cc6
-rw-r--r--chrome/browser/chromeos/extensions/wallpaper_private_api.cc4
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc15
-rw-r--r--chrome/browser/chromeos/login/login_utils_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/login/mock_user_image_manager.cc15
-rw-r--r--chrome/browser/chromeos/login/mock_user_image_manager.h34
-rw-r--r--chrome/browser/chromeos/login/mock_user_manager.cc12
-rw-r--r--chrome/browser/chromeos/login/mock_user_manager.h15
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc2
-rw-r--r--chrome/browser/chromeos/login/simple_jpeg_encoder.cc8
-rw-r--r--chrome/browser/chromeos/login/simple_jpeg_encoder.h2
-rw-r--r--chrome/browser/chromeos/login/user.cc7
-rw-r--r--chrome/browser/chromeos/login/user.h17
-rw-r--r--chrome/browser/chromeos/login/user_image.cc53
-rw-r--r--chrome/browser/chromeos/login/user_image.h6
-rw-r--r--chrome/browser/chromeos/login/user_image_loader.cc6
-rw-r--r--chrome/browser/chromeos/login/user_image_manager.cc12
-rw-r--r--chrome/browser/chromeos/login/user_image_manager.h76
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_browsertest.cc262
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_impl.cc722
-rw-r--r--chrome/browser/chromeos/login/user_image_manager_impl.h173
-rw-r--r--chrome/browser/chromeos/login/user_image_screen.cc19
-rw-r--r--chrome/browser/chromeos/login/user_manager.cc29
-rw-r--r--chrome/browser/chromeos/login/user_manager.h68
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.cc762
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.h144
-rw-r--r--chrome/browser/chromeos/login/user_manager_unittest.cc5
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.cc88
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.h7
-rw-r--r--chrome/browser/chromeos/login/webui_screen_locker.cc2
-rw-r--r--chrome/browser/chromeos/power/power_button_observer.cc2
-rw-r--r--chrome/browser/chromeos/system/ash_system_tray_delegate.cc6
-rw-r--r--chrome/browser/chromeos/system/drm_settings.cc6
-rw-r--r--chrome/browser/policy/browser_policy_connector.cc2
-rw-r--r--chrome/browser/policy/user_cloud_policy_store_chromeos.cc2
-rw-r--r--chrome/browser/prefs/browser_prefs.cc2
-rw-r--r--chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc3
-rw-r--r--chrome/browser/ui/webui/feedback_ui.cc2
-rw-r--r--chrome/browser/ui/webui/help/help_handler.cc2
-rw-r--r--chrome/browser/ui/webui/options/browser_options_handler.cc32
-rw-r--r--chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc46
-rw-r--r--chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc2
-rw-r--r--chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.cc2
-rw-r--r--chrome/browser/ui/webui/policy_ui.cc4
-rw-r--r--chrome/browser/ui/webui/web_ui_util.cc4
-rw-r--r--chrome/chrome_browser_chromeos.gypi4
-rw-r--r--chrome/chrome_tests.gypi3
49 files changed, 1671 insertions, 1049 deletions
diff --git a/chrome/browser/automation/automation_provider_observers_chromeos.cc b/chrome/browser/automation/automation_provider_observers_chromeos.cc
index 440091f..fb9c87a 100644
--- a/chrome/browser/automation/automation_provider_observers_chromeos.cc
+++ b/chrome/browser/automation/automation_provider_observers_chromeos.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
@@ -496,8 +497,8 @@ void PhotoCaptureObserver::OnCapturingStopped(
return;
}
- const chromeos::User& user = user_manager->GetLoggedInUser();
- if (user.email().empty()) {
+ const chromeos::User* user = user_manager->GetLoggedInUser();
+ if (user->email().empty()) {
if (automation_) {
AutomationJSONReply(
automation_,
@@ -509,8 +510,8 @@ void PhotoCaptureObserver::OnCapturingStopped(
// Set up an observer for UserManager (it will delete itself).
user_manager->AddObserver(this);
- user_manager->SaveUserImage(
- user.email(), chromeos::UserImage::CreateAndEncode(photo));
+ user_manager->GetUserImageManager()->SaveUserImage(
+ user->email(), chromeos::UserImage::CreateAndEncode(photo));
}
void PhotoCaptureObserver::LocalStateChanged(
diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc
index e1fcd7f..1b8eeca 100644
--- a/chrome/browser/automation/testing_automation_provider_chromeos.cc
+++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc
@@ -313,11 +313,11 @@ void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args,
return_value->SetBoolean("is_logged_in", user_manager->IsUserLoggedIn());
return_value->SetBoolean("is_screen_locked", screen_locker);
if (user_manager->IsUserLoggedIn()) {
- const User& user = user_manager->GetLoggedInUser();
+ const User* user = user_manager->GetLoggedInUser();
return_value->SetBoolean("is_guest", user_manager->IsLoggedInAsGuest());
- return_value->SetString("email", user.email());
- return_value->SetString("display_email", user.display_email());
- switch (user.image_index()) {
+ return_value->SetString("email", user->email());
+ return_value->SetString("display_email", user->display_email());
+ switch (user->image_index()) {
case User::kExternalImageIndex:
return_value->SetString("user_image", "file");
break;
@@ -327,7 +327,7 @@ void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args,
break;
default:
- return_value->SetInteger("user_image", user.image_index());
+ return_value->SetInteger("user_image", user->image_index());
break;
}
}
diff --git a/chrome/browser/chromeos/cros/onc_network_parser.cc b/chrome/browser/chromeos/cros/onc_network_parser.cc
index f0ac5db..213b716 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
@@ -687,13 +687,13 @@ std::string OncNetworkParser::GetUserExpandedValue(
if (!UserManager::Get()->IsUserLoggedIn())
return string_value;
- const User& logged_in_user(UserManager::Get()->GetLoggedInUser());
+ const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
ReplaceSubstringsAfterOffset(&string_value, 0,
onc::substitutes::kLoginIDField,
- logged_in_user.GetAccountName(false));
+ logged_in_user->GetAccountName(false));
ReplaceSubstringsAfterOffset(&string_value, 0,
onc::substitutes::kEmailField,
- logged_in_user.email());
+ logged_in_user->email());
return string_value;
}
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index 7d44c40..0bdb21b 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -152,7 +152,7 @@ bool WallpaperSetWallpaperFunction::RunImpl() {
return false;
// Gets email address while at UI thread.
- email_ = chromeos::UserManager::Get()->GetLoggedInUser().email();
+ email_ = chromeos::UserManager::Get()->GetLoggedInUser()->email();
image_data_.assign(input->GetBuffer(), input->GetSize());
if (wallpaper_decoder_)
@@ -252,7 +252,7 @@ bool WallpaperSetCustomWallpaperFunction::RunImpl() {
layout_ = ash::GetLayoutEnum(layout_string);
// Gets email address while at UI thread.
- email_ = chromeos::UserManager::Get()->GetLoggedInUser().email();
+ email_ = chromeos::UserManager::Get()->GetLoggedInUser()->email();
image_data_.assign(input->GetBuffer(), input->GetSize());
if (wallpaper_decoder_)
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index b177c05..8ee7f43 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -540,7 +540,7 @@ void LoginUtilsImpl::OnProfileCreated(
google_services_username.Init(prefs::kGoogleServicesUsername,
user_profile->GetPrefs(), NULL);
google_services_username.SetValue(
- UserManager::Get()->GetLoggedInUser().display_email());
+ UserManager::Get()->GetLoggedInUser()->display_email());
// Make sure we flip every profile to not share proxies if the user hasn't
// specified so explicitly.
const PrefService::Preference* use_shared_proxies_pref =
@@ -661,7 +661,7 @@ void LoginUtilsImpl::StartSignedInServices(
// Make sure SigninManager is connected to our current user (this should
// happen automatically because we set kGoogleServicesUsername in
// OnProfileCreated()).
- DCHECK_EQ(UserManager::Get()->GetLoggedInUser().display_email(),
+ DCHECK_EQ(UserManager::Get()->GetLoggedInUser()->display_email(),
signin->GetAuthenticatedUsername());
static bool initialized = false;
if (!initialized) {
@@ -1030,7 +1030,7 @@ bool LoginUtilsImpl::ReadOAuth1AccessToken(Profile* user_profile,
std::string* secret) {
// Skip reading oauth token if user does not have a valid status.
if (UserManager::Get()->IsUserLoggedIn() &&
- UserManager::Get()->GetLoggedInUser().oauth_token_status() !=
+ UserManager::Get()->GetLoggedInUser()->oauth_token_status() !=
User::OAUTH_TOKEN_STATUS_VALID) {
return false;
}
@@ -1062,6 +1062,7 @@ void LoginUtilsImpl::StoreOAuth1AccessToken(Profile* user_profile,
std::string encrypted_secret =
CrosLibrary::Get()->GetCertLibrary()->EncryptToken(secret);
PrefService* pref_service = user_profile->GetPrefs();
+ User* user = UserManager::Get()->GetLoggedInUser();
if (!encrypted_token.empty() && !encrypted_secret.empty()) {
pref_service->SetString(prefs::kOAuth1Token, encrypted_token);
pref_service->SetString(prefs::kOAuth1Secret, encrypted_secret);
@@ -1069,15 +1070,13 @@ void LoginUtilsImpl::StoreOAuth1AccessToken(Profile* user_profile,
// ...then record the presence of valid OAuth token for this account in
// local state as well.
UserManager::Get()->SaveUserOAuthStatus(
- UserManager::Get()->GetLoggedInUser().email(),
- User::OAUTH_TOKEN_STATUS_VALID);
+ user->email(), User::OAUTH_TOKEN_STATUS_VALID);
} else {
LOG(WARNING) << "Failed to get OAuth1 token/secret encrypted.";
// Set the OAuth status invalid so that the user will go through full
// GAIA login next time.
UserManager::Get()->SaveUserOAuthStatus(
- UserManager::Get()->GetLoggedInUser().email(),
- User::OAUTH_TOKEN_STATUS_INVALID);
+ user->email(), User::OAUTH_TOKEN_STATUS_INVALID);
}
}
@@ -1096,7 +1095,7 @@ void LoginUtilsImpl::FetchCredentials(Profile* user_profile,
const std::string& secret) {
oauth_login_verifier_.reset(new OAuthLoginVerifier(
this, user_profile, token, secret,
- UserManager::Get()->GetLoggedInUser().email()));
+ UserManager::Get()->GetLoggedInUser()->email()));
oauth_login_verifier_->StartOAuthVerification();
}
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index f7f6ad7..b31daea 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -422,7 +422,7 @@ TEST_F(LoginUtilsTest, NormalLoginDoesntBlock) {
EXPECT_TRUE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
- EXPECT_EQ(kUsername, user_manager->GetLoggedInUser().email());
+ EXPECT_EQ(kUsername, user_manager->GetLoggedInUser()->email());
}
TEST_F(LoginUtilsTest, EnterpriseLoginDoesntBlockForNormalUser) {
@@ -444,7 +444,7 @@ TEST_F(LoginUtilsTest, EnterpriseLoginDoesntBlockForNormalUser) {
EXPECT_TRUE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
- EXPECT_EQ(kUsernameOtherDomain, user_manager->GetLoggedInUser().email());
+ EXPECT_EQ(kUsernameOtherDomain, user_manager->GetLoggedInUser()->email());
}
TEST_F(LoginUtilsTest, OAuth1TokenFetchFailureUnblocksRefreshPolicies) {
@@ -466,7 +466,7 @@ TEST_F(LoginUtilsTest, OAuth1TokenFetchFailureUnblocksRefreshPolicies) {
profile_creation_observer.Wait();
EXPECT_TRUE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
- EXPECT_EQ(kUsername, user_manager->GetLoggedInUser().email());
+ EXPECT_EQ(kUsername, user_manager->GetLoggedInUser()->email());
// 2. Get the pending oauth1 access token fetcher.
net::TestURLFetcher* fetcher =
diff --git a/chrome/browser/chromeos/login/mock_user_image_manager.cc b/chrome/browser/chromeos/login/mock_user_image_manager.cc
new file mode 100644
index 0000000..07482350
--- /dev/null
+++ b/chrome/browser/chromeos/login/mock_user_image_manager.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/mock_user_image_manager.h"
+
+namespace chromeos {
+
+MockUserImageManager::MockUserImageManager() {
+}
+
+MockUserImageManager::~MockUserImageManager() {
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/mock_user_image_manager.h b/chrome/browser/chromeos/login/mock_user_image_manager.h
new file mode 100644
index 0000000..8bcd97b
--- /dev/null
+++ b/chrome/browser/chromeos/login/mock_user_image_manager.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_USER_IMAGE_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_USER_IMAGE_MANAGER_H_
+
+#include <string>
+
+#include "base/file_path.h"
+#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockUserImageManager : public UserImageManager {
+ public:
+ MockUserImageManager();
+ virtual ~MockUserImageManager();
+
+ MOCK_METHOD2(SaveUserDefaultImageIndex, void(const std::string&, int));
+ MOCK_METHOD2(SaveUserImage, void(const std::string&, const UserImage&));
+ MOCK_METHOD2(SaveUserImageFromFile, void(const std::string&,
+ const FilePath&));
+ MOCK_METHOD1(SaveUserImageFromProfileImage, void(const std::string&));
+ MOCK_METHOD1(DownloadProfileImage, void(const std::string&));
+ MOCK_CONST_METHOD0(DownloadedProfileImage, const gfx::ImageSkia& (void));
+
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_USER_IMAGE_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/mock_user_manager.cc b/chrome/browser/chromeos/login/mock_user_manager.cc
index a1655c0..035d8f3 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.cc
+++ b/chrome/browser/chromeos/login/mock_user_manager.cc
@@ -12,12 +12,16 @@ MockUserManager::~MockUserManager() {
delete user_;
}
-const User& MockUserManager::GetLoggedInUser() const {
- return *user_;
+const User* MockUserManager::GetLoggedInUser() const {
+ return user_;
}
-User& MockUserManager::GetLoggedInUser() {
- return *user_;
+User* MockUserManager::GetLoggedInUser() {
+ return user_;
+}
+
+UserImageManager* MockUserManager::GetUserImageManager() {
+ return user_image_manager_.get();
}
// Creates a new User instance.
diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h
index 8bc31b1..147dac1 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/mock_user_manager.h
@@ -9,6 +9,7 @@
#include "base/file_path.h"
#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/login/mock_user_image_manager.h"
#include "chrome/browser/chromeos/login/user_image.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -40,14 +41,8 @@ class MockUserManager : public UserManager {
MOCK_METHOD2(SaveLoggedInUserWallpaperProperties, void(User::WallpaperType,
int));
MOCK_CONST_METHOD1(GetUserDisplayEmail, std::string(const std::string&));
- MOCK_METHOD2(SaveUserDefaultImageIndex, void(const std::string&, int));
- MOCK_METHOD2(SaveUserImage, void(const std::string&, const UserImage&));
MOCK_METHOD1(SetLoggedInUserCustomWallpaperLayout,void(
ash::WallpaperLayout));
- MOCK_METHOD2(SaveUserImageFromFile, void(const std::string&,
- const FilePath&));
- MOCK_METHOD1(SaveUserImageFromProfileImage, void(const std::string&));
- MOCK_METHOD1(DownloadProfileImage, void(const std::string&));
MOCK_CONST_METHOD0(IsCurrentUserOwner, bool(void));
MOCK_CONST_METHOD0(IsCurrentUserNew, bool(void));
MOCK_CONST_METHOD0(IsCurrentUserEphemeral, bool(void));
@@ -60,20 +55,22 @@ class MockUserManager : public UserManager {
MOCK_METHOD1(AddObserver, void(UserManager::Observer*));
MOCK_METHOD1(RemoveObserver, void(UserManager::Observer*));
MOCK_METHOD0(NotifyLocalStateChanged, void(void));
- MOCK_CONST_METHOD0(DownloadedProfileImage, const gfx::ImageSkia& (void));
// You can't mock this function easily because nobody can create User objects
// but the UserManagerImpl and us.
- virtual const User& GetLoggedInUser() const OVERRIDE;
+ virtual const User* GetLoggedInUser() const OVERRIDE;
// You can't mock this function easily because nobody can create User objects
// but the UserManagerImpl and us.
- virtual User& GetLoggedInUser() OVERRIDE;
+ virtual User* GetLoggedInUser() OVERRIDE;
+
+ virtual UserImageManager* GetUserImageManager() OVERRIDE;
// Sets a new User instance.
void SetLoggedInUser(const std::string& email);
User* user_;
+ scoped_ptr<MockUserImageManager> user_image_manager_;
};
// Class that provides easy life-cycle management for mocking the UserManager
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 8a3bf91..f2be07b 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -284,7 +284,7 @@ void ScreenLocker::Show() {
if (!screen_locker_) {
ScreenLocker* locker =
- new ScreenLocker(UserManager::Get()->GetLoggedInUser());
+ new ScreenLocker(*UserManager::Get()->GetLoggedInUser());
VLOG(1) << "Created ScreenLocker " << locker;
locker->Init();
} else {
diff --git a/chrome/browser/chromeos/login/simple_jpeg_encoder.cc b/chrome/browser/chromeos/login/simple_jpeg_encoder.cc
index c24ae46..d9dcc02 100644
--- a/chrome/browser/chromeos/login/simple_jpeg_encoder.cc
+++ b/chrome/browser/chromeos/login/simple_jpeg_encoder.cc
@@ -16,7 +16,7 @@
namespace chromeos {
namespace {
-const int kCustomWallpaperQuality = 90;
+const int kDefaultEncodingQuality = 90;
}
SimpleJpegEncoder::SimpleJpegEncoder(
@@ -29,12 +29,12 @@ SimpleJpegEncoder::SimpleJpegEncoder(
void SimpleJpegEncoder::Run(EncoderCallback callback) {
base::WorkerPool::PostTaskAndReply(
FROM_HERE,
- base::Bind(&SimpleJpegEncoder::EncodeWallpaper, this),
+ base::Bind(&SimpleJpegEncoder::EncodeBitmap, this),
base::Bind(callback, data_),
true /* task_is_slow */);
}
-void SimpleJpegEncoder::EncodeWallpaper() {
+void SimpleJpegEncoder::EncodeBitmap() {
if (cancel_flag_.IsSet())
return;
SkAutoLockPixels lock_input(image_);
@@ -44,7 +44,7 @@ void SimpleJpegEncoder::EncodeWallpaper() {
image_.width(),
image_.height(),
image_.width() * image_.bytesPerPixel(),
- kCustomWallpaperQuality, &data_->data());
+ kDefaultEncodingQuality, &data_->data());
}
void SimpleJpegEncoder::Cancel() {
diff --git a/chrome/browser/chromeos/login/simple_jpeg_encoder.h b/chrome/browser/chromeos/login/simple_jpeg_encoder.h
index 3c932f6..b193525 100644
--- a/chrome/browser/chromeos/login/simple_jpeg_encoder.h
+++ b/chrome/browser/chromeos/login/simple_jpeg_encoder.h
@@ -36,7 +36,7 @@ class SimpleJpegEncoder
~SimpleJpegEncoder();
// Encodes a SkBitmap with JPEG codec on worker pool.
- void EncodeWallpaper();
+ void EncodeBitmap();
base::CancellationFlag cancel_flag_;
diff --git a/chrome/browser/chromeos/login/user.cc b/chrome/browser/chromeos/login/user.cc
index 339dece..8df3ad9 100644
--- a/chrome/browser/chromeos/login/user.cc
+++ b/chrome/browser/chromeos/login/user.cc
@@ -36,7 +36,8 @@ User::User(const std::string& email)
: email_(email),
oauth_token_status_(OAUTH_TOKEN_STATUS_UNKNOWN),
image_index_(kInvalidImageIndex),
- image_is_stub_(false) {
+ image_is_stub_(false),
+ image_is_loading_(false) {
// The email address of a demo user is for internal purposes only,
// never meant for display.
if (!is_demo_user())
@@ -49,6 +50,7 @@ void User::SetImage(const UserImage& user_image, int image_index) {
user_image_ = user_image;
image_index_ = image_index;
image_is_stub_ = false;
+ image_is_loading_ = false;
DCHECK(HasDefaultImage() || user_image.has_raw_image());
}
@@ -56,12 +58,13 @@ void User::SetImageURL(const GURL& image_url) {
user_image_.set_url(image_url);
}
-void User::SetStubImage(int image_index) {
+void User::SetStubImage(int image_index, bool is_loading) {
user_image_ = UserImage(
*ResourceBundle::GetSharedInstance().
GetImageSkiaNamed(IDR_PROFILE_PICTURE_LOADING));
image_index_ = image_index;
image_is_stub_ = true;
+ image_is_loading_ = is_loading;
}
std::string User::GetAccountName(bool use_display_email) const {
diff --git a/chrome/browser/chromeos/login/user.h b/chrome/browser/chromeos/login/user.h
index 63ec6c5..2989c64 100644
--- a/chrome/browser/chromeos/login/user.h
+++ b/chrome/browser/chromeos/login/user.h
@@ -83,6 +83,10 @@ class User {
return user_image_.animated_image();
}
+ // Whether |raw_image| contains data in format that is considered safe to
+ // decode in sensitive environment (on Login screen).
+ bool image_is_safe_format() const { return user_image_.is_safe_format(); }
+
// Returns the URL of user image, if there is any. Currently only the profile
// image has a URL, for other images empty URL is returned.
GURL image_url() const { return user_image_.url(); }
@@ -90,6 +94,9 @@ class User {
// True if user image is a stub (while real image is being loaded from file).
bool image_is_stub() const { return image_is_stub_; }
+ // True if image is being loaded from file.
+ bool image_is_loading() const { return image_is_loading_; }
+
// OAuth token status for this user.
OAuthTokenStatus oauth_token_status() const { return oauth_token_status_; }
@@ -104,6 +111,8 @@ class User {
private:
friend class UserManagerImpl;
+ friend class UserImageManagerImpl;
+ // For testing:
friend class MockUserManager;
friend class UserManagerTest;
@@ -118,7 +127,8 @@ class User {
// Sets a stub image until the next |SetImage| call. |image_index| may be
// one of |kExternalImageIndex| or |kProfileImageIndex|.
- void SetStubImage(int image_index);
+ // If |is_loading| is |true|, that means user image is being loaded from file.
+ void SetStubImage(int image_index, bool is_loading);
// Set thumbnail of user custom wallpaper.
void SetWallpaperThumbnail(const SkBitmap& wallpaper_thumbnail);
@@ -135,6 +145,8 @@ class User {
display_email_ = display_email;
}
+ UserImage& user_image() { return user_image_; }
+
std::string email_;
string16 display_name_;
// The displayed user email, defaults to |email_|.
@@ -149,6 +161,9 @@ class User {
// True if current user image is a stub set by a |SetStubImage| call.
bool image_is_stub_;
+ // True if current user image is being loaded from file.
+ bool image_is_loading_;
+
DISALLOW_COPY_AND_ASSIGN(User);
};
diff --git a/chrome/browser/chromeos/login/user_image.cc b/chrome/browser/chromeos/login/user_image.cc
index fe77a4d..347c1fb 100644
--- a/chrome/browser/chromeos/login/user_image.cc
+++ b/chrome/browser/chromeos/login/user_image.cc
@@ -4,12 +4,18 @@
#include "chrome/browser/chromeos/login/user_image.h"
-#include "ui/gfx/codec/png_codec.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+
+#include "base/debug/trace_event.h"
namespace chromeos {
namespace {
+// Default quality for encoding user images.
+const int kDefaultEncodingQuality = 90;
+
bool IsAnimatedImage(const UserImage::RawImage& data) {
const char kGIFStamp[] = "GIF";
const size_t kGIFStampLength = sizeof(kGIFStamp) - 1;
@@ -21,13 +27,21 @@ bool IsAnimatedImage(const UserImage::RawImage& data) {
return false;
}
-bool EncodeBGRAImageSkia(const gfx::ImageSkia& image,
- bool discard_transparency,
- std::vector<unsigned char>* output) {
- if (image.isNull() || !image.bitmap())
+bool EncodeImageSkia(const gfx::ImageSkia& image,
+ std::vector<unsigned char>* output) {
+ TRACE_EVENT2("oobe", "EncodeImageSkia",
+ "width", image.width(), "height", image.height());
+ if (image.isNull())
return false;
- return gfx::PNGCodec::EncodeBGRASkBitmap(*image.bitmap(),
- discard_transparency, output);
+ const SkBitmap& bitmap = *image.bitmap();
+ SkAutoLockPixels lock_image(bitmap);
+ return gfx::JPEGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
+ gfx::JPEGCodec::FORMAT_SkBitmap,
+ bitmap.width(),
+ bitmap.height(),
+ bitmap.width() * bitmap.bytesPerPixel(),
+ kDefaultEncodingQuality, output);
}
} // namespace
@@ -35,31 +49,40 @@ bool EncodeBGRAImageSkia(const gfx::ImageSkia& image,
// static
UserImage UserImage::CreateAndEncode(const gfx::ImageSkia& image) {
RawImage raw_image;
- return EncodeBGRAImageSkia(image, false, &raw_image) ?
- UserImage(image, raw_image) : UserImage(image);
+ if (EncodeImageSkia(image, &raw_image)) {
+ UserImage result(image, raw_image);
+ result.MarkAsSafe();
+ return result;
+ }
+ return UserImage(image);
}
UserImage::UserImage()
: has_raw_image_(false),
- has_animated_image_(false) {
+ has_animated_image_(false),
+ is_safe_format_(false) {
}
UserImage::UserImage(const gfx::ImageSkia& image)
: image_(image),
has_raw_image_(false),
- has_animated_image_(false) {
+ has_animated_image_(false),
+ is_safe_format_(false) {
}
UserImage::UserImage(const gfx::ImageSkia& image,
const RawImage& raw_image)
: image_(image),
has_raw_image_(false),
- has_animated_image_(false) {
+ has_animated_image_(false),
+ is_safe_format_(false) {
if (IsAnimatedImage(raw_image)) {
has_animated_image_ = true;
animated_image_ = raw_image;
- if (EncodeBGRAImageSkia(image_, false, &raw_image_))
+ if (EncodeImageSkia(image_, &raw_image_)) {
has_raw_image_ = true;
+ MarkAsSafe();
+ }
} else {
has_raw_image_ = true;
raw_image_ = raw_image;
@@ -72,4 +95,8 @@ void UserImage::DiscardRawImage() {
RawImage().swap(raw_image_); // Clear |raw_image_|.
}
+void UserImage::MarkAsSafe() {
+ is_safe_format_ = true;
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image.h b/chrome/browser/chromeos/login/user_image.h
index e91067b..1bae8d8 100644
--- a/chrome/browser/chromeos/login/user_image.h
+++ b/chrome/browser/chromeos/login/user_image.h
@@ -56,6 +56,11 @@ class UserImage {
void set_url(const GURL& url) { url_ = url; }
GURL url() const { return url_; }
+ // Whether |raw_image| contains data in format that is considered safe to
+ // decode in sensitive environment (on Login screen).
+ bool is_safe_format() const { return is_safe_format_; }
+ void MarkAsSafe();
+
private:
gfx::ImageSkia image_;
bool has_raw_image_;
@@ -63,6 +68,7 @@ class UserImage {
bool has_animated_image_;
RawImage animated_image_;
GURL url_;
+ bool is_safe_format_;
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_loader.cc b/chrome/browser/chromeos/login/user_image_loader.cc
index dbd4958..89fae74 100644
--- a/chrome/browser/chromeos/login/user_image_loader.cc
+++ b/chrome/browser/chromeos/login/user_image_loader.cc
@@ -95,10 +95,12 @@ void UserImageLoader::OnImageDecoded(const ImageDecoder* decoder,
}
gfx::ImageSkia final_image_skia(final_image);
final_image_skia.MakeThreadSafe();
+ UserImage user_image(final_image_skia, decoder->get_image_data());
+ if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC)
+ user_image.MarkAsSafe();
target_message_loop_->PostTask(
FROM_HERE,
- base::Bind(image_info.loaded_cb,
- UserImage(final_image_skia, decoder->get_image_data())));
+ base::Bind(image_info.loaded_cb, user_image));
image_info_map_.erase(info_it);
}
diff --git a/chrome/browser/chromeos/login/user_image_manager.cc b/chrome/browser/chromeos/login/user_image_manager.cc
new file mode 100644
index 0000000..84699cc
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/user_image_manager.h"
+
+namespace chromeos {
+
+UserImageManager::~UserImageManager() {
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager.h b/chrome/browser/chromeos/login/user_image_manager.h
new file mode 100644
index 0000000..ac6c1b07
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_H_
+
+#include <string>
+
+#include "chrome/browser/chromeos/login/user.h"
+
+class FilePath;
+class PrefService;
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace chromeos {
+
+class UserImage;
+
+// Base class that provides a mechanism for updating user images.
+class UserImageManager {
+ public:
+ // Registers user image manager preferences.
+ static void RegisterPrefs(PrefService* local_state);
+
+ virtual ~UserImageManager();
+
+ // Loads user image data from Local State.
+ virtual void LoadUserImages(const UserList& users) = 0;
+
+ // Indicates that a user with the given email has just logged in.
+ virtual void UserLoggedIn(const std::string& email, bool user_is_new) = 0;
+
+ // Sets user image to the default image with index |image_index|, sends
+ // LOGIN_USER_IMAGE_CHANGED notification and updates Local State.
+ virtual void SaveUserDefaultImageIndex(const std::string& username,
+ int image_index) = 0;
+
+ // Saves image to file, sends LOGIN_USER_IMAGE_CHANGED notification and
+ // updates Local State.
+ virtual void SaveUserImage(const std::string& username,
+ const UserImage& user_image) = 0;
+
+ // Tries to load user image from disk; if successful, sets it for the user,
+ // sends LOGIN_USER_IMAGE_CHANGED notification and updates Local State.
+ virtual void SaveUserImageFromFile(const std::string& username,
+ const FilePath& path) = 0;
+
+ // Sets profile image as user image for |username|, sends
+ // LOGIN_USER_IMAGE_CHANGED notification and updates Local State. If the user
+ // is not logged-in or the last |DownloadProfileImage| call has failed, a
+ // default grey avatar will be used until the user logs in and profile image
+ // is downloaded successfully.
+ virtual void SaveUserImageFromProfileImage(const std::string& username) = 0;
+
+ // Deletes user image and the corresponding image file.
+ virtual void DeleteUserImage(const std::string& username) = 0;
+
+ // Starts downloading the profile image for the logged-in user.
+ // If user's image index is |kProfileImageIndex|, newly downloaded image
+ // is immediately set as user's current picture.
+ // |reason| is an arbitrary string (used to report UMA histograms with
+ // download times).
+ virtual void DownloadProfileImage(const std::string& reason) = 0;
+
+ // Returns the result of the last successful profile image download, if any.
+ // Otherwise, returns an empty bitmap.
+ virtual const gfx::ImageSkia& DownloadedProfileImage() const = 0;
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
new file mode 100644
index 0000000..0f7b327
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
@@ -0,0 +1,262 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
+#include "chrome/browser/chromeos/login/default_user_images.h"
+#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/layout.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace chromeos {
+
+const char kTestUser1[] = "test-user@example.com";
+const char kTestUser2[] = "test-user2@example.com";
+
+class UserImageManagerTest : public CrosInProcessBrowserTest,
+ public content::NotificationObserver,
+ public UserManager::Observer {
+ protected:
+ UserImageManagerTest() {
+ }
+
+ // CrosInProcessBrowserTest overrides:
+ virtual void SetUpOnMainThread() OVERRIDE {
+ UserManager::Get()->AddObserver(this);
+ user_image_manager_ = UserManager::Get()->GetUserImageManager();
+ local_state_ = g_browser_process->local_state();
+ // No migration delay for testing.
+ UserImageManagerImpl::user_image_migration_delay_ms = 0;
+ }
+
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ command_line->AppendSwitch(switches::kLoginManager);
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
+ }
+
+ // content::NotificationObserver overrides:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE {
+ DCHECK(type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED);
+ registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+ content::NotificationService::AllSources());
+ MessageLoopForUI::current()->Quit();
+ }
+
+ // UserManager::Observer overrides:
+ virtual void LocalStateChanged(UserManager* user_manager) OVERRIDE {
+ MessageLoopForUI::current()->Quit();
+ }
+
+ // Adds given user to Local State, if not there.
+ void AddUser(const std::string& username) {
+ ListPrefUpdate users_pref(local_state_, "LoggedInUsers");
+ users_pref->AppendIfNotPresent(base::Value::CreateStringValue(username));
+ }
+
+ // Logs in |username|.
+ void LogIn(const std::string& username) {
+ UserManager::Get()->UserLoggedIn(username, false);
+ }
+
+ // Subscribes for image change notification.
+ void ExpectImageChange() {
+ registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+ content::NotificationService::AllSources());
+ }
+
+ // Stores old (pre-migration) user image info.
+ void SetOldUserImageInfo(const std::string& username,
+ int image_index,
+ const FilePath& image_path) {
+ AddUser(username);
+ DictionaryPrefUpdate images_pref(local_state_, "UserImages");
+ base::DictionaryValue* image_properties = new base::DictionaryValue();
+ image_properties->Set(
+ "index", base::Value::CreateIntegerValue(image_index));
+ image_properties->Set(
+ "path" , base::Value::CreateStringValue(image_path.value()));
+ images_pref->SetWithoutPathExpansion(username, image_properties);
+ }
+
+ // Verifies user image info in |images_pref| dictionary.
+ void ExpectUserImageInfo(const base::DictionaryValue* images_pref,
+ const std::string& username,
+ int image_index,
+ const FilePath& image_path) {
+ ASSERT_TRUE(images_pref);
+ const base::DictionaryValue* image_properties = NULL;
+ images_pref->GetDictionaryWithoutPathExpansion(username, &image_properties);
+ ASSERT_TRUE(image_properties);
+ int actual_image_index;
+ std::string actual_image_path;
+ ASSERT_TRUE(image_properties->GetInteger("index", &actual_image_index) &&
+ image_properties->GetString("path", &actual_image_path));
+ EXPECT_EQ(image_index, actual_image_index);
+ EXPECT_EQ(image_path.value(), actual_image_path);
+ }
+
+ // Verifies that there is no image info for |username| in dictionary
+ // |images_pref|.
+ void ExpectNoUserImageInfo(const base::DictionaryValue* images_pref,
+ const std::string& username) {
+ ASSERT_TRUE(images_pref);
+ const base::DictionaryValue* image_properties = NULL;
+ images_pref->GetDictionaryWithoutPathExpansion(username, &image_properties);
+ ASSERT_FALSE(image_properties);
+ }
+
+ // Verifies that old user image info matches |image_index| and |image_path|
+ // and that new user image info does not exist.
+ void ExpectOldUserImageInfo(const std::string& username,
+ int image_index,
+ const FilePath& image_path) {
+ ExpectUserImageInfo(local_state_->GetDictionary("UserImages"),
+ username, image_index, image_path);
+ ExpectNoUserImageInfo(local_state_->GetDictionary("user_image_info"),
+ username);
+ }
+
+ // Verifies that new user image info matches |image_index| and |image_path|
+ // and that old user image info does not exist.
+ void ExpectNewUserImageInfo(const std::string& username,
+ int image_index,
+ const FilePath& image_path) {
+ ExpectUserImageInfo(local_state_->GetDictionary("user_image_info"),
+ username, image_index, image_path);
+ ExpectNoUserImageInfo(local_state_->GetDictionary("UserImages"),
+ username);
+ }
+
+ // Sets bitmap |resource_id| as image for |username| and saves it to disk.
+ void SaveUserImagePNG(const std::string& username,
+ int resource_id) {
+ FilePath image_path = GetUserImagePath(username, "png");
+ scoped_refptr<base::RefCountedStaticMemory> image_data(
+ ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
+ resource_id, ui::SCALE_FACTOR_100P));
+ int written = file_util::WriteFile(
+ image_path,
+ reinterpret_cast<const char*>(image_data->front()),
+ image_data->size());
+ EXPECT_EQ(static_cast<int>(image_data->size()), written);
+ SetOldUserImageInfo(username, User::kExternalImageIndex, image_path);
+ }
+
+ // Returns the image path for user |username| with specified |extension|.
+ FilePath GetUserImagePath(const std::string& username,
+ const std::string& extension) {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ return user_data_dir.Append(username).AddExtension(extension);
+ }
+
+ UserImageManager* user_image_manager_;
+ PrefService* local_state_;
+ content::NotificationRegistrar registrar_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UserImageManagerTest);
+};
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_DefaultUserImagePreserved) {
+ // Setup an old default (stock) user image.
+ ScopedMockUserManagerEnabler mock_user_manager;
+ SetOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, DefaultUserImagePreserved) {
+ UserManager::Get()->GetUsers(); // Load users.
+ // Old info preserved.
+ ExpectOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+ LogIn(kTestUser1);
+ // Wait for migration.
+ content::RunMessageLoop();
+ // Image info is migrated now.
+ ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_OtherUsersUnaffected) {
+ // Setup two users with stock images.
+ ScopedMockUserManagerEnabler mock_user_manager;
+ SetOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+ SetOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1, FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, OtherUsersUnaffected) {
+ UserManager::Get()->GetUsers(); // Load users.
+ // Old info preserved.
+ ExpectOldUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+ ExpectOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1, FilePath());
+ LogIn(kTestUser1);
+ // Wait for migration.
+ content::RunMessageLoop();
+ // Image info is migrated for the first user and unaffected for the rest.
+ ExpectNewUserImageInfo(kTestUser1, kFirstDefaultImageIndex, FilePath());
+ ExpectOldUserImageInfo(kTestUser2, kFirstDefaultImageIndex + 1, FilePath());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_PRE_NonJPEGImageFromFile) {
+ // Setup a user with non-JPEG image.
+ ScopedMockUserManagerEnabler mock_user_manager;
+ SaveUserImagePNG(
+ kTestUser1, kDefaultImageResourceIDs[kFirstDefaultImageIndex]);
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, PRE_NonJPEGImageFromFile) {
+ UserManager::Get()->GetUsers(); // Load users.
+ // Old info preserved.
+ ExpectOldUserImageInfo(kTestUser1, User::kExternalImageIndex,
+ GetUserImagePath(kTestUser1, "png"));
+ LogIn(kTestUser1);
+ // Wait for migration.
+ content::RunMessageLoop();
+ // Image info is migrated and the image is converted to JPG.
+ ExpectNewUserImageInfo(kTestUser1, User::kExternalImageIndex,
+ GetUserImagePath(kTestUser1, "jpg"));
+ const User* user = UserManager::Get()->GetLoggedInUser();
+ ASSERT_TRUE(user);
+ EXPECT_FALSE(user->image_is_safe_format());
+ // Check image dimensions.
+ const gfx::ImageSkia& saved_image = GetDefaultImage(kFirstDefaultImageIndex);
+ EXPECT_EQ(saved_image.width(), user->image().width());
+ EXPECT_EQ(saved_image.height(), user->image().height());
+}
+
+IN_PROC_BROWSER_TEST_F(UserImageManagerTest, NonJPEGImageFromFile) {
+ ExpectImageChange();
+ UserManager::Get()->GetUsers(); // Load users.
+ // Wait for image load.
+ content::RunMessageLoop();
+ // Now the migrated image is used.
+ const User* user = UserManager::Get()->FindUser(kTestUser1);
+ ASSERT_TRUE(user);
+ EXPECT_TRUE(user->image_is_safe_format());
+ // Check image dimensions. Images can't be compared since JPEG is lossy.
+ const gfx::ImageSkia& saved_image = GetDefaultImage(kFirstDefaultImageIndex);
+ EXPECT_EQ(saved_image.width(), user->image().width());
+ EXPECT_EQ(saved_image.height(), user->image().height());
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
new file mode 100644
index 0000000..5a7ca978
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.cc
@@ -0,0 +1,722 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/path_service.h"
+#include "base/rand_util.h"
+#include "base/threading/worker_pool.h"
+#include "base/time.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/default_user_images.h"
+#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/profiles/profile_downloader.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/webui/web_ui_util.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/common/url_constants.h"
+#include "ui/gfx/image/image_skia.h"
+
+#include "base/debug/trace_event.h"
+
+using content::BrowserThread;
+
+namespace chromeos {
+
+namespace {
+
+// A dictionary that maps usernames to old user image data with images stored in
+// PNG format. Deprecated.
+// TODO(ivankr): remove this const char after migration is gone.
+const char kUserImages[] = "UserImages";
+
+// A dictionary that maps usernames to user image data with images stored in
+// JPEG format.
+const char kUserImageProperties[] = "user_image_info";
+
+// Names of user image properties.
+const char kImagePathNodeName[] = "path";
+const char kImageIndexNodeName[] = "index";
+const char kImageURLNodeName[] = "url";
+
+// Delay betweeen user login and user image migration.
+const long kUserImageMigrationDelayMs = 50000;
+
+// Delay betweeen user login and attempt to update user's profile data.
+const long kProfileDataDownloadDelayMs = 10000;
+
+// Delay betweeen subsequent profile refresh attempts (24 hrs).
+const long kProfileRefreshIntervalMs = 24L * 3600 * 1000;
+
+const char kSafeImagePathExtension[] = ".jpg";
+
+// Enum for reporting histograms about profile picture download.
+enum ProfileDownloadResult {
+ kDownloadSuccessChanged,
+ kDownloadSuccess,
+ kDownloadFailure,
+ kDownloadDefault,
+ kDownloadCached,
+
+ // Must be the last, convenient count.
+ kDownloadResultsCount
+};
+
+// Time histogram prefix for a cached profile image download.
+const char kProfileDownloadCachedTime[] =
+ "UserImage.ProfileDownloadTime.Cached";
+// Time histogram prefix for the default profile image download.
+const char kProfileDownloadDefaultTime[] =
+ "UserImage.ProfileDownloadTime.Default";
+// Time histogram prefix for a failed profile image download.
+const char kProfileDownloadFailureTime[] =
+ "UserImage.ProfileDownloadTime.Failure";
+// Time histogram prefix for a successful profile image download.
+const char kProfileDownloadSuccessTime[] =
+ "UserImage.ProfileDownloadTime.Success";
+// Time histogram suffix for a profile image download after login.
+const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
+// Time histogram suffix for a scheduled profile image download.
+const char kProfileDownloadReasonScheduled[] = "Scheduled";
+
+// Add a histogram showing the time it takes to download a profile image.
+// Separate histograms are reported for each download |reason| and |result|.
+void AddProfileImageTimeHistogram(ProfileDownloadResult result,
+ const std::string& download_reason,
+ const base::TimeDelta& time_delta) {
+ std::string histogram_name;
+ switch (result) {
+ case kDownloadFailure:
+ histogram_name = kProfileDownloadFailureTime;
+ break;
+ case kDownloadDefault:
+ histogram_name = kProfileDownloadDefaultTime;
+ break;
+ case kDownloadSuccess:
+ histogram_name = kProfileDownloadSuccessTime;
+ break;
+ case kDownloadCached:
+ histogram_name = kProfileDownloadCachedTime;
+ break;
+ default:
+ NOTREACHED();
+ }
+ if (!download_reason.empty()) {
+ histogram_name += ".";
+ histogram_name += download_reason;
+ }
+
+ static const base::TimeDelta min_time = base::TimeDelta::FromMilliseconds(1);
+ static const base::TimeDelta max_time = base::TimeDelta::FromSeconds(50);
+ const size_t bucket_count(50);
+
+ base::Histogram* counter = base::Histogram::FactoryTimeGet(
+ histogram_name, min_time, max_time, bucket_count,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ counter->AddTime(time_delta);
+
+ DVLOG(1) << "Profile image download time: " << time_delta.InSecondsF();
+}
+
+// Deletes image file.
+void DeleteImageFile(const std::string& image_path) {
+ if (image_path.empty())
+ return;
+ FilePath fp(image_path);
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&file_util::Delete),
+ fp, /* recursive= */ false));
+}
+
+// Converts |image_index| to UMA histogram value.
+int ImageIndexToHistogramIndex(int image_index) {
+ switch (image_index) {
+ case User::kExternalImageIndex:
+ // TODO(ivankr): Distinguish this from selected from file.
+ return kHistogramImageFromCamera;
+ case User::kProfileImageIndex:
+ return kHistogramImageFromProfile;
+ default:
+ return image_index;
+ }
+}
+
+} // namespace
+
+// static
+long UserImageManagerImpl::user_image_migration_delay_ms =
+ kUserImageMigrationDelayMs;
+
+// static
+void UserImageManager::RegisterPrefs(PrefService* local_state) {
+ local_state->RegisterDictionaryPref(kUserImages,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserImageProperties,
+ PrefService::UNSYNCABLE_PREF);
+}
+
+UserImageManagerImpl::UserImageManagerImpl()
+ : image_loader_(new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC)),
+ unsafe_image_loader_(new UserImageLoader(ImageDecoder::DEFAULT_CODEC)),
+ last_image_set_async_(false),
+ downloaded_profile_image_data_url_(chrome::kAboutBlankURL),
+ downloading_profile_image_(false),
+ migrate_current_user_on_load_(false) {
+}
+
+UserImageManagerImpl::~UserImageManagerImpl() {
+}
+
+void UserImageManagerImpl::LoadUserImages(const UserList& users) {
+ PrefService* local_state = g_browser_process->local_state();
+ const DictionaryValue* prefs_images_unsafe =
+ local_state->GetDictionary(kUserImages);
+ const DictionaryValue* prefs_images =
+ local_state->GetDictionary(kUserImageProperties);
+ if (!prefs_images && !prefs_images_unsafe)
+ return;
+
+ for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
+ User* user = *it;
+ const base::DictionaryValue* image_properties = NULL;
+ bool needs_migration = false; // |true| if user has image in old format.
+ bool safe_source = false; // |true| if image loaded from safe source.
+
+ if (prefs_images_unsafe) {
+ needs_migration = prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
+ user->email(), &image_properties);
+ }
+ if (prefs_images) {
+ safe_source = prefs_images->GetDictionaryWithoutPathExpansion(
+ user->email(), &image_properties);
+ }
+
+ if (needs_migration)
+ users_to_migrate_.insert(user->email());
+
+ if (!image_properties) {
+ SetInitialUserImage(user->email());
+ } else {
+ int image_index = User::kInvalidImageIndex;
+ image_properties->GetInteger(kImageIndexNodeName, &image_index);
+
+ if (image_index >= 0 && image_index < kDefaultImagesCount) {
+ user->SetImage(UserImage(GetDefaultImage(image_index)),
+ image_index);
+ } else if (image_index == User::kExternalImageIndex ||
+ image_index == User::kProfileImageIndex) {
+ std::string image_path;
+ image_properties->GetString(kImagePathNodeName, &image_path);
+ // Path may be empty for profile images (meaning that the image
+ // hasn't been downloaded for the first time yet, in which case a
+ // download will be scheduled for |kProfileDataDownloadDelayMs|
+ // after user logs in).
+ DCHECK(!image_path.empty() || image_index == User::kProfileImageIndex);
+ std::string image_url;
+ image_properties->GetString(kImageURLNodeName, &image_url);
+ GURL image_gurl(image_url);
+ // Until image has been loaded, use the stub image (gray avatar).
+ user->SetStubImage(image_index, true);
+ user->SetImageURL(image_gurl);
+ if (!image_path.empty()) {
+ // Load user image asynchronously.
+ UserImageLoader* loader =
+ safe_source ? image_loader_.get() : unsafe_image_loader_.get();
+ loader->Start(
+ image_path, 0 /* no resize */,
+ base::Bind(&UserImageManagerImpl::SetUserImage,
+ base::Unretained(this),
+ user->email(), image_index, image_gurl));
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+}
+
+void UserImageManagerImpl::UserLoggedIn(const std::string& email,
+ bool user_is_new) {
+ if (user_is_new) {
+ SetInitialUserImage(email);
+ } else {
+ int image_index = UserManager::Get()->GetLoggedInUser()->image_index();
+ // If current user image is profile image, it needs to be refreshed.
+ bool download_profile_image = image_index == User::kProfileImageIndex;
+ if (download_profile_image)
+ InitDownloadedProfileImage();
+
+ // Download user's profile data (full name and optionally image) to see if
+ // it has changed.
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&UserImageManagerImpl::DownloadProfileData,
+ base::Unretained(this),
+ kProfileDownloadReasonLoggedIn,
+ download_profile_image),
+ base::TimeDelta::FromMilliseconds(kProfileDataDownloadDelayMs));
+
+ UMA_HISTOGRAM_ENUMERATION("UserImage.LoggedIn",
+ ImageIndexToHistogramIndex(image_index),
+ kHistogramImagesCount);
+
+ if (users_to_migrate_.count(email)) {
+ // User needs image format migration.
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&UserImageManagerImpl::MigrateUserImage,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(user_image_migration_delay_ms));
+ }
+ }
+
+ // Set up a repeating timer for refreshing the profile data.
+ profile_download_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromMilliseconds(kProfileRefreshIntervalMs),
+ this, &UserImageManagerImpl::DownloadProfileDataScheduled);
+}
+
+void UserImageManagerImpl::SaveUserDefaultImageIndex(
+ const std::string& username,
+ int image_index) {
+ DCHECK(image_index >= 0 && image_index < kDefaultImagesCount);
+ SetUserImage(username, image_index, GURL(),
+ UserImage(GetDefaultImage(image_index)));
+ SaveImageToLocalState(username, "", image_index, GURL(), false);
+}
+
+void UserImageManagerImpl::SaveUserImage(const std::string& username,
+ const UserImage& user_image) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ SaveUserImageInternal(username, User::kExternalImageIndex,
+ GURL(), user_image);
+}
+
+void UserImageManagerImpl::SaveUserImageFromFile(const std::string& username,
+ const FilePath& path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Always use unsafe image loader because we resize the image when saving
+ // anyway.
+ unsafe_image_loader_->Start(
+ path.value(), login::kMaxUserImageSize,
+ base::Bind(&UserImageManagerImpl::SaveUserImage,
+ base::Unretained(this), username));
+}
+
+void UserImageManagerImpl::SaveUserImageFromProfileImage(
+ const std::string& username) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!downloaded_profile_image_.isNull()) {
+ // Profile image has already been downloaded, so save it to file right now.
+ DCHECK(profile_image_url_.is_valid());
+ SaveUserImageInternal(
+ username,
+ User::kProfileImageIndex, profile_image_url_,
+ UserImage::CreateAndEncode(downloaded_profile_image_));
+ } else {
+ // No profile image - use the stub image (gray avatar).
+ SetUserImage(username, User::kProfileImageIndex, GURL(), UserImage());
+ SaveImageToLocalState(username, "", User::kProfileImageIndex,
+ GURL(), false);
+ }
+}
+
+void UserImageManagerImpl::DeleteUserImage(const std::string& username) {
+ // Delete from the old dictionary, if present.
+ DeleteOldUserImage(username);
+
+ PrefService* prefs = g_browser_process->local_state();
+ DictionaryPrefUpdate prefs_images_update(prefs, kUserImageProperties);
+ const base::DictionaryValue* image_properties;
+ if (prefs_images_update->GetDictionaryWithoutPathExpansion(
+ username, &image_properties)) {
+ std::string image_path;
+ image_properties->GetString(kImageURLNodeName, &image_path);
+ prefs_images_update->RemoveWithoutPathExpansion(username, NULL);
+ DeleteImageFile(image_path);
+ }
+}
+
+void UserImageManagerImpl::DownloadProfileImage(const std::string& reason) {
+ DownloadProfileData(reason, true);
+}
+
+const gfx::ImageSkia& UserImageManagerImpl::DownloadedProfileImage() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return downloaded_profile_image_;
+}
+
+FilePath UserImageManagerImpl::GetImagePathForUser(
+ const std::string& username) {
+ std::string filename = username + kSafeImagePathExtension;
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ return user_data_dir.AppendASCII(filename);
+}
+
+void UserImageManagerImpl::SetInitialUserImage(const std::string& username) {
+ // Choose a random default image.
+ int image_id =
+ base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1);
+ SaveUserDefaultImageIndex(username, image_id);
+}
+
+void UserImageManagerImpl::SetUserImage(const std::string& username,
+ int image_index,
+ const GURL& image_url,
+ const UserImage& user_image) {
+ User* user = const_cast<User*>(UserManager::Get()->FindUser(username));
+ // User may have been removed by now.
+ if (user) {
+ bool image_changed = user->image_index() != User::kInvalidImageIndex;
+ bool is_current_user = user == UserManager::Get()->GetLoggedInUser();
+ if (!user_image.image().isNull())
+ user->SetImage(user_image, image_index);
+ else
+ user->SetStubImage(image_index, false);
+ user->SetImageURL(image_url);
+ // For the logged-in user with a profile picture, initialize
+ // |downloaded_profile_picture_|.
+ if (is_current_user && image_index == User::kProfileImageIndex) {
+ InitDownloadedProfileImage();
+ }
+ if (image_changed) {
+ // Unless this is first-time setting with |SetInitialUserImage|,
+ // send a notification about image change.
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+ content::Source<UserImageManager>(this),
+ content::Details<const User>(user));
+ }
+ if (is_current_user && migrate_current_user_on_load_)
+ MigrateUserImage();
+ }
+}
+
+void UserImageManagerImpl::SaveUserImageInternal(const std::string& username,
+ int image_index,
+ const GURL& image_url,
+ const UserImage& user_image) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ SetUserImage(username, image_index, image_url, user_image);
+
+ // Ignore for ephemeral users.
+ if (UserManager::Get()->IsEphemeralUser(username))
+ return;
+
+ FilePath image_path = GetImagePathForUser(username);
+ DVLOG(1) << "Saving user image to " << image_path.value();
+
+ last_image_set_async_ = true;
+
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&UserImageManagerImpl::SaveImageToFile,
+ base::Unretained(this),
+ username, user_image, image_path, image_index, image_url),
+ /* is_slow= */ false);
+}
+
+void UserImageManagerImpl::SaveImageToFile(const std::string& username,
+ const UserImage& user_image,
+ const FilePath& image_path,
+ int image_index,
+ const GURL& image_url) {
+ if (!SaveBitmapToFile(user_image, image_path))
+ return;
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&UserImageManagerImpl::SaveImageToLocalState,
+ base::Unretained(this),
+ username, image_path.value(), image_index, image_url, true));
+}
+
+void UserImageManagerImpl::SaveImageToLocalState(const std::string& username,
+ const std::string& image_path,
+ int image_index,
+ const GURL& image_url,
+ bool is_async) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Ignore for ephemeral users.
+ if (UserManager::Get()->IsEphemeralUser(username))
+ return;
+
+ // TODO(ivankr): use unique filenames for user images each time
+ // a new image is set so that only the last image update is saved
+ // to Local State and notified.
+ if (is_async && !last_image_set_async_) {
+ DVLOG(1) << "Ignoring saved image because it has changed";
+ return;
+ } else if (!is_async) {
+ // Reset the async image save flag if called directly from the UI thread.
+ last_image_set_async_ = false;
+ }
+
+ PrefService* local_state = g_browser_process->local_state();
+ DictionaryPrefUpdate images_update(local_state, kUserImageProperties);
+ base::DictionaryValue* image_properties = new base::DictionaryValue();
+ image_properties->Set(kImagePathNodeName, new StringValue(image_path));
+ image_properties->Set(kImageIndexNodeName,
+ new base::FundamentalValue(image_index));
+ if (!image_url.is_empty()) {
+ image_properties->Set(kImageURLNodeName,
+ new StringValue(image_url.spec()));
+ } else {
+ image_properties->Remove(kImageURLNodeName, NULL);
+ }
+ images_update->SetWithoutPathExpansion(username, image_properties);
+ DVLOG(1) << "Saving path to user image in Local State.";
+
+ if (users_to_migrate_.count(username)) {
+ DeleteOldUserImage(username);
+ users_to_migrate_.erase(username);
+ }
+
+ UserManager::Get()->NotifyLocalStateChanged();
+}
+
+bool UserImageManagerImpl::SaveBitmapToFile(const UserImage& user_image,
+ const FilePath& image_path) {
+ UserImage safe_image;
+ const UserImage::RawImage* encoded_image = NULL;
+ if (!user_image.is_safe_format()) {
+ safe_image = UserImage::CreateAndEncode(user_image.image());
+ encoded_image = &safe_image.raw_image();
+ UMA_HISTOGRAM_MEMORY_KB("UserImage.RecodedJpegSize", encoded_image->size());
+ } else if (user_image.has_raw_image()) {
+ encoded_image = &user_image.raw_image();
+ } else {
+ NOTREACHED() << "Raw image missing.";
+ return false;
+ }
+
+ if (file_util::WriteFile(image_path,
+ reinterpret_cast<const char*>(&(*encoded_image)[0]),
+ encoded_image->size()) == -1) {
+ LOG(ERROR) << "Failed to save image to file.";
+ return false;
+ }
+ return true;
+}
+
+void UserImageManagerImpl::InitDownloadedProfileImage() {
+ const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
+ DCHECK_EQ(logged_in_user->image_index(), User::kProfileImageIndex);
+ if (downloaded_profile_image_.isNull() && !logged_in_user->image_is_stub()) {
+ VLOG(1) << "Profile image initialized";
+ downloaded_profile_image_ = logged_in_user->image();
+ downloaded_profile_image_data_url_ =
+ web_ui_util::GetImageDataUrl(downloaded_profile_image_);
+ profile_image_url_ = logged_in_user->image_url();
+ }
+}
+
+void UserImageManagerImpl::DownloadProfileData(const std::string& reason,
+ bool download_image) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // For guest login there's no profile image to download.
+ if (UserManager::Get()->IsLoggedInAsGuest())
+ return;
+
+ // Mark profile picture as needed.
+ downloading_profile_image_ |= download_image;
+
+ // Another download is already in progress
+ if (profile_image_downloader_.get())
+ return;
+
+ profile_image_download_reason_ = reason;
+ profile_image_load_start_time_ = base::Time::Now();
+ profile_image_downloader_.reset(new ProfileDownloader(this));
+ profile_image_downloader_->Start();
+}
+
+void UserImageManagerImpl::DownloadProfileDataScheduled() {
+ const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
+ // If current user image is profile image, it needs to be refreshed.
+ bool download_profile_image =
+ logged_in_user->image_index() == User::kProfileImageIndex;
+ DownloadProfileData(kProfileDownloadReasonScheduled, download_profile_image);
+}
+
+// ProfileDownloaderDelegate override.
+bool UserImageManagerImpl::NeedsProfilePicture() const {
+ return downloading_profile_image_;
+}
+
+// ProfileDownloaderDelegate override.
+int UserImageManagerImpl::GetDesiredImageSideLength() const {
+ return GetCurrentUserImageSize();
+}
+
+// ProfileDownloaderDelegate override.
+std::string UserImageManagerImpl::GetCachedPictureURL() const {
+ return profile_image_url_.spec();
+}
+
+Profile* UserImageManagerImpl::GetBrowserProfile() {
+ return ProfileManager::GetDefaultProfile();
+}
+
+void UserImageManagerImpl::OnProfileDownloadSuccess(
+ ProfileDownloader* downloader) {
+ // Make sure that |ProfileDownloader| gets deleted after return.
+ scoped_ptr<ProfileDownloader> profile_image_downloader(
+ profile_image_downloader_.release());
+ DCHECK_EQ(downloader, profile_image_downloader.get());
+
+ UserManager* user_manager = UserManager::Get();
+ const User* user = user_manager->GetLoggedInUser();
+
+ if (!downloader->GetProfileFullName().empty()) {
+ user_manager->SaveUserDisplayName(
+ user->email(), downloader->GetProfileFullName());
+ }
+
+ bool requested_image = downloading_profile_image_;
+ downloading_profile_image_ = false;
+ if (!requested_image)
+ return;
+
+ ProfileDownloadResult result = kDownloadFailure;
+ switch (downloader->GetProfilePictureStatus()) {
+ case ProfileDownloader::PICTURE_SUCCESS:
+ result = kDownloadSuccess;
+ break;
+ case ProfileDownloader::PICTURE_CACHED:
+ result = kDownloadCached;
+ break;
+ case ProfileDownloader::PICTURE_DEFAULT:
+ result = kDownloadDefault;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
+ result, kDownloadResultsCount);
+
+ DCHECK(!profile_image_load_start_time_.is_null());
+ base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
+ AddProfileImageTimeHistogram(result, profile_image_download_reason_, delta);
+
+ if (result == kDownloadDefault) {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
+ content::Source<UserImageManager>(this),
+ content::NotificationService::NoDetails());
+ }
+
+ // Nothing to do if picture is cached or the default avatar.
+ if (result != kDownloadSuccess)
+ return;
+
+ // Check if this image is not the same as already downloaded.
+ gfx::ImageSkia new_image(downloader->GetProfilePicture());
+ std::string new_image_data_url = web_ui_util::GetImageDataUrl(new_image);
+ if (!downloaded_profile_image_data_url_.empty() &&
+ new_image_data_url == downloaded_profile_image_data_url_)
+ return;
+
+ downloaded_profile_image_data_url_ = new_image_data_url;
+ downloaded_profile_image_ = gfx::ImageSkia(downloader->GetProfilePicture());
+ profile_image_url_ = GURL(downloader->GetProfilePictureURL());
+
+ if (user->image_index() == User::kProfileImageIndex) {
+ VLOG(1) << "Updating profile image for logged-in user";
+ UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
+ kDownloadSuccessChanged,
+ kDownloadResultsCount);
+ // This will persist |downloaded_profile_image_| to file.
+ SaveUserImageFromProfileImage(user->email());
+ }
+
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
+ content::Source<UserImageManager>(this),
+ content::Details<const gfx::ImageSkia>(&downloaded_profile_image_));
+}
+
+void UserImageManagerImpl::OnProfileDownloadFailure(
+ ProfileDownloader* downloader) {
+ DCHECK_EQ(downloader, profile_image_downloader_.get());
+ profile_image_downloader_.reset();
+
+ downloading_profile_image_ = false;
+
+ UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
+ kDownloadFailure, kDownloadResultsCount);
+
+ DCHECK(!profile_image_load_start_time_.is_null());
+ base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
+ AddProfileImageTimeHistogram(kDownloadFailure, profile_image_download_reason_,
+ delta);
+
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
+ content::Source<UserImageManager>(this),
+ content::NotificationService::NoDetails());
+}
+
+void UserImageManagerImpl::MigrateUserImage() {
+ User* user = UserManager::Get()->GetLoggedInUser();
+ if (user->image_is_loading()) {
+ LOG(INFO) << "Waiting for user image to load before migration";
+ migrate_current_user_on_load_ = true;
+ return;
+ }
+ migrate_current_user_on_load_ = false;
+ if (user->has_raw_image() && user->image_is_safe_format()) {
+ // Nothing to migrate already, make sure we delete old image.
+ DeleteOldUserImage(user->email());
+ users_to_migrate_.erase(user->email());
+ return;
+ }
+ if (user->HasDefaultImage()) {
+ SaveUserDefaultImageIndex(user->email(), user->image_index());
+ } else {
+ SaveUserImageInternal(user->email(), user->image_index(),
+ user->image_url(), user->user_image());
+ }
+ UMA_HISTOGRAM_ENUMERATION("UserImage.Migration",
+ ImageIndexToHistogramIndex(user->image_index()),
+ kHistogramImagesCount);
+}
+
+void UserImageManagerImpl::DeleteOldUserImage(const std::string& username) {
+ PrefService* prefs = g_browser_process->local_state();
+ DictionaryPrefUpdate prefs_images_update(prefs, kUserImages);
+ const base::DictionaryValue* image_properties;
+ if (prefs_images_update->GetDictionaryWithoutPathExpansion(
+ username, &image_properties)) {
+ std::string image_path;
+ image_properties->GetString(kImagePathNodeName, &image_path);
+ prefs_images_update->RemoveWithoutPathExpansion(username, NULL);
+ DeleteImageFile(image_path);
+ }
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.h b/chrome/browser/chromeos/login/user_image_manager_impl.h
new file mode 100644
index 0000000..648139a
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_IMPL_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_image_loader.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
+#include "chrome/browser/profiles/profile_downloader_delegate.h"
+#include "ui/gfx/image/image_skia.h"
+
+class ProfileDownloader;
+class UserImage;
+
+namespace chromeos {
+
+class UserImageManagerImpl : public UserImageManager,
+ public ProfileDownloaderDelegate {
+ public:
+ UserImageManagerImpl();
+
+ // UserImageManager implemenation:
+ virtual ~UserImageManagerImpl();
+ virtual void LoadUserImages(const UserList& users) OVERRIDE;
+ virtual void UserLoggedIn(const std::string& email,
+ bool user_is_new) OVERRIDE;
+ virtual void SaveUserDefaultImageIndex(const std::string& username,
+ int image_index) OVERRIDE;
+ virtual void SaveUserImage(const std::string& username,
+ const UserImage& user_image) OVERRIDE;
+ virtual void SaveUserImageFromFile(const std::string& username,
+ const FilePath& path) OVERRIDE;
+ virtual void SaveUserImageFromProfileImage(
+ const std::string& username) OVERRIDE;
+ virtual void DeleteUserImage(const std::string& username) OVERRIDE;
+ virtual void DownloadProfileImage(const std::string& reason) OVERRIDE;
+ virtual const gfx::ImageSkia& DownloadedProfileImage() const OVERRIDE;
+
+ private:
+ friend class UserImageManagerTest;
+
+ // Non-const for testing purposes.
+ static long user_image_migration_delay_ms;
+
+ // ProfileDownloaderDelegate implementation:
+ virtual bool NeedsProfilePicture() const OVERRIDE;
+ virtual int GetDesiredImageSideLength() const OVERRIDE;
+ virtual Profile* GetBrowserProfile() OVERRIDE;
+ virtual std::string GetCachedPictureURL() const OVERRIDE;
+ virtual void OnProfileDownloadSuccess(ProfileDownloader* downloader) OVERRIDE;
+ virtual void OnProfileDownloadFailure(ProfileDownloader* downloader) OVERRIDE;
+
+ // Returns image filepath for the given user.
+ FilePath GetImagePathForUser(const std::string& username);
+
+ // Sets one of the default images for the specified user and saves this
+ // setting in local state.
+ // Does not send LOGIN_USER_IMAGE_CHANGED notification.
+ void SetInitialUserImage(const std::string& username);
+
+ // Sets image for user |username| and sends LOGIN_USER_IMAGE_CHANGED
+ // notification unless this is a new user and image is set for the first time.
+ // If |image| is empty, sets a stub image for the user.
+ void SetUserImage(const std::string& username,
+ int image_index,
+ const GURL& image_url,
+ const UserImage& user_image);
+
+ // Saves image to file, updates local state preferences to given image index
+ // and sends LOGIN_USER_IMAGE_CHANGED notification.
+ void SaveUserImageInternal(const std::string& username,
+ int image_index,
+ const GURL& image_url,
+ const UserImage& user_image);
+
+ // Saves image to file with specified path and sends LOGIN_USER_IMAGE_CHANGED
+ // notification. Runs on FILE thread. Posts task for saving image info to
+ // Local State on UI thread.
+ void SaveImageToFile(const std::string& username,
+ const UserImage& user_image,
+ const FilePath& image_path,
+ int image_index,
+ const GURL& image_url);
+
+ // Stores path to the image and its index in local state. Runs on UI thread.
+ // If |is_async| is true, it has been posted from the FILE thread after
+ // saving the image.
+ void SaveImageToLocalState(const std::string& username,
+ const std::string& image_path,
+ int image_index,
+ const GURL& image_url,
+ bool is_async);
+
+ // Saves |image| to the specified |image_path|. Runs on FILE thread.
+ bool SaveBitmapToFile(const UserImage& user_image,
+ const FilePath& image_path);
+
+ // Initializes |downloaded_profile_image_| with the picture of the logged-in
+ // user.
+ void InitDownloadedProfileImage();
+
+ // Download user's profile data, including full name and picture, when
+ // |download_image| is true.
+ // |reason| is an arbitrary string (used to report UMA histograms with
+ // download times).
+ void DownloadProfileData(const std::string& reason, bool download_image);
+
+ // Scheduled call for downloading profile data.
+ void DownloadProfileDataScheduled();
+
+ // Migrates image info for the current user and deletes the old image, if any.
+ void MigrateUserImage();
+
+ // Deletes old user image and dictionary entry.
+ void DeleteOldUserImage(const std::string& username);
+
+ // Loader for JPEG user images.
+ scoped_refptr<UserImageLoader> image_loader_;
+
+ // Unsafe loader instance for all user images formats.
+ scoped_refptr<UserImageLoader> unsafe_image_loader_;
+
+ // Download user profile image on login to update it if it's changed.
+ scoped_ptr<ProfileDownloader> profile_image_downloader_;
+
+ // Arbitrary string passed to the last |DownloadProfileImage| call.
+ std::string profile_image_download_reason_;
+
+ // Time when the profile image download has started.
+ base::Time profile_image_load_start_time_;
+
+ // True if the last user image required async save operation (which may not
+ // have been completed yet). This flag is used to avoid races when user image
+ // is first set with |SaveUserImage| and then with |SaveUserImagePath|.
+ bool last_image_set_async_;
+
+ // Result of the last successful profile image download, if any.
+ gfx::ImageSkia downloaded_profile_image_;
+
+ // Data URL for |downloaded_profile_image_|.
+ std::string downloaded_profile_image_data_url_;
+
+ // Original URL of |downloaded_profile_image_|, from which it was downloaded.
+ GURL profile_image_url_;
+
+ // True when |profile_image_downloader_| is fetching profile picture (not
+ // just full name).
+ bool downloading_profile_image_;
+
+ // Timer triggering DownloadProfileDataScheduled for refreshing profile data.
+ base::RepeatingTimer<UserImageManagerImpl> profile_download_timer_;
+
+ // Users that need image migration to JPEG.
+ std::set<std::string> users_to_migrate_;
+
+ // If |true|, current user image should be migrated right after it is loaded.
+ bool migrate_current_user_on_load_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserImageManagerImpl);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_MANAGER_IMPL_H_
diff --git a/chrome/browser/chromeos/login/user_image_screen.cc b/chrome/browser/chromeos/login/user_image_screen.cc
index a942789..034c7bc 100644
--- a/chrome/browser/chromeos/login/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/user_image_screen.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/common/chrome_notification_types.h"
@@ -68,10 +69,11 @@ void UserImageScreen::Show() {
return;
actor_->Show();
- actor_->SelectImage(UserManager::Get()->GetLoggedInUser().image_index());
+ actor_->SelectImage(UserManager::Get()->GetLoggedInUser()->image_index());
// Start fetching the profile image.
- UserManager::Get()->DownloadProfileImage(kProfileDownloadReason);
+ UserManager::Get()->GetUserImageManager()->
+ DownloadProfileImage(kProfileDownloadReason);
accessibility::MaybeSpeak(
l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT));
@@ -118,8 +120,9 @@ void UserImageScreen::OnPhotoTaken(const gfx::ImageSkia& image) {
UserManager* user_manager = UserManager::Get();
// TODO(ivankr): once old camera UI is gone, there's raw data in image
// decoder, pass UserImage and user it instead.
- user_manager->SaveUserImage(user_manager->GetLoggedInUser().email(),
- UserImage::CreateAndEncode(image));
+ user_manager->GetUserImageManager()->SaveUserImage(
+ user_manager->GetLoggedInUser()->email(),
+ UserImage::CreateAndEncode(image));
get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
@@ -130,8 +133,8 @@ void UserImageScreen::OnPhotoTaken(const gfx::ImageSkia& image) {
void UserImageScreen::OnProfileImageSelected() {
UserManager* user_manager = UserManager::Get();
- user_manager->SaveUserImageFromProfileImage(
- user_manager->GetLoggedInUser().email());
+ user_manager->GetUserImageManager()->SaveUserImageFromProfileImage(
+ user_manager->GetLoggedInUser()->email());
get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
@@ -142,8 +145,8 @@ void UserImageScreen::OnProfileImageSelected() {
void UserImageScreen::OnDefaultImageSelected(int index) {
UserManager* user_manager = UserManager::Get();
- user_manager->SaveUserDefaultImageIndex(
- user_manager->GetLoggedInUser().email(), index);
+ user_manager->GetUserImageManager()->SaveUserDefaultImageIndex(
+ user_manager->GetLoggedInUser()->email(), index);
get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc
index 46e030d..4cc4474 100644
--- a/chrome/browser/chromeos/login/user_manager.cc
+++ b/chrome/browser/chromeos/login/user_manager.cc
@@ -4,23 +4,13 @@
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "base/synchronization/lock.h"
#include "chrome/browser/chromeos/login/user_manager_impl.h"
-#include "chrome/browser/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
namespace chromeos {
// static
-const char UserManager::kLoggedInUsers[] = "LoggedInUsers";
const char UserManager::kStubUser[] = "stub-user@example.com";
-const char UserManager::kUserWallpapers[] = "UserWallpapers";
-const char UserManager::kUserWallpapersProperties[] =
- "UserWallpapersProperties";
-const char UserManager::kUserImages[] = "UserImages";
-const char UserManager::kUserDisplayName[] = "UserDisplayName";
-const char UserManager::kUserDisplayEmail[] = "UserDisplayEmail";
-const char UserManager::kUserOAuthTokenStatus[] = "OAuthTokenStatus";
// Class that is holds pointer to UserManager instance.
// One could set UserManager mock instance through it (see UserManager::Set).
@@ -35,7 +25,6 @@ class UserManagerImplWrapper {
}
UserManager* get() {
- base::AutoLock create(create_lock_);
if (!ptr_.get())
reset(new UserManagerImpl);
return ptr_.get();
@@ -57,7 +46,6 @@ class UserManagerImplWrapper {
UserManagerImplWrapper() {
}
- base::Lock create_lock_;
scoped_ptr<UserManager> ptr_;
DISALLOW_COPY_AND_ASSIGN(UserManagerImplWrapper);
@@ -75,23 +63,6 @@ UserManager* UserManager::Set(UserManager* mock) {
return old_manager;
}
-// static
-void UserManager::RegisterPrefs(PrefService* local_state) {
- local_state->RegisterListPref(kLoggedInUsers, PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserWallpapers,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserWallpapersProperties,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserImages,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserOAuthTokenStatus,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserDisplayName,
- PrefService::UNSYNCABLE_PREF);
- local_state->RegisterDictionaryPref(kUserDisplayEmail,
- PrefService::UNSYNCABLE_PREF);
-}
-
UserManager::~UserManager() {
}
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 8396b53..b9e5865 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -12,17 +12,12 @@
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.h"
-class FilePath;
class PrefService;
-namespace gfx {
-class ImageSkia;
-}
-
namespace chromeos {
class RemoveUserDelegate;
-class UserImage;
+class UserImageManager;
// Base class for UserManagerImpl - provides a mechanism for discovering users
// who have logged into this Chrome OS device before and updating that list.
@@ -39,31 +34,9 @@ class UserManager {
virtual ~Observer() {}
};
- // A vector pref of the users who have logged into the device.
- static const char kLoggedInUsers[];
-
// Username for stub login when not running on ChromeOS.
static const char kStubUser[];
- // A dictionary that maps usernames to file paths to their wallpapers.
- // Deprecated. Will remove this const char after done migration.
- static const char kUserWallpapers[];
-
- // A dictionary that maps usernames to wallpaper properties.
- static const char kUserWallpapersProperties[];
-
- // A dictionary that maps usernames to file paths to their images.
- static const char kUserImages[];
-
- // A dictionary that maps usernames to the displayed name.
- static const char kUserDisplayName[];
-
- // A dictionary that maps usernames to the displayed (non-canonical) emails.
- static const char kUserDisplayEmail[];
-
- // A dictionary that maps usernames to OAuth token presence flag.
- static const char kUserOAuthTokenStatus[];
-
// Returns a shared instance of a UserManager. Not thread-safe, should only be
// called from the main UI thread.
static UserManager* Get();
@@ -93,6 +66,8 @@ class UserManager {
virtual ~UserManager();
+ virtual UserImageManager* GetUserImageManager() = 0;
+
// Returns a list of users who have logged into this device previously. This
// is sorted by last login date with the most recent user at the beginning.
virtual const UserList& GetUsers() const = 0;
@@ -138,8 +113,8 @@ class UserManager {
virtual const User* FindUser(const std::string& email) const = 0;
// Returns the logged-in user.
- virtual const User& GetLoggedInUser() const = 0;
- virtual User& GetLoggedInUser() = 0;
+ virtual const User* GetLoggedInUser() const = 0;
+ virtual User* GetLoggedInUser() = 0;
// Saves user's oauth token status in local state preferences.
virtual void SaveUserOAuthStatus(
@@ -172,40 +147,11 @@ class UserManager {
virtual void SaveLoggedInUserWallpaperProperties(User::WallpaperType type,
int index) = 0;
- // Sets user image to the default image with index |image_index|, sends
- // LOGIN_USER_IMAGE_CHANGED notification and updates Local State.
- virtual void SaveUserDefaultImageIndex(const std::string& username,
- int image_index) = 0;
-
- // Saves image to file, sends LOGIN_USER_IMAGE_CHANGED notification and
- // updates Local State.
- virtual void SaveUserImage(const std::string& username,
- const UserImage& user_image) = 0;
-
// Updates custom wallpaper to selected layout and saves layout to Local
// State.
virtual void SetLoggedInUserCustomWallpaperLayout(
ash::WallpaperLayout layout) = 0;
- // Tries to load user image from disk; if successful, sets it for the user,
- // sends LOGIN_USER_IMAGE_CHANGED notification and updates Local State.
- virtual void SaveUserImageFromFile(const std::string& username,
- const FilePath& path) = 0;
-
- // Sets profile image as user image for |username|, sends
- // LOGIN_USER_IMAGE_CHANGED notification and updates Local State. If the user
- // is not logged-in or the last |DownloadProfileImage| call has failed, a
- // default grey avatar will be used until the user logs in and profile image
- // is downloaded successfully.
- virtual void SaveUserImageFromProfileImage(const std::string& username) = 0;
-
- // Starts downloading the profile image for the logged-in user.
- // If user's image index is |kProfileImageIndex|, newly downloaded image
- // is immediately set as user's current picture.
- // |reason| is an arbitrary string (used to report UMA histograms with
- // download times).
- virtual void DownloadProfileImage(const std::string& reason) = 0;
-
// Returns true if current user is an owner.
virtual bool IsCurrentUserOwner() const = 0;
@@ -240,10 +186,6 @@ class UserManager {
virtual void RemoveObserver(Observer* obs) = 0;
virtual void NotifyLocalStateChanged() = 0;
-
- // Returns the result of the last successful profile image download, if any.
- // Otherwise, returns an empty bitmap.
- virtual const gfx::ImageSkia& DownloadedProfileImage() const = 0;
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index 752085f..17ae134 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -4,8 +4,6 @@
#include "chrome/browser/chromeos/login/user_manager_impl.h"
-#include <vector>
-
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/shell.h"
#include "base/bind.h"
@@ -15,133 +13,49 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/path_service.h"
#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/stringprintf.h"
-#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cert_library.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
-#include "chrome/browser/chromeos/login/default_user_images.h"
-#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_display.h"
#include "chrome/browser/chromeos/login/remove_user_delegate.h"
-#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
-#include "chrome/browser/profiles/profile_downloader.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/ui/webui/web_ui_util.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
-#include "content/public/common/url_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/image/image_skia.h"
using content::BrowserThread;
-typedef GoogleServiceAuthError AuthError;
-
namespace chromeos {
namespace {
-// Names of nodes with info about user image.
-const char kImagePathNodeName[] = "path";
-const char kImageIndexNodeName[] = "index";
-const char kImageURLNodeName[] = "url";
-
-// Delay betweeen user login and attempt to update user's profile data.
-const long kProfileDataDownloadDelayMs = 10000;
-
-// Delay betweeen subsequent profile refresh attempts (24 hrs).
-const long kProfileRefreshIntervalMs = 24L * 3600 * 1000;
-
-// Enum for reporting histograms about profile picture download.
-enum ProfileDownloadResult {
- kDownloadSuccessChanged,
- kDownloadSuccess,
- kDownloadFailure,
- kDownloadDefault,
- kDownloadCached,
-
- // Must be the last, convenient count.
- kDownloadResultsCount
-};
-
-// Time histogram prefix for a cached profile image download.
-const char kProfileDownloadCachedTime[] =
- "UserImage.ProfileDownloadTime.Cached";
-// Time histogram prefix for the default profile image download.
-const char kProfileDownloadDefaultTime[] =
- "UserImage.ProfileDownloadTime.Default";
-// Time histogram prefix for a failed profile image download.
-const char kProfileDownloadFailureTime[] =
- "UserImage.ProfileDownloadTime.Failure";
-// Time histogram prefix for a successful profile image download.
-const char kProfileDownloadSuccessTime[] =
- "UserImage.ProfileDownloadTime.Success";
-// Time histogram suffix for a profile image download after login.
-const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
-// Time histogram suffix for a scheduled profile image download.
-const char kProfileDownloadReasonScheduled[] = "Scheduled";
-
-// Add a histogram showing the time it takes to download a profile image.
-// Separate histograms are reported for each download |reason| and |result|.
-void AddProfileImageTimeHistogram(ProfileDownloadResult result,
- const std::string& download_reason,
- const base::TimeDelta& time_delta) {
- std::string histogram_name;
- switch (result) {
- case kDownloadFailure:
- histogram_name = kProfileDownloadFailureTime;
- break;
- case kDownloadDefault:
- histogram_name = kProfileDownloadDefaultTime;
- break;
- case kDownloadSuccess:
- histogram_name = kProfileDownloadSuccessTime;
- break;
- case kDownloadCached:
- histogram_name = kProfileDownloadCachedTime;
- break;
- default:
- NOTREACHED();
- }
- if (!download_reason.empty()) {
- histogram_name += ".";
- histogram_name += download_reason;
- }
+// A vector pref of the users who have logged into the device.
+const char kLoggedInUsers[] = "LoggedInUsers";
- static const base::TimeDelta min_time = base::TimeDelta::FromMilliseconds(1);
- static const base::TimeDelta max_time = base::TimeDelta::FromSeconds(50);
- const size_t bucket_count(50);
+// A dictionary that maps usernames to the displayed name.
+const char kUserDisplayName[] = "UserDisplayName";
- base::Histogram* counter = base::Histogram::FactoryTimeGet(
- histogram_name, min_time, max_time, bucket_count,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter->AddTime(time_delta);
+// A dictionary that maps usernames to the displayed (non-canonical) emails.
+const char kUserDisplayEmail[] = "UserDisplayEmail";
- DVLOG(1) << "Profile image download time: " << time_delta.InSecondsF();
-}
+// A dictionary that maps usernames to OAuth token presence flag.
+const char kUserOAuthTokenStatus[] = "OAuthTokenStatus";
// Callback that is called after user removal is complete.
void OnRemoveUserComplete(const std::string& user_email,
@@ -186,22 +100,29 @@ void RemoveUserInternal(const std::string& user_email,
} // namespace
+// static
+void UserManager::RegisterPrefs(PrefService* local_state) {
+ LOG(ERROR) << "UserManager::RegisterPrefs";
+ local_state->RegisterListPref(kLoggedInUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserOAuthTokenStatus,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserDisplayName,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserDisplayEmail,
+ PrefService::UNSYNCABLE_PREF);
+}
+
UserManagerImpl::UserManagerImpl()
- : image_loader_(new UserImageLoader(ImageDecoder::DEFAULT_CODEC)),
- logged_in_user_(NULL),
+ : logged_in_user_(NULL),
session_started_(false),
is_current_user_owner_(false),
is_current_user_new_(false),
is_current_user_ephemeral_(false),
ephemeral_users_enabled_(false),
observed_sync_service_(NULL),
- last_image_set_async_(false),
- downloaded_profile_image_data_url_(chrome::kAboutBlankURL),
- downloading_profile_image_(false) {
+ user_image_manager_(new UserImageManagerImpl) {
// UserManager instance should be used only on UI thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- MigrateWallpaperData();
registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
@@ -218,6 +139,10 @@ UserManagerImpl::~UserManagerImpl() {
delete logged_in_user_;
}
+UserImageManager* UserManagerImpl::GetUserImageManager() {
+ return user_image_manager_.get();
+}
+
const UserList& UserManagerImpl::GetUsers() const {
const_cast<UserManagerImpl*>(this)->EnsureUsersLoaded();
return users_;
@@ -247,7 +172,7 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
// Clear the prefs view of the users.
PrefService* prefs = g_browser_process->local_state();
- ListPrefUpdate prefs_users_update(prefs, UserManager::kLoggedInUsers);
+ ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
prefs_users_update->Clear();
// Make sure this user is first.
@@ -273,54 +198,21 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
users_.insert(users_.begin(), logged_in_user_);
if (is_current_user_new_) {
- SaveUserDisplayName(GetLoggedInUser().email(),
- UTF8ToUTF16(GetLoggedInUser().GetAccountName(true)));
- SetInitialUserImage(email);
+ SaveUserDisplayName(logged_in_user_->email(),
+ UTF8ToUTF16(logged_in_user_->GetAccountName(true)));
WallpaperManager::Get()->SetInitialUserWallpaper(email, true);
- } else {
- int image_index = logged_in_user_->image_index();
- // If current user image is profile image, it needs to be refreshed.
- bool download_profile_image = image_index == User::kProfileImageIndex;
- if (download_profile_image)
- InitDownloadedProfileImage();
-
- // Download user's profile data (full name and optionally image) to see if
- // it has changed.
- BrowserThread::PostDelayedTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&UserManagerImpl::DownloadProfileData,
- base::Unretained(this),
- kProfileDownloadReasonLoggedIn,
- download_profile_image),
- base::TimeDelta::FromMilliseconds(kProfileDataDownloadDelayMs));
-
- int histogram_index = image_index;
- switch (image_index) {
- case User::kExternalImageIndex:
- // TODO(avayvod): Distinguish this from selected from file.
- histogram_index = kHistogramImageFromCamera;
- break;
-
- case User::kProfileImageIndex:
- histogram_index = kHistogramImageFromProfile;
- break;
- }
- UMA_HISTOGRAM_ENUMERATION("UserImage.LoggedIn",
- histogram_index,
- kHistogramImagesCount);
}
- // Set up a repeating timer for refreshing the profile data.
- profile_download_timer_.Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(kProfileRefreshIntervalMs),
- this, &UserManagerImpl::DownloadProfileDataScheduled);
+ user_image_manager_->UserLoggedIn(email, is_current_user_new_);
if (!browser_restart) {
// For GAIA login flow, logged in user wallpaper may not be loaded.
WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
}
+ // Make sure we persist new user data to Local State.
+ prefs->CommitPendingWrite();
+
NotifyOnLogin();
}
@@ -329,7 +221,7 @@ void UserManagerImpl::DemoUserLoggedIn() {
is_current_user_new_ = true;
is_current_user_ephemeral_ = true;
logged_in_user_ = CreateUser(kDemoUser, /* is_ephemeral= */ true);
- SetInitialUserImage(kDemoUser);
+ user_image_manager_->UserLoggedIn(kDemoUser, /* user_is_new= */ true);
WallpaperManager::Get()->SetInitialUserWallpaper(kDemoUser, false);
NotifyOnLogin();
}
@@ -339,7 +231,7 @@ void UserManagerImpl::GuestUserLoggedIn() {
is_current_user_ephemeral_ = true;
WallpaperManager::Get()->SetInitialUserWallpaper(kGuestUser, false);
logged_in_user_ = CreateUser(kGuestUser, /* is_ephemeral= */ true);
- logged_in_user_->SetStubImage(User::kInvalidImageIndex);
+ logged_in_user_->SetStubImage(User::kInvalidImageIndex, false);
NotifyOnLogin();
}
@@ -348,7 +240,7 @@ void UserManagerImpl::EphemeralUserLoggedIn(const std::string& email) {
is_current_user_new_ = true;
is_current_user_ephemeral_ = true;
logged_in_user_ = CreateUser(email, /* is_ephemeral= */ true);
- SetInitialUserImage(email);
+ user_image_manager_->UserLoggedIn(email, /* user_is_new= */ true);
WallpaperManager::Get()->SetInitialUserWallpaper(email, false);
NotifyOnLogin();
}
@@ -360,6 +252,10 @@ void UserManagerImpl::SessionStarted() {
chrome::NOTIFICATION_SESSION_STARTED,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
+ if (is_current_user_new_) {
+ // Make sure we persist new user data to Local State.
+ g_browser_process->local_state()->CommitPendingWrite();
+ }
}
void UserManagerImpl::RemoveUser(const std::string& email,
@@ -401,14 +297,14 @@ const User* UserManagerImpl::FindUser(const std::string& email) const {
return FindUserInList(email);
}
-const User& UserManagerImpl::GetLoggedInUser() const {
+const User* UserManagerImpl::GetLoggedInUser() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return *logged_in_user_;
+ return logged_in_user_;
}
-User& UserManagerImpl::GetLoggedInUser() {
+User* UserManagerImpl::GetLoggedInUser() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return *logged_in_user_;
+ return logged_in_user_;
}
void UserManagerImpl::SaveUserOAuthStatus(
@@ -427,8 +323,7 @@ void UserManagerImpl::SaveUserOAuthStatus(
PrefService* local_state = g_browser_process->local_state();
- DictionaryPrefUpdate oauth_status_update(local_state,
- UserManager::kUserOAuthTokenStatus);
+ DictionaryPrefUpdate oauth_status_update(local_state, kUserOAuthTokenStatus);
oauth_status_update->SetWithoutPathExpansion(username,
new base::FundamentalValue(static_cast<int>(oauth_token_status)));
}
@@ -444,7 +339,7 @@ User::OAuthTokenStatus UserManagerImpl::LoadUserOAuthStatus(
} else {
PrefService* local_state = g_browser_process->local_state();
const DictionaryValue* prefs_oauth_status =
- local_state->GetDictionary(UserManager::kUserOAuthTokenStatus);
+ local_state->GetDictionary(kUserOAuthTokenStatus);
int oauth_token_status = User::OAUTH_TOKEN_STATUS_UNKNOWN;
if (prefs_oauth_status &&
@@ -473,8 +368,7 @@ void UserManagerImpl::SaveUserDisplayName(const std::string& username,
PrefService* local_state = g_browser_process->local_state();
- DictionaryPrefUpdate display_name_update(local_state,
- UserManager::kUserDisplayName);
+ DictionaryPrefUpdate display_name_update(local_state, kUserDisplayName);
display_name_update->SetWithoutPathExpansion(
username,
base::Value::CreateStringValue(display_name));
@@ -502,8 +396,7 @@ void UserManagerImpl::SaveUserDisplayEmail(const std::string& username,
PrefService* local_state = g_browser_process->local_state();
- DictionaryPrefUpdate display_email_update(local_state,
- UserManager::kUserDisplayEmail);
+ DictionaryPrefUpdate display_email_update(local_state, kUserDisplayEmail);
display_email_update->SetWithoutPathExpansion(
username,
base::Value::CreateStringValue(display_email));
@@ -515,21 +408,6 @@ std::string UserManagerImpl::GetUserDisplayEmail(
return user ? user->display_email() : username;
}
-void UserManagerImpl::SaveUserDefaultImageIndex(const std::string& username,
- int image_index) {
- DCHECK(image_index >= 0 && image_index < kDefaultImagesCount);
- SetUserImage(username, image_index, GURL(),
- UserImage(GetDefaultImage(image_index)));
- SaveImageToLocalState(username, "", image_index, GURL(), false);
-}
-
-void UserManagerImpl::SaveUserImage(const std::string& username,
- const UserImage& user_image) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- SaveUserImageInternal(username, User::kExternalImageIndex,
- GURL(), user_image);
-}
-
void UserManagerImpl::SetLoggedInUserCustomWallpaperLayout(
ash::WallpaperLayout layout) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -539,8 +417,7 @@ void UserManagerImpl::SetLoggedInUserCustomWallpaperLayout(
// memory. Need a smarter way to solve this.
if (IsCurrentUserEphemeral())
return;
- const chromeos::User& user = GetLoggedInUser();
- std::string username = user.email();
+ std::string username = logged_in_user_->email();
DCHECK(!username.empty());
std::string file_path = WallpaperManager::Get()->
@@ -550,37 +427,6 @@ void UserManagerImpl::SetLoggedInUserCustomWallpaperLayout(
WallpaperManager::Get()->SetUserWallpaper(username);
}
-void UserManagerImpl::SaveUserImageFromFile(const std::string& username,
- const FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- image_loader_->Start(
- path.value(), login::kMaxUserImageSize,
- base::Bind(&UserManagerImpl::SaveUserImage,
- base::Unretained(this), username));
-}
-
-void UserManagerImpl::SaveUserImageFromProfileImage(
- const std::string& username) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!downloaded_profile_image_.isNull()) {
- // Profile image has already been downloaded, so save it to file right now.
- DCHECK(profile_image_url_.is_valid());
- SaveUserImageInternal(
- username,
- User::kProfileImageIndex, profile_image_url_,
- UserImage::CreateAndEncode(downloaded_profile_image_));
- } else {
- // No profile image - use the stub image (gray avatar).
- SetUserImage(username, User::kProfileImageIndex, GURL(), UserImage());
- SaveImageToLocalState(username, "", User::kProfileImageIndex,
- GURL(), false);
- }
-}
-
-void UserManagerImpl::DownloadProfileImage(const std::string& reason) {
- DownloadProfileData(reason, true);
-}
-
void UserManagerImpl::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -609,17 +455,18 @@ void UserManagerImpl::Observe(int type,
void UserManagerImpl::OnStateChanged() {
DCHECK(IsUserLoggedIn() && !IsLoggedInAsGuest());
- AuthError::State state = observed_sync_service_->GetAuthError().state();
- if (state != AuthError::NONE &&
- state != AuthError::CONNECTION_FAILED &&
- state != AuthError::SERVICE_UNAVAILABLE &&
- state != AuthError::REQUEST_CANCELED) {
+ GoogleServiceAuthError::State state =
+ observed_sync_service_->GetAuthError().state();
+ if (state != GoogleServiceAuthError::NONE &&
+ state != GoogleServiceAuthError::CONNECTION_FAILED &&
+ state != GoogleServiceAuthError::SERVICE_UNAVAILABLE &&
+ state != GoogleServiceAuthError::REQUEST_CANCELED) {
// Invalidate OAuth token to force Gaia sign-in flow. This is needed
// because sign-out/sign-in solution is suggested to the user.
// TODO(altimofeev): this code isn't needed after crosbug.com/25978 is
// implemented.
DVLOG(1) << "Invalidate OAuth token because of a sync error.";
- SaveUserOAuthStatus(GetLoggedInUser().email(),
+ SaveUserOAuthStatus(logged_in_user_->email(),
User::OAUTH_TOKEN_STATUS_INVALID);
}
}
@@ -704,24 +551,12 @@ void UserManagerImpl::RemoveObserver(UserManager::Observer* obs) {
observer_list_.RemoveObserver(obs);
}
-const gfx::ImageSkia& UserManagerImpl::DownloadedProfileImage() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return downloaded_profile_image_;
-}
-
void UserManagerImpl::NotifyLocalStateChanged() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
FOR_EACH_OBSERVER(UserManager::Observer, observer_list_,
LocalStateChanged(this));
}
-FilePath UserManagerImpl::GetImagePathForUser(const std::string& username) {
- std::string filename = username + ".png";
- FilePath user_data_dir;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- return user_data_dir.AppendASCII(filename);
-}
-
void UserManagerImpl::EnsureUsersLoaded() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!users_.empty())
@@ -731,96 +566,40 @@ void UserManagerImpl::EnsureUsersLoaded() {
PrefService* local_state = g_browser_process->local_state();
const ListValue* prefs_users =
- local_state->GetList(UserManager::kLoggedInUsers);
- const DictionaryValue* prefs_images =
- local_state->GetDictionary(UserManager::kUserImages);
+ local_state->GetList(kLoggedInUsers);
const DictionaryValue* prefs_display_names =
- local_state->GetDictionary(UserManager::kUserDisplayName);
+ local_state->GetDictionary(kUserDisplayName);
const DictionaryValue* prefs_display_emails =
- local_state->GetDictionary(UserManager::kUserDisplayEmail);
-
- if (prefs_users) {
- for (ListValue::const_iterator it = prefs_users->begin();
- it != prefs_users->end(); ++it) {
- std::string email;
- if ((*it)->GetAsString(&email)) {
- User* user = CreateUser(email, /* is_ephemeral= */ false);
- users_.push_back(user);
-
- if (prefs_images) {
- // Get account image path.
- // TODO(avayvod): Reading image path as a string is here for
- // backward compatibility.
- std::string image_path;
- const base::DictionaryValue* image_properties;
- if (prefs_images->GetStringWithoutPathExpansion(email, &image_path)) {
- int image_id = User::kInvalidImageIndex;
- if (IsDefaultImagePath(image_path, &image_id)) {
- user->SetImage(UserImage(GetDefaultImage(image_id)), image_id);
- } else {
- int image_index = User::kExternalImageIndex;
- // Until image has been loaded, use the stub image.
- user->SetStubImage(image_index);
- DCHECK(!image_path.empty());
- // Load user image asynchronously.
- image_loader_->Start(
- image_path, 0 /* no resize */,
- base::Bind(&UserManagerImpl::SetUserImage,
- base::Unretained(this),
- email, image_index, GURL()));
- }
- } else if (prefs_images->GetDictionaryWithoutPathExpansion(
- email, &image_properties)) {
- int image_index = User::kInvalidImageIndex;
- image_properties->GetString(kImagePathNodeName, &image_path);
- image_properties->GetInteger(kImageIndexNodeName, &image_index);
- if (image_index >= 0 && image_index < kDefaultImagesCount) {
- user->SetImage(UserImage(GetDefaultImage(image_index)),
- image_index);
- } else if (image_index == User::kExternalImageIndex ||
- image_index == User::kProfileImageIndex) {
- // Path may be empty for profile images (meaning that the image
- // hasn't been downloaded for the first time yet, in which case a
- // download will be scheduled for |kProfileDataDownloadDelayMs|
- // after user logs in).
- DCHECK(!image_path.empty() ||
- image_index == User::kProfileImageIndex);
- std::string image_url;
- image_properties->GetString(kImageURLNodeName, &image_url);
- GURL image_gurl(image_url);
- // Until image has been loaded, use the stub image (gray avatar).
- user->SetStubImage(image_index);
- user->SetImageURL(image_gurl);
- if (!image_path.empty()) {
- // Load user image asynchronously.
- image_loader_->Start(
- image_path, 0 /* no resize */,
- base::Bind(&UserManagerImpl::SetUserImage,
- base::Unretained(this),
- email, image_index, image_gurl));
- }
- } else {
- NOTREACHED();
- }
- }
- }
+ local_state->GetDictionary(kUserDisplayEmail);
- string16 display_name;
- if (prefs_display_names &&
- prefs_display_names->GetStringWithoutPathExpansion(
- email, &display_name)) {
- user->set_display_name(display_name);
- }
+ if (!prefs_users)
+ return;
- std::string display_email;
- if (prefs_display_emails &&
- prefs_display_emails->GetStringWithoutPathExpansion(
- email, &display_email)) {
- user->set_display_email(display_email);
- }
+ for (ListValue::const_iterator it = prefs_users->begin();
+ it != prefs_users->end(); ++it) {
+ std::string email;
+ if ((*it)->GetAsString(&email)) {
+ User* user = CreateUser(email, /* is_ephemeral= */ false);
+ users_.push_back(user);
+
+ string16 display_name;
+ if (prefs_display_names &&
+ prefs_display_names->GetStringWithoutPathExpansion(
+ email, &display_name)) {
+ user->set_display_name(display_name);
+ }
+
+ std::string display_email;
+ if (prefs_display_emails &&
+ prefs_display_emails->GetStringWithoutPathExpansion(
+ email, &display_email)) {
+ user->set_display_email(display_email);
}
}
}
+
+ user_image_manager_->LoadUserImages(users_);
+ WallpaperManager::Get()->MigrateWallpaperData(users_);
}
void UserManagerImpl::RetrieveTrustedDevicePolicies() {
@@ -859,7 +638,7 @@ void UserManagerImpl::RetrieveTrustedDevicePolicies() {
if (changed) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
- content::Source<UserManagerImpl>(this),
+ content::Source<UserManager>(this),
content::NotificationService::NoDetails());
}
}
@@ -884,7 +663,7 @@ void UserManagerImpl::NotifyOnLogin() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_LOGIN_USER_CHANGED,
- content::Source<UserManagerImpl>(this),
+ content::Source<UserManager>(this),
content::Details<const User>(logged_in_user_));
CrosLibrary::Get()->GetCertLibrary()->LoadKeyStore();
@@ -894,177 +673,13 @@ void UserManagerImpl::NotifyOnLogin() {
DeviceSettingsService::Get()->SetUsername(logged_in_user_->email());
}
-void UserManagerImpl::SetInitialUserImage(const std::string& username) {
- // Choose a random default image.
- int image_id =
- base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1);
- SaveUserDefaultImageIndex(username, image_id);
-}
-
-void UserManagerImpl::MigrateWallpaperData() {
- PrefService* local_state = g_browser_process->local_state();
- if (local_state) {
- const DictionaryValue* user_wallpapers =
- local_state->GetDictionary(kUserWallpapers);
- int index;
- const DictionaryValue* new_user_wallpapers =
- local_state->GetDictionary(kUserWallpapersProperties);
- if (new_user_wallpapers->empty()) {
- const UserList& users = GetUsers();
- for (UserList::const_iterator it = users.begin();
- it != users.end();
- ++it) {
- std::string username = (*it)->email();
- if (user_wallpapers->GetIntegerWithoutPathExpansion((username),
- &index)) {
- DictionaryPrefUpdate prefs_wallpapers_update(local_state,
- kUserWallpapers);
- prefs_wallpapers_update->RemoveWithoutPathExpansion(username, NULL);
- WallpaperManager::Get()->SetUserWallpaperProperties(username,
- User::DEFAULT,
- index,
- true);
- } else {
- // Before M20, wallpaper index is not saved into LocalState unless
- // user specifically sets a wallpaper. After M20, the default
- // wallpaper index is saved to LocalState as soon as a new user login.
- // When migrating wallpaper index from M20 to M21, we only migrate
- // data that is in LocalState. This cause a problem when users login
- // on a M20 device and then update the device to M21. The default
- // wallpaper index failed to migrate because it was not saved into
- // LocalState. Then we assume that all users have index saved in
- // LocalState in M21. This is not true and it results an empty
- // wallpaper for those users as described in cr/130685. So here we use
- // default wallpaper for users that exist in user list but does not
- // have an index saved in LocalState.
- WallpaperManager::Get()->SetUserWallpaperProperties(username,
- User::DEFAULT, ash::GetDefaultWallpaperIndex(), true);
- }
- }
- }
- }
-}
-
void UserManagerImpl::SaveLoggedInUserWallpaperProperties(
User::WallpaperType type, int index) {
// Ephemeral users can not save data to local state.
// We just cache the index in memory for them.
bool is_persistent = !IsCurrentUserEphemeral();
WallpaperManager::Get()->SetUserWallpaperProperties(
- GetLoggedInUser().email(), type, index, is_persistent);
-}
-
-void UserManagerImpl::SetUserImage(const std::string& username,
- int image_index,
- const GURL& image_url,
- const UserImage& user_image) {
- User* user = const_cast<User*>(FindUser(username));
- // User may have been removed by now.
- if (user) {
- // For existing users, a valid image index should have been set upon loading
- // them from Local State.
- DCHECK(user->image_index() != User::kInvalidImageIndex ||
- is_current_user_new_);
- bool image_changed = user->image_index() != User::kInvalidImageIndex;
- if (!user_image.image().isNull())
- user->SetImage(user_image, image_index);
- else
- user->SetStubImage(image_index);
- user->SetImageURL(image_url);
- // For the logged-in user with a profile picture, initialize
- // |downloaded_profile_picture_|.
- if (user == logged_in_user_ && image_index == User::kProfileImageIndex)
- InitDownloadedProfileImage();
- if (image_changed) {
- // Unless this is first-time setting with |SetInitialUserImage|,
- // send a notification about image change.
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
- content::Source<UserManagerImpl>(this),
- content::Details<const User>(user));
- }
- }
-}
-
-void UserManagerImpl::SaveUserImageInternal(const std::string& username,
- int image_index,
- const GURL& image_url,
- const UserImage& user_image) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- SetUserImage(username, image_index, image_url, user_image);
-
- // Ignore for ephemeral users.
- if (IsEphemeralUser(username))
- return;
-
- FilePath image_path = GetImagePathForUser(username);
- DVLOG(1) << "Saving user image to " << image_path.value();
-
- last_image_set_async_ = true;
-
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UserManagerImpl::SaveImageToFile,
- base::Unretained(this),
- username, user_image, image_path, image_index, image_url));
-}
-
-void UserManagerImpl::SaveImageToFile(const std::string& username,
- const UserImage& user_image,
- const FilePath& image_path,
- int image_index,
- const GURL& image_url) {
- if (!SaveBitmapToFile(user_image, image_path))
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&UserManagerImpl::SaveImageToLocalState,
- base::Unretained(this),
- username, image_path.value(), image_index, image_url, true));
-}
-
-void UserManagerImpl::SaveImageToLocalState(const std::string& username,
- const std::string& image_path,
- int image_index,
- const GURL& image_url,
- bool is_async) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Ignore for ephemeral users.
- if (IsEphemeralUser(username))
- return;
-
- // TODO(ivankr): use unique filenames for user images each time
- // a new image is set so that only the last image update is saved
- // to Local State and notified.
- if (is_async && !last_image_set_async_) {
- DVLOG(1) << "Ignoring saved image because it has changed";
- return;
- } else if (!is_async) {
- // Reset the async image save flag if called directly from the UI thread.
- last_image_set_async_ = false;
- }
-
- PrefService* local_state = g_browser_process->local_state();
- DictionaryPrefUpdate images_update(local_state, UserManager::kUserImages);
- base::DictionaryValue* image_properties = new base::DictionaryValue();
- image_properties->Set(kImagePathNodeName, new StringValue(image_path));
- image_properties->Set(kImageIndexNodeName,
- new base::FundamentalValue(image_index));
- if (!image_url.is_empty()) {
- image_properties->Set(kImageURLNodeName,
- new StringValue(image_url.spec()));
- } else {
- image_properties->Remove(kImageURLNodeName, NULL);
- }
- images_update->SetWithoutPathExpansion(username, image_properties);
- DVLOG(1) << "Saving path to user image in Local State.";
-
- NotifyLocalStateChanged();
+ logged_in_user_->email(), type, index, is_persistent);
}
void UserManagerImpl::SaveWallpaperToLocalState(const std::string& username,
@@ -1076,78 +691,6 @@ void UserManagerImpl::SaveWallpaperToLocalState(const std::string& username,
username, type, layout, true);
}
-bool UserManagerImpl::SaveBitmapToFile(const UserImage& user_image,
- const FilePath& image_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- const UserImage::RawImage* encoded_image = NULL;
- if (user_image.has_animated_image()) {
- encoded_image = &user_image.animated_image();
- } else if (user_image.has_raw_image()) {
- encoded_image = &user_image.raw_image();
- } else {
- LOG(ERROR) << "Failed to encode the image.";
- return false;
- }
- DCHECK(encoded_image != NULL);
-
- if (file_util::WriteFile(image_path,
- reinterpret_cast<const char*>(&(*encoded_image)[0]),
- encoded_image->size()) == -1) {
- LOG(ERROR) << "Failed to save image to file.";
- return false;
- }
- return true;
-}
-
-void UserManagerImpl::InitDownloadedProfileImage() {
- DCHECK(logged_in_user_);
- DCHECK_EQ(logged_in_user_->image_index(), User::kProfileImageIndex);
- if (downloaded_profile_image_.isNull() && !logged_in_user_->image_is_stub()) {
- VLOG(1) << "Profile image initialized";
- downloaded_profile_image_ = logged_in_user_->image();
- downloaded_profile_image_data_url_ =
- web_ui_util::GetImageDataUrl(downloaded_profile_image_);
- profile_image_url_ = logged_in_user_->image_url();
- }
-}
-
-void UserManagerImpl::DownloadProfileData(const std::string& reason,
- bool download_image) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // For guest login there's no profile image to download.
- if (IsLoggedInAsGuest())
- return;
-
- // Mark profile picture as needed.
- downloading_profile_image_ |= download_image;
-
- // Another download is already in progress
- if (profile_image_downloader_.get())
- return;
-
- profile_image_download_reason_ = reason;
- profile_image_load_start_time_ = base::Time::Now();
- profile_image_downloader_.reset(new ProfileDownloader(this));
- profile_image_downloader_->Start();
-}
-
-void UserManagerImpl::DownloadProfileDataScheduled() {
- // If current user image is profile image, it needs to be refreshed.
- bool download_profile_image =
- logged_in_user_->image_index() == User::kProfileImageIndex;
- DownloadProfileData(kProfileDownloadReasonScheduled, download_profile_image);
-}
-
-void UserManagerImpl::DeleteUserImage(const FilePath& image_path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (!file_util::Delete(image_path, false)) {
- LOG(ERROR) << "Failed to remove user image.";
- return;
- }
-}
-
void UserManagerImpl::UpdateOwnership(
DeviceSettingsService::OwnershipStatus status,
bool is_owner) {
@@ -1162,120 +705,6 @@ void UserManagerImpl::CheckOwnership() {
base::Unretained(this)));
}
-// ProfileDownloaderDelegate override.
-bool UserManagerImpl::NeedsProfilePicture() const {
- return downloading_profile_image_;
-}
-
-// ProfileDownloaderDelegate override.
-int UserManagerImpl::GetDesiredImageSideLength() const {
- return GetCurrentUserImageSize();
-}
-
-// ProfileDownloaderDelegate override.
-std::string UserManagerImpl::GetCachedPictureURL() const {
- return profile_image_url_.spec();
-}
-
-Profile* UserManagerImpl::GetBrowserProfile() {
- return ProfileManager::GetDefaultProfile();
-}
-
-void UserManagerImpl::OnProfileDownloadSuccess(ProfileDownloader* downloader) {
- // Make sure that |ProfileDownloader| gets deleted after return.
- scoped_ptr<ProfileDownloader> profile_image_downloader(
- profile_image_downloader_.release());
- DCHECK_EQ(downloader, profile_image_downloader.get());
-
- if (!downloader->GetProfileFullName().empty()) {
- SaveUserDisplayName(GetLoggedInUser().email(),
- downloader->GetProfileFullName());
- }
-
- bool requested_image = downloading_profile_image_;
- downloading_profile_image_ = false;
- if (!requested_image)
- return;
-
- ProfileDownloadResult result = kDownloadFailure;
- switch (downloader->GetProfilePictureStatus()) {
- case ProfileDownloader::PICTURE_SUCCESS:
- result = kDownloadSuccess;
- break;
- case ProfileDownloader::PICTURE_CACHED:
- result = kDownloadCached;
- break;
- case ProfileDownloader::PICTURE_DEFAULT:
- result = kDownloadDefault;
- break;
- default:
- NOTREACHED();
- }
-
- UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
- result, kDownloadResultsCount);
-
- DCHECK(!profile_image_load_start_time_.is_null());
- base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
- AddProfileImageTimeHistogram(result, profile_image_download_reason_, delta);
-
- if (result == kDownloadDefault) {
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
- content::Source<UserManagerImpl>(this),
- content::NotificationService::NoDetails());
- }
-
- // Nothing to do if picture is cached or the default avatar.
- if (result != kDownloadSuccess)
- return;
-
- // Check if this image is not the same as already downloaded.
- gfx::ImageSkia new_image(downloader->GetProfilePicture());
- std::string new_image_data_url = web_ui_util::GetImageDataUrl(new_image);
- if (!downloaded_profile_image_data_url_.empty() &&
- new_image_data_url == downloaded_profile_image_data_url_)
- return;
-
- downloaded_profile_image_data_url_ = new_image_data_url;
- downloaded_profile_image_ = gfx::ImageSkia(downloader->GetProfilePicture());
- profile_image_url_ = GURL(downloader->GetProfilePictureURL());
-
- if (GetLoggedInUser().image_index() == User::kProfileImageIndex) {
- VLOG(1) << "Updating profile image for logged-in user";
- UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
- kDownloadSuccessChanged,
- kDownloadResultsCount);
- // This will persist |downloaded_profile_image_| to file.
- SaveUserImageFromProfileImage(GetLoggedInUser().email());
- }
-
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
- content::Source<UserManagerImpl>(this),
- content::Details<const gfx::ImageSkia>(&downloaded_profile_image_));
-}
-
-void UserManagerImpl::OnProfileDownloadFailure(ProfileDownloader* downloader) {
- DCHECK_EQ(downloader, profile_image_downloader_.get());
- profile_image_downloader_.reset();
-
- downloading_profile_image_ = false;
-
- UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
- kDownloadFailure, kDownloadResultsCount);
-
- DCHECK(!profile_image_load_start_time_.is_null());
- base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
- AddProfileImageTimeHistogram(kDownloadFailure, profile_image_download_reason_,
- delta);
-
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
- content::Source<UserManagerImpl>(this),
- content::NotificationService::NoDetails());
-}
-
User* UserManagerImpl::CreateUser(const std::string& email,
bool is_ephemeral) const {
User* user = new User(email);
@@ -1302,11 +731,6 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
WallpaperManager::Get()->RemoveUserWallpaperInfo(email);
- DictionaryPrefUpdate prefs_images_update(prefs, kUserImages);
- std::string image_path_string;
- prefs_images_update->GetStringWithoutPathExpansion(email, &image_path_string);
- prefs_images_update->RemoveWithoutPathExpansion(email, NULL);
-
DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
int oauth_status;
prefs_oauth_update->GetIntegerWithoutPathExpansion(email, &oauth_status);
@@ -1322,18 +746,6 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
delete *user_to_remove;
users_.erase(user_to_remove);
}
-
- int default_image_id = User::kInvalidImageIndex;
- if (!image_path_string.empty() &&
- !IsDefaultImagePath(image_path_string, &default_image_id)) {
- FilePath image_path(image_path_string);
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&UserManagerImpl::DeleteUserImage,
- base::Unretained(this),
- image_path));
- }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h
index 10cf895..801ed8a 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_manager_impl.h
@@ -8,45 +8,36 @@
#include <string>
#include "base/basictypes.h"
-#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
-#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "base/timer.h"
#include "chrome/browser/api/sync/profile_sync_service_observer.h"
#include "chrome/browser/chromeos/login/user.h"
-#include "chrome/browser/chromeos/login/user_image_loader.h"
+#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chrome/browser/profiles/profile_downloader_delegate.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "ui/gfx/image/image_skia.h"
class FilePath;
class PrefService;
-class ProfileDownloader;
class ProfileSyncService;
-class SkBitmap;
namespace chromeos {
class RemoveUserDelegate;
-class UserImage;
// Implementation of the UserManager.
class UserManagerImpl : public UserManager,
- public ProfileDownloaderDelegate,
public ProfileSyncServiceObserver,
public content::NotificationObserver {
public:
- // UserManager implementation:
virtual ~UserManagerImpl();
+ // UserManager implementation:
+ virtual UserImageManager* GetUserImageManager() OVERRIDE;
virtual const UserList& GetUsers() const OVERRIDE;
virtual void UserLoggedIn(const std::string& email,
bool browser_restart) OVERRIDE;
@@ -59,8 +50,8 @@ class UserManagerImpl : public UserManager,
virtual void RemoveUserFromList(const std::string& email) OVERRIDE;
virtual bool IsKnownUser(const std::string& email) const OVERRIDE;
virtual const User* FindUser(const std::string& email) const OVERRIDE;
- virtual const User& GetLoggedInUser() const OVERRIDE;
- virtual User& GetLoggedInUser() OVERRIDE;
+ virtual const User* GetLoggedInUser() const OVERRIDE;
+ virtual User* GetLoggedInUser() OVERRIDE;
virtual void SaveUserOAuthStatus(
const std::string& username,
User::OAuthTokenStatus oauth_token_status) OVERRIDE;
@@ -74,17 +65,8 @@ class UserManagerImpl : public UserManager,
const std::string& username) const OVERRIDE;
virtual void SaveLoggedInUserWallpaperProperties(User::WallpaperType type,
int index) OVERRIDE;
- virtual void SaveUserDefaultImageIndex(const std::string& username,
- int image_index) OVERRIDE;
- virtual void SaveUserImage(const std::string& username,
- const UserImage& user_image) OVERRIDE;
virtual void SetLoggedInUserCustomWallpaperLayout(
ash::WallpaperLayout layout) OVERRIDE;
- virtual void SaveUserImageFromFile(const std::string& username,
- const FilePath& path) OVERRIDE;
- virtual void SaveUserImageFromProfileImage(
- const std::string& username) OVERRIDE;
- virtual void DownloadProfileImage(const std::string& reason) OVERRIDE;
virtual bool IsCurrentUserOwner() const OVERRIDE;
virtual bool IsCurrentUserNew() const OVERRIDE;
virtual bool IsCurrentUserEphemeral() const OVERRIDE;
@@ -97,7 +79,6 @@ class UserManagerImpl : public UserManager,
virtual void AddObserver(UserManager::Observer* obs) OVERRIDE;
virtual void RemoveObserver(UserManager::Observer* obs) OVERRIDE;
virtual void NotifyLocalStateChanged() OVERRIDE;
- virtual const gfx::ImageSkia& DownloadedProfileImage() const OVERRIDE;
// content::NotificationObserver implementation.
virtual void Observe(int type,
@@ -107,16 +88,12 @@ class UserManagerImpl : public UserManager,
// ProfileSyncServiceObserver implementation.
virtual void OnStateChanged() OVERRIDE;
- protected:
- UserManagerImpl();
-
- // Returns image filepath for the given user.
- FilePath GetImagePathForUser(const std::string& username);
-
private:
friend class UserManagerImplWrapper;
- friend class UserManagerTest;
friend class WallpaperManager;
+ friend class UserManagerTest;
+
+ UserManagerImpl();
// Loads |users_| from Local State if the list has not been loaded yet.
// Subsequent calls have no effect. Must be called on the UI thread.
@@ -143,76 +120,12 @@ class UserManagerImpl : public UserManager,
void SetCurrentUserIsOwner(bool is_current_user_owner);
- // Sets one of the default images for the specified user and saves this
- // setting in local state.
- // Does not send LOGIN_USER_IMAGE_CHANGED notification.
- void SetInitialUserImage(const std::string& username);
-
- // Migrate the old wallpaper index to a new wallpaper structure.
- // The new wallpaper structure is:
- // { WallpaperType: DAILY|CUSTOMIZED|DEFAULT,
- // index: index of the default wallpapers }
- void MigrateWallpaperData();
-
- // Sets image for user |username| and sends LOGIN_USER_IMAGE_CHANGED
- // notification unless this is a new user and image is set for the first time.
- // If |image| is empty, sets a stub image for the user.
- void SetUserImage(const std::string& username,
- int image_index,
- const GURL& image_url,
- const UserImage& user_image);
-
- // Saves image to file, updates local state preferences to given image index
- // and sends LOGIN_USER_IMAGE_CHANGED notification.
- void SaveUserImageInternal(const std::string& username,
- int image_index,
- const GURL& image_url,
- const UserImage& user_image);
-
- // Saves image to file with specified path and sends LOGIN_USER_IMAGE_CHANGED
- // notification. Runs on FILE thread. Posts task for saving image info to
- // Local State on UI thread.
- void SaveImageToFile(const std::string& username,
- const UserImage& user_image,
- const FilePath& image_path,
- int image_index,
- const GURL& image_url);
-
- // Stores path to the image and its index in local state. Runs on UI thread.
- // If |is_async| is true, it has been posted from the FILE thread after
- // saving the image.
- void SaveImageToLocalState(const std::string& username,
- const std::string& image_path,
- int image_index,
- const GURL& image_url,
- bool is_async);
-
// Stores layout and type preference in local state. Runs on UI thread.
void SaveWallpaperToLocalState(const std::string& username,
const std::string& wallpaper_path,
ash::WallpaperLayout layout,
User::WallpaperType type);
- // Saves |image| to the specified |image_path|. Runs on FILE thread.
- bool SaveBitmapToFile(const UserImage& user_image,
- const FilePath& image_path);
-
- // Initializes |downloaded_profile_image_| with the picture of the logged-in
- // user.
- void InitDownloadedProfileImage();
-
- // Download user's profile data, including full name and picture, when
- // |download_image| is true.
- // |reason| is an arbitrary string (used to report UMA histograms with
- // download times).
- void DownloadProfileData(const std::string& reason, bool download_image);
-
- // Scheduled call for downloading profile data.
- void DownloadProfileDataScheduled();
-
- // Deletes user's image file. Runs on FILE thread.
- void DeleteUserImage(const FilePath& image_path);
-
// Updates current user ownership on UI thread.
void UpdateOwnership(DeviceSettingsService::OwnershipStatus status,
bool is_owner);
@@ -220,14 +133,6 @@ class UserManagerImpl : public UserManager,
// Triggers an asynchronous ownership check.
void CheckOwnership();
- // ProfileDownloaderDelegate implementation.
- virtual bool NeedsProfilePicture() const OVERRIDE;
- virtual int GetDesiredImageSideLength() const OVERRIDE;
- virtual Profile* GetBrowserProfile() OVERRIDE;
- virtual std::string GetCachedPictureURL() const OVERRIDE;
- virtual void OnProfileDownloadSuccess(ProfileDownloader* downloader) OVERRIDE;
- virtual void OnProfileDownloadFailure(ProfileDownloader* downloader) OVERRIDE;
-
// Creates a new User instance.
User* CreateUser(const std::string& email, bool is_ephemeral) const;
@@ -235,9 +140,6 @@ class UserManagerImpl : public UserManager,
// picture.
void RemoveUserFromListInternal(const std::string& email);
- // Loads user image from its file.
- scoped_refptr<UserImageLoader> image_loader_;
-
// List of all known users. User instances are owned by |this| and deleted
// when users are removed by |RemoveUserFromListInternal|.
mutable UserList users_;
@@ -285,35 +187,7 @@ class UserManagerImpl : public UserManager,
ObserverList<UserManager::Observer> observer_list_;
- // Download user profile image on login to update it if it's changed.
- scoped_ptr<ProfileDownloader> profile_image_downloader_;
-
- // Arbitrary string passed to the last |DownloadProfileImage| call.
- std::string profile_image_download_reason_;
-
- // Time when the profile image download has started.
- base::Time profile_image_load_start_time_;
-
- // True if the last user image required async save operation (which may not
- // have been completed yet). This flag is used to avoid races when user image
- // is first set with |SaveUserImage| and then with |SaveUserImagePath|.
- bool last_image_set_async_;
-
- // Result of the last successful profile image download, if any.
- gfx::ImageSkia downloaded_profile_image_;
-
- // Data URL for |downloaded_profile_image_|.
- std::string downloaded_profile_image_data_url_;
-
- // Original URL of |downloaded_profile_image_|, from which it was downloaded.
- GURL profile_image_url_;
-
- // True when |profile_image_downloader_| is fetching profile picture (not
- // just full name).
- bool downloading_profile_image_;
-
- // Timer triggering DownloadProfileDataScheduled for refreshing profile data.
- base::RepeatingTimer<UserManagerImpl> profile_download_timer_;
+ scoped_ptr<UserImageManagerImpl> user_image_manager_;
DISALLOW_COPY_AND_ASSIGN(UserManagerImpl);
};
diff --git a/chrome/browser/chromeos/login/user_manager_unittest.cc b/chrome/browser/chromeos/login/user_manager_unittest.cc
index c9b2df8..8d8f5e0 100644
--- a/chrome/browser/chromeos/login/user_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/user_manager_unittest.cc
@@ -60,8 +60,9 @@ class UserManagerTest : public testing::Test {
reinterpret_cast<TestingBrowserProcess*>(g_browser_process)
->SetLocalState(local_state_.get());
UserManager::RegisterPrefs(local_state_.get());
- // Wallpaper manager pref is also used by the unit test when new wallpaper
- // picker ui is enabled.
+ // Wallpaper manager and user image managers prefs will be accessed by the
+ // unit-test as well.
+ UserImageManager::RegisterPrefs(local_state_.get());
WallpaperManager::RegisterPrefs(local_state_.get());
old_user_manager_ = UserManager::Get();
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index 223a7a1..04f7c35 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include <vector>
+
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/desktop_background/desktop_background_resources.h"
#include "ash/shell.h"
@@ -47,6 +48,11 @@ namespace {
const int kWallpaperUpdateIntervalSec = 24 * 60 * 60;
+// A dictionary pref that maps usernames to file paths to their wallpapers.
+// Deprecated. Will remove this const char after done migration.
+const char kUserWallpapers[] = "UserWallpapers";
+
+// Names of nodes with info about wallpaper in |kUserWallpapers| dictionary.
const char kWallpaperTypeNodeName[] = "type";
const char kWallpaperIndexNodeName[] = "index";
const char kWallpaperDateNodeName[] = "date";
@@ -66,7 +72,11 @@ const int kDefaultOOBEWallpaperIndex = 20; // IDR_AURA_WALLPAPERS_2_LANDSCAPE8
const int kDefaultOOBEWallpaperIndex = 0; // IDR_AURA_WALLPAPERS_ROMAINGUY_0
#endif
-// Names of nodes with info about wallpaper.
+// A dictionary pref that maps usernames to wallpaper properties.
+const char kUserWallpapersProperties[] = "UserWallpapersProperties";
+
+// Names of nodes with info about wallpaper in |kUserWallpapersProperties|
+// dictionary.
const char kNewWallpaperDateNodeName[] = "date";
const char kNewWallpaperLayoutNodeName[] = "layout";
const char kNewWallpaperFileNodeName[] = "file";
@@ -132,6 +142,10 @@ WallpaperManager::WallpaperManager()
void WallpaperManager::RegisterPrefs(PrefService* local_state) {
local_state->RegisterDictionaryPref(prefs::kUsersWallpaperInfo,
PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserWallpapers,
+ PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterDictionaryPref(kUserWallpapersProperties,
+ PrefService::UNSYNCABLE_PREF);
}
void WallpaperManager::AddObservers() {
@@ -161,7 +175,7 @@ void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
return;
}
}
- SetUserWallpaper(UserManager::Get()->GetLoggedInUser().email());
+ SetUserWallpaper(UserManager::Get()->GetLoggedInUser()->email());
}
void WallpaperManager::GetCustomWallpaper(const std::string& email,
@@ -240,7 +254,7 @@ void WallpaperManager::GetLoggedInUserWallpaperProperties(
return;
}
- GetUserWallpaperProperties(UserManager::Get()->GetLoggedInUser().email(),
+ GetUserWallpaperProperties(UserManager::Get()->GetLoggedInUser()->email(),
type, index, last_modification_date);
}
@@ -254,7 +268,7 @@ bool WallpaperManager::GetLoggedInUserWallpaperInfo(WallpaperInfo* info) {
return true;
}
- return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser().email(),
+ return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
info);
}
@@ -309,7 +323,7 @@ void WallpaperManager::InitializeWallpaper() {
}
return;
}
- SetUserWallpaper(user_manager->GetLoggedInUser().email());
+ SetUserWallpaper(user_manager->GetLoggedInUser()->email());
}
void WallpaperManager::Observe(int type,
@@ -355,7 +369,7 @@ void WallpaperManager::Observe(int type,
void WallpaperManager::RemoveUserWallpaperInfo(const std::string& email) {
PrefService* prefs = g_browser_process->local_state();
DictionaryPrefUpdate prefs_wallpapers_update(prefs,
- UserManager::kUserWallpapersProperties);
+ kUserWallpapersProperties);
prefs_wallpapers_update->RemoveWithoutPathExpansion(email, NULL);
bool new_wallpaper_ui_disabled = CommandLine::ForCurrentProcess()->
@@ -412,7 +426,7 @@ void WallpaperManager::ResizeAndSaveWallpaper(const UserImage& wallpaper,
gfx::Size(resized_width, resized_height));
scoped_refptr<base::RefCountedBytes> data = new base::RefCountedBytes();
- // Uses simple jpeg encoder to encode image on worker pool. So we do not block
+ // Uses simple JPG encoder to encode image on worker pool so we do not block
// chrome shutdown on image encoding.
SimpleJpegEncoder* jpeg_encoder = new SimpleJpegEncoder(
data, *(resized_image.bitmap()));
@@ -524,8 +538,7 @@ void WallpaperManager::SetUserWallpaperProperties(const std::string& email,
return;
PrefService* local_state = g_browser_process->local_state();
- DictionaryPrefUpdate wallpaper_update(local_state,
- UserManager::kUserWallpapersProperties);
+ DictionaryPrefUpdate wallpaper_update(local_state, kUserWallpapersProperties);
base::DictionaryValue* wallpaper_properties = new base::DictionaryValue();
wallpaper_properties->Set(kWallpaperTypeNodeName,
@@ -711,7 +724,7 @@ void WallpaperManager::BatchUpdateWallpaper() {
// TODO(bshe): Notify lock screen, wallpaper picker UI to update wallpaper
// as well.
if (user_manager->IsUserLoggedIn() &&
- email == user_manager->GetLoggedInUser().email()) {
+ email == user_manager->GetLoggedInUser()->email()) {
SetUserWallpaper(email);
} else if (show_users &&
email == last_selected_user_) {
@@ -799,18 +812,15 @@ void WallpaperManager::DeleteWallpaperInList(
void WallpaperManager::DeleteUserWallpapers(const std::string& email) {
std::vector<FilePath> file_to_remove;
// Remove small user wallpaper.
- FilePath wallpaper_path = WallpaperManager::Get()->
- GetWallpaperPathForUser(email, true);
+ FilePath wallpaper_path = GetWallpaperPathForUser(email, true);
file_to_remove.push_back(wallpaper_path);
// Remove large user wallpaper.
- wallpaper_path = WallpaperManager::Get()->
- GetWallpaperPathForUser(email, false);
+ wallpaper_path = GetWallpaperPathForUser(email, false);
file_to_remove.push_back(wallpaper_path);
// Remove original user wallpaper.
- wallpaper_path = WallpaperManager::Get()->
- GetOriginalWallpaperPathForUser(email);
+ wallpaper_path = GetOriginalWallpaperPathForUser(email);
file_to_remove.push_back(wallpaper_path);
base::WorkerPool::PostTask(
@@ -907,7 +917,7 @@ void WallpaperManager::GetUserWallpaperProperties(const std::string& email,
// Override with values found in local store, if any.
if (!email.empty()) {
const DictionaryValue* user_wallpapers = g_browser_process->local_state()->
- GetDictionary(UserManager::kUserWallpapersProperties);
+ GetDictionary(kUserWallpapersProperties);
const base::DictionaryValue* wallpaper_properties;
if (user_wallpapers->GetDictionaryWithoutPathExpansion(
email,
@@ -985,12 +995,52 @@ void WallpaperManager::GetCustomWallpaperInternal(const std::string& email,
base::Unretained(this), email, new_info, update_wallpaper));
}
+void WallpaperManager::MigrateWallpaperData(const UserList& users) {
+ PrefService* local_state = g_browser_process->local_state();
+ if (local_state) {
+ const DictionaryValue* user_wallpapers =
+ local_state->GetDictionary(kUserWallpapers);
+ int index;
+ const DictionaryValue* new_user_wallpapers =
+ local_state->GetDictionary(kUserWallpapersProperties);
+ if (new_user_wallpapers->empty()) {
+ for (UserList::const_iterator it = users.begin();
+ it != users.end();
+ ++it) {
+ std::string username = (*it)->email();
+ if (user_wallpapers->GetIntegerWithoutPathExpansion(
+ username, &index)) {
+ DictionaryPrefUpdate prefs_wallpapers_update(
+ local_state, kUserWallpapers);
+ prefs_wallpapers_update->RemoveWithoutPathExpansion(username, NULL);
+ SetUserWallpaperProperties(username, User::DEFAULT, index, true);
+ } else {
+ // Before M20, wallpaper index is not saved into LocalState unless
+ // user specifically sets a wallpaper. After M20, the default
+ // wallpaper index is saved to LocalState as soon as a new user login.
+ // When migrating wallpaper index from M20 to M21, we only migrate
+ // data that is in LocalState. This cause a problem when users login
+ // on a M20 device and then update the device to M21. The default
+ // wallpaper index failed to migrate because it was not saved into
+ // LocalState. Then we assume that all users have index saved in
+ // LocalState in M21. This is not true and it results an empty
+ // wallpaper for those users as described in cr/130685. So here we use
+ // default wallpaper for users that exist in user list but does not
+ // have an index saved in LocalState.
+ SetUserWallpaperProperties(
+ username, User::DEFAULT, ash::GetDefaultWallpaperIndex(), true);
+ }
+ }
+ }
+ }
+}
+
void WallpaperManager::MigrateBuiltInWallpaper(const std::string& email) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!email.empty() && UserManager::Get()->IsKnownUser(email)) {
PrefService* prefs = g_browser_process->local_state();
const DictionaryValue* user_wallpapers = prefs->
- GetDictionary(UserManager::kUserWallpapersProperties);
+ GetDictionary(kUserWallpapersProperties);
const base::DictionaryValue* wallpaper_properties;
User::WallpaperType type;
int index;
@@ -1167,7 +1217,7 @@ bool WallpaperManager::ShouldPersistDataForUser(const std::string& email) {
// case.
if (!user_manager->IsUserLoggedIn())
return true;
- return !(email == user_manager->GetLoggedInUser().email() &&
+ return !(email == user_manager->GetLoggedInUser()->email() &&
user_manager->IsCurrentUserEphemeral());
}
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h
index ae2b90d..378fdaa 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/wallpaper_manager.h
@@ -62,6 +62,13 @@ class WallpaperManager: public system::TimezoneSettings::Observer,
// added after PowerManagerClient initialized.
void AddObservers();
+ // Migrate the old wallpaper index to a new wallpaper structure for all users
+ // in |users|.
+ // The new wallpaper structure is:
+ // { WallpaperType: DAILY|CUSTOMIZED|DEFAULT,
+ // index: index of the default wallpapers }
+ void MigrateWallpaperData(const UserList& users);
+
// Loads wallpaper asynchronously if the current wallpaper is not the
// wallpaper of logged in user.
void EnsureLoggedInUserWallpaperLoaded();
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.cc b/chrome/browser/chromeos/login/webui_screen_locker.cc
index 0dd129f..7c03cf5 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/webui_screen_locker.cc
@@ -60,7 +60,7 @@ void WebUIScreenLocker::LockScreen(bool unlock_on_input) {
lock_window->Grab();
// User list consisting of a single logged-in user.
- UserList users(1, &chromeos::UserManager::Get()->GetLoggedInUser());
+ UserList users(1, chromeos::UserManager::Get()->GetLoggedInUser());
login_display_.reset(new WebUILoginDisplay(this));
login_display_->set_background_bounds(bounds);
login_display_->set_parent_window(GetNativeWindow());
diff --git a/chrome/browser/chromeos/power/power_button_observer.cc b/chrome/browser/chromeos/power/power_button_observer.cc
index 173fbfc..9f00bd6 100644
--- a/chrome/browser/chromeos/power/power_button_observer.cc
+++ b/chrome/browser/chromeos/power/power_button_observer.cc
@@ -25,7 +25,7 @@ ash::user::LoginStatus GetCurrentLoginStatus() {
if (!user_manager->IsUserLoggedIn())
return ash::user::LOGGED_IN_NONE;
- if (user_manager->GetLoggedInUser().is_guest())
+ if (user_manager->GetLoggedInUser()->is_guest())
return ash::user::LOGGED_IN_GUEST;
return ash::user::LOGGED_IN_USER;
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index f8fed06..287ccca 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -252,15 +252,15 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
}
virtual const string16 GetUserDisplayName() const OVERRIDE {
- return UserManager::Get()->GetLoggedInUser().GetDisplayName();
+ return UserManager::Get()->GetLoggedInUser()->GetDisplayName();
}
virtual const std::string GetUserEmail() const OVERRIDE {
- return UserManager::Get()->GetLoggedInUser().display_email();
+ return UserManager::Get()->GetLoggedInUser()->display_email();
}
virtual const gfx::ImageSkia& GetUserImage() const OVERRIDE {
- return UserManager::Get()->GetLoggedInUser().image();
+ return UserManager::Get()->GetLoggedInUser()->image();
}
virtual ash::user::LoginStatus GetUserLoginStatus() const OVERRIDE {
diff --git a/chrome/browser/chromeos/system/drm_settings.cc b/chrome/browser/chromeos/system/drm_settings.cc
index adb7330..1b83806 100644
--- a/chrome/browser/chromeos/system/drm_settings.cc
+++ b/chrome/browser/chromeos/system/drm_settings.cc
@@ -111,10 +111,10 @@ void ToggleDrm(bool enable) {
// The user email address is included in the hash to keep the identifier
// from being the same across users.
- std::string email = user_manager->GetLoggedInUser().email();
+ std::string email = user_manager->GetLoggedInUser()->email();
// If there is no real user then there's nothing to do here.
- if (email.length() == 0) {
- LOG(WARNING) << "Unexpected 0 length user email.";
+ if (email.empty()) {
+ LOG(WARNING) << "Unexpected empty user email.";
return;
}
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index ca8b4d0..445ca3a 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -176,7 +176,7 @@ scoped_ptr<UserCloudPolicyManager>
// Don't wait for a policy fetch if there's no logged in user.
if (chromeos::UserManager::Get()->IsUserLoggedIn()) {
std::string email =
- chromeos::UserManager::Get()->GetLoggedInUser().email();
+ chromeos::UserManager::Get()->GetLoggedInUser()->email();
wait_for_policy_fetch =
GetUserAffiliation(email) == USER_AFFILIATION_MANAGED;
}
diff --git a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
index f92b7da..e91259b 100644
--- a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc
@@ -286,7 +286,7 @@ void UserCloudPolicyStoreChromeOS::Validate(
scoped_ptr<UserCloudPolicyValidator> validator =
CreateValidator(policy.Pass(), callback);
validator->ValidateUsername(
- chromeos::UserManager::Get()->GetLoggedInUser().email());
+ chromeos::UserManager::Get()->GetLoggedInUser()->email());
// TODO(mnissler): Do a signature check here as well. The key is stored by
// session_manager in the root-owned cryptohome area, which is currently
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 5b4153b..e1121b453 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -97,6 +97,7 @@
#include "chrome/browser/chromeos/audio/audio_handler.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/display/display_preferences.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -198,6 +199,7 @@ void RegisterLocalState(PrefService* local_state) {
chromeos::ProxyConfigServiceImpl::RegisterPrefs(local_state);
chromeos::RegisterDisplayLocalStatePrefs(local_state);
chromeos::ServicesCustomizationDocument::RegisterPrefs(local_state);
+ chromeos::UserImageManager::RegisterPrefs(local_state);
chromeos::UserManager::RegisterPrefs(local_state);
chromeos::WallpaperManager::RegisterPrefs(local_state);
chromeos::WizardController::RegisterPrefs(local_state);
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 8b1f198..6c71632 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -728,8 +728,7 @@ void SigninScreenHandler::SendUserList(bool animated) {
std::string owner;
chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
bool is_owner = (email == owner);
- bool signed_in = UserManager::Get()->IsUserLoggedIn() &&
- email == UserManager::Get()->GetLoggedInUser().email();
+ bool signed_in = *it == UserManager::Get()->GetLoggedInUser();
if (non_owner_count < max_non_owner_users || is_owner) {
DictionaryValue* user_dict = new DictionaryValue();
diff --git a/chrome/browser/ui/webui/feedback_ui.cc b/chrome/browser/ui/webui/feedback_ui.cc
index ff84057..7b1ec4b 100644
--- a/chrome/browser/ui/webui/feedback_ui.cc
+++ b/chrome/browser/ui/webui/feedback_ui.cc
@@ -102,7 +102,7 @@ std::string GetUserEmail() {
if (!manager)
return std::string();
else
- return manager->GetLoggedInUser().display_email();
+ return manager->GetLoggedInUser()->display_email();
}
bool ScreenshotDriveTimestampComp(const drive::DriveEntryProto& entry1,
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc
index 374f2ee..0d24f59 100644
--- a/chrome/browser/ui/webui/help/help_handler.cc
+++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -87,7 +87,7 @@ bool CanChangeReleaseChannel() {
return false;
// Get the currently logged in user and strip the domain part only.
std::string domain = "";
- std::string user = chromeos::UserManager::Get()->GetLoggedInUser().email();
+ std::string user = chromeos::UserManager::Get()->GetLoggedInUser()->email();
size_t at_pos = user.find('@');
if (at_pos != std::string::npos && at_pos + 1 < user.length())
domain = user.substr(user.find('@') + 1);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 67e5116..e1ceea1 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -378,22 +378,20 @@ void BrowserOptionsHandler::GetLocalizedValues(DictionaryValue* values) {
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
#if defined(OS_CHROMEOS)
- values->SetString("username",
- chromeos::UserManager::Get()->IsUserLoggedIn() ?
- chromeos::UserManager::Get()->GetLoggedInUser().email() :
- std::string());
-
- values->SetString(
- "factoryResetWarning",
- l10n_util::GetStringFUTF16(
- IDS_OPTIONS_FACTORY_RESET_WARNING,
- l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
-
- values->SetString(
- "factoryResetDescription",
- l10n_util::GetStringFUTF16(
- IDS_OPTIONS_FACTORY_RESET_DESCRIPTION,
- l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
+ const chromeos::User* user = chromeos::UserManager::Get()->GetLoggedInUser();
+ values->SetString("username", user ? user->email() : std::string());
+
+ values->SetString(
+ "factoryResetWarning",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_FACTORY_RESET_WARNING,
+ l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
+
+ values->SetString(
+ "factoryResetDescription",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_FACTORY_RESET_DESCRIPTION,
+ l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
#endif
// Pass along sync status early so it will be available during page init.
@@ -1022,7 +1020,7 @@ void BrowserOptionsHandler::ThemesSetGTK(const ListValue* args) {
#if defined(OS_CHROMEOS)
void BrowserOptionsHandler::UpdateAccountPicture() {
- std::string email = chromeos::UserManager::Get()->GetLoggedInUser().email();
+ std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
if (!email.empty()) {
web_ui()->CallJavascriptFunction("BrowserOptions.updateAccountPicture");
base::StringValue email_value(email);
diff --git a/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
index 357d60f..06ebe11 100644
--- a/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
@@ -15,6 +15,7 @@
#include "chrome/browser/chromeos/login/camera_detector.h"
#include "chrome/browser/chromeos/login/default_user_images.h"
#include "chrome/browser/chromeos/login/user_image.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/options/take_photo_dialog.h"
#include "chrome/browser/ui/browser_finder.h"
@@ -239,21 +240,21 @@ void ChangePictureOptionsHandler::HandlePageShown(const base::ListValue* args) {
}
void ChangePictureOptionsHandler::SendSelectedImage() {
- const User& user = UserManager::Get()->GetLoggedInUser();
- DCHECK(!user.email().empty());
+ const User* user = UserManager::Get()->GetLoggedInUser();
+ DCHECK(!user->email().empty());
- previous_image_index_ = user.image_index();
+ previous_image_index_ = user->image_index();
switch (previous_image_index_) {
case User::kExternalImageIndex: {
// User has image from camera/file, record it and add to the image list.
- previous_image_ = user.image();
+ previous_image_ = user->image();
previous_image_data_url_ = web_ui_util::GetImageDataUrl(previous_image_);
web_ui()->CallJavascriptFunction("ChangePictureOptions.setOldImage");
break;
}
case User::kProfileImageIndex: {
// User has his/her Profile image as the current image.
- SendProfileImage(user.image(), true);
+ SendProfileImage(user->image(), true);
break;
}
default: {
@@ -282,15 +283,16 @@ void ChangePictureOptionsHandler::SendProfileImage(const gfx::ImageSkia& image,
}
void ChangePictureOptionsHandler::UpdateProfileImage() {
- UserManager* user_manager = UserManager::Get();
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
// If we have a downloaded profile image and haven't sent it in
// |SendSelectedImage|, send it now (without selecting).
if (previous_image_index_ != User::kProfileImageIndex &&
- !user_manager->DownloadedProfileImage().isNull())
- SendProfileImage(user_manager->DownloadedProfileImage(), false);
+ !user_image_manager->DownloadedProfileImage().isNull())
+ SendProfileImage(user_image_manager->DownloadedProfileImage(), false);
- user_manager->DownloadProfileImage(kProfileDownloadReason);
+ user_image_manager->DownloadProfileImage(kProfileDownloadReason);
}
void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) {
@@ -303,8 +305,9 @@ void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) {
}
DCHECK(!image_url.empty());
- UserManager* user_manager = UserManager::Get();
- const User& user = user_manager->GetLoggedInUser();
+ const User* user = UserManager::Get()->GetLoggedInUser();
+ UserImageManager* user_image_manager =
+ UserManager::Get()->GetUserImageManager();
int image_index = User::kInvalidImageIndex;
bool waiting_for_camera_photo = false;
@@ -318,13 +321,13 @@ void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) {
if (previous_image_index_ == User::kExternalImageIndex) {
DCHECK(!previous_image_.isNull());
- user_manager->SaveUserImage(user.email(),
- UserImage::CreateAndEncode(previous_image_));
+ user_image_manager->SaveUserImage(
+ user->email(), UserImage::CreateAndEncode(previous_image_));
} else {
DCHECK(previous_image_index_ >= 0 &&
previous_image_index_ < kFirstDefaultImageIndex);
- user_manager->SaveUserDefaultImageIndex(user.email(),
- previous_image_index_);
+ user_image_manager->SaveUserDefaultImageIndex(
+ user->email(), previous_image_index_);
}
UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
@@ -333,7 +336,7 @@ void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) {
VLOG(1) << "Selected old user image";
} else if (IsDefaultImageUrl(image_url, &image_index)) {
// One of the default user images.
- user_manager->SaveUserDefaultImageIndex(user.email(), image_index);
+ user_image_manager->SaveUserDefaultImageIndex(user->email(), image_index);
UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
GetDefaultImageHistogramValue(image_index),
@@ -350,7 +353,7 @@ void ChangePictureOptionsHandler::HandleSelectImage(const ListValue* args) {
}
} else {
// Profile image selected. Could be previous (old) user image.
- user_manager->SaveUserImageFromProfileImage(user.email());
+ user_image_manager->SaveUserImageFromProfileImage(user->email());
if (previous_image_index_ == User::kProfileImageIndex) {
UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
@@ -374,8 +377,8 @@ void ChangePictureOptionsHandler::FileSelected(const FilePath& path,
int index,
void* params) {
UserManager* user_manager = UserManager::Get();
- user_manager->SaveUserImageFromFile(user_manager->GetLoggedInUser().email(),
- path);
+ user_manager->GetUserImageManager()->SaveUserImageFromFile(
+ user_manager->GetLoggedInUser()->email(), path);
UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
kHistogramImageFromFile,
kHistogramImagesCount);
@@ -386,8 +389,9 @@ void ChangePictureOptionsHandler::OnPhotoAccepted(const gfx::ImageSkia& photo) {
UserManager* user_manager = UserManager::Get();
// TODO(ivankr): once old camera UI is gone, there's always raw data in
// |image_decoder_|, pass UserImage and user it instead.
- user_manager->SaveUserImage(user_manager->GetLoggedInUser().email(),
- UserImage::CreateAndEncode(photo));
+ user_manager->GetUserImageManager()->SaveUserImage(
+ user_manager->GetLoggedInUser()->email(),
+ UserImage::CreateAndEncode(photo));
UMA_HISTOGRAM_ENUMERATION("UserImage.ChangeChoice",
kHistogramImageFromCamera,
kHistogramImagesCount);
diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
index b943376..6abee13 100644
--- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc
@@ -48,7 +48,7 @@ bool IsSettingOwnerOnly(const std::string& pref) {
bool IsLoggedInOwner(const std::string& username) {
UserManager* user_manager = UserManager::Get();
return user_manager->IsCurrentUserOwner() &&
- user_manager->GetLoggedInUser().email() == username;
+ user_manager->GetLoggedInUser()->email() == username;
}
// Creates a user info dictionary to be stored in the |ListValue| that is
diff --git a/chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.cc
index 4d76f8f..64ed143 100644
--- a/chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/set_wallpaper_options_handler.cc
@@ -106,7 +106,7 @@ void SetWallpaperOptionsHandler::FileSelected(const FilePath& path,
// Default wallpaper layout is CENTER_CROPPED.
WallpaperManager::Get()->SetUserWallpaperFromFile(
- user_manager->GetLoggedInUser().email(), path, ash::CENTER_CROPPED,
+ user_manager->GetLoggedInUser()->email(), path, ash::CENTER_CROPPED,
weak_factory_.GetWeakPtr());
web_ui()->CallJavascriptFunction("SetWallpaperOptions.didSelectFile");
}
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index 9eebb59..9f96b37 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -322,9 +322,9 @@ base::DictionaryValue* PolicyUIHandler::GetStatusData() {
results->SetString("userLastFetchTime", GetLastFetchTime(user_subsystem));
#if defined(OS_CHROMEOS)
- const chromeos::User& user =
+ const chromeos::User* user =
chromeos::UserManager::Get()->GetLoggedInUser();
- results->SetString("user", ASCIIToUTF16(user.email()));
+ results->SetString("user", ASCIIToUTF16(user->email()));
#else
results->SetString("user", string16());
#endif
diff --git a/chrome/browser/ui/webui/web_ui_util.cc b/chrome/browser/ui/webui/web_ui_util.cc
index 08614d3..2d43279 100644
--- a/chrome/browser/ui/webui/web_ui_util.cc
+++ b/chrome/browser/ui/webui/web_ui_util.cc
@@ -17,6 +17,8 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
+#include "base/debug/trace_event.h"
+
namespace {
struct ScaleFactorMap {
@@ -34,6 +36,8 @@ const ScaleFactorMap kScaleFactorMap[] = {
namespace web_ui_util {
std::string GetImageDataUrl(const gfx::ImageSkia& image) {
+ TRACE_EVENT2("oobe", "GetImageDataUrl",
+ "width", image.width(), "height", image.height());
std::vector<unsigned char> output;
gfx::PNGCodec::EncodeBGRASkBitmap(*image.bitmap(), false, &output);
std::string str_url;
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 6a76868..ec40bef 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -460,6 +460,10 @@
'browser/chromeos/login/user_image.h',
'browser/chromeos/login/user_image_loader.cc',
'browser/chromeos/login/user_image_loader.h',
+ 'browser/chromeos/login/user_image_manager.h',
+ 'browser/chromeos/login/user_image_manager.cc',
+ 'browser/chromeos/login/user_image_manager_impl.cc',
+ 'browser/chromeos/login/user_image_manager_impl.h',
'browser/chromeos/login/user_image_screen.cc',
'browser/chromeos/login/user_image_screen.h',
'browser/chromeos/login/user_image_screen_actor.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 59bb895..5f75c2f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -109,6 +109,8 @@
'browser/chromeos/login/mock_login_utils.h',
'browser/chromeos/login/mock_url_fetchers.cc',
'browser/chromeos/login/mock_url_fetchers.h',
+ 'browser/chromeos/login/mock_user_image_manager.cc',
+ 'browser/chromeos/login/mock_user_image_manager.h',
'browser/chromeos/login/mock_user_manager.cc',
'browser/chromeos/login/mock_user_manager.h',
'browser/chromeos/settings/device_settings_test_helper.cc',
@@ -2827,6 +2829,7 @@
'browser/chromeos/login/screen_locker_tester.cc',
'browser/chromeos/login/screen_locker_tester.h',
'browser/chromeos/login/update_screen_browsertest.cc',
+ 'browser/chromeos/login/user_image_manager_browsertest.cc',
'browser/chromeos/login/wizard_controller_browsertest.cc',
'browser/chromeos/login/wizard_in_process_browser_test.cc',
'browser/chromeos/login/wizard_in_process_browser_test.h',