1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/login/user_image_sync_observer.h"
8 #include "base/prefs/pref_change_registrar.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/chromeos/login/default_user_images.h"
13 #include "chrome/browser/chromeos/login/screens/user_image_screen.h"
14 #include "chrome/browser/chromeos/login/user.h"
15 #include "chrome/browser/chromeos/login/user_image_manager.h"
16 #include "chrome/browser/chromeos/login/wizard_controller.h"
17 #include "chrome/browser/chromeos/profiles/profile_helper.h"
18 #include "chrome/browser/prefs/pref_service_syncable.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/common/pref_names.h"
22 #include "content/public/browser/notification_registrar.h"
23 #include "content/public/browser/notification_service.h"
28 // A dictionary containing info about user image.
29 const char kUserImageInfo
[] = "user_image_info";
30 // Path to value with image index.
31 const char kImageIndex
[] = "image_index";
33 bool IsIndexSupported(int index
) {
34 return (index
>= kFirstDefaultImageIndex
&& index
< kDefaultImagesCount
) ||
35 (index
== User::kProfileImageIndex
);
38 Profile
* GetUserProfile() {
39 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
40 if (!profile_manager
|| !profile_manager
->IsLoggedIn())
42 base::FilePath profile_path
= profile_manager
->user_data_dir().Append(
43 profile_manager
->GetInitialProfileDir());
44 return profile_manager
->GetProfileByPath(profile_path
);
47 } // anonymous namespace
49 UserImageSyncObserver::Observer::~Observer() {}
51 UserImageSyncObserver::UserImageSyncObserver(const User
* user
)
55 local_image_changed_(false) {
56 notification_registrar_
.reset(new content::NotificationRegistrar
);
57 notification_registrar_
->Add(this,
58 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
,
59 content::NotificationService::AllSources());
60 Profile
* profile
= GetUserProfile();
62 OnProfileGained(profile
);
64 notification_registrar_
->Add(this,
65 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
66 content::NotificationService::AllSources());
70 UserImageSyncObserver::~UserImageSyncObserver() {
71 if (!is_synced_
&& prefs_
)
72 prefs_
->RemoveObserver(this);
73 if (pref_change_registrar_
)
74 pref_change_registrar_
->RemoveAll();
78 void UserImageSyncObserver::RegisterProfilePrefs(
79 user_prefs::PrefRegistrySyncable
* registry_
) {
80 registry_
->RegisterDictionaryPref(
82 user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF
);
85 void UserImageSyncObserver::AddObserver(Observer
* observer
) {
86 observer_list_
.AddObserver(observer
);
89 void UserImageSyncObserver::RemoveObserver(Observer
* observer
) {
90 observer_list_
.RemoveObserver(observer
);
93 void UserImageSyncObserver::OnProfileGained(Profile
* profile
) {
94 prefs_
= PrefServiceSyncable::FromProfile(profile
);
95 pref_change_registrar_
.reset(new PrefChangeRegistrar
);
96 pref_change_registrar_
->Init(prefs_
);
97 pref_change_registrar_
->Add(kUserImageInfo
,
98 base::Bind(&UserImageSyncObserver::OnPreferenceChanged
,
99 base::Unretained(this)));
100 is_synced_
= prefs_
->IsPrioritySyncing();
102 prefs_
->AddObserver(this);
108 void UserImageSyncObserver::OnInitialSync() {
110 bool local_image_updated
= false;
111 if (!GetSyncedImageIndex(&synced_index
) || local_image_changed_
) {
112 UpdateSyncedImageFromLocal();
113 } else if (IsIndexSupported(synced_index
) && CanUpdateLocalImageNow()) {
114 UpdateLocalImageFromSynced();
115 local_image_updated
= true;
117 FOR_EACH_OBSERVER(UserImageSyncObserver::Observer
, observer_list_
,
118 OnInitialSync(local_image_updated
));
121 void UserImageSyncObserver::OnPreferenceChanged(const std::string
& pref_name
) {
122 // OnPreferenceChanged can be called before OnIsSyncingChanged.
125 prefs_
->RemoveObserver(this);
127 } else if (CanUpdateLocalImageNow()) {
128 UpdateLocalImageFromSynced();
132 void UserImageSyncObserver::Observe(
134 const content::NotificationSource
& source
,
135 const content::NotificationDetails
& details
) {
136 if (type
== chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
) {
137 Profile
* profile
= content::Details
<Profile
>(details
).ptr();
138 if (GetUserProfile() != profile
)
140 notification_registrar_
->Remove(
142 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
143 content::NotificationService::AllSources());
144 OnProfileGained(profile
);
145 } else if (type
== chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
) {
147 UpdateSyncedImageFromLocal();
149 local_image_changed_
= true;
155 void UserImageSyncObserver::OnIsSyncingChanged() {
156 is_synced_
= prefs_
->IsPrioritySyncing();
158 prefs_
->RemoveObserver(this);
163 void UserImageSyncObserver::UpdateSyncedImageFromLocal() {
164 int local_index
= user_
->image_index();
165 if (!IsIndexSupported(local_index
)) {
166 local_index
= User::kInvalidImageIndex
;
169 if (GetSyncedImageIndex(&synced_index
) && (synced_index
== local_index
))
171 DictionaryPrefUpdate
update(prefs_
, kUserImageInfo
);
172 base::DictionaryValue
* dict
= update
.Get();
173 dict
->SetInteger(kImageIndex
, local_index
);
174 VLOG(1) << "Saved avatar index " << local_index
<< " to sync.";
177 void UserImageSyncObserver::UpdateLocalImageFromSynced() {
179 GetSyncedImageIndex(&synced_index
);
180 int local_index
= user_
->image_index();
181 if ((synced_index
== local_index
) || !IsIndexSupported(synced_index
))
183 UserImageManager
* image_manager
=
184 UserManager::Get()->GetUserImageManager(user_
->email());
185 if (synced_index
== User::kProfileImageIndex
) {
186 image_manager
->SaveUserImageFromProfileImage();
188 image_manager
->SaveUserDefaultImageIndex(synced_index
);
190 VLOG(1) << "Loaded avatar index " << synced_index
<< " from sync.";
193 bool UserImageSyncObserver::GetSyncedImageIndex(int* index
) {
194 *index
= User::kInvalidImageIndex
;
195 const base::DictionaryValue
* dict
= prefs_
->GetDictionary(kUserImageInfo
);
196 return dict
&& dict
->GetInteger(kImageIndex
, index
);
199 bool UserImageSyncObserver::CanUpdateLocalImageNow() {
200 if (WizardController
* wizard_controller
=
201 WizardController::default_controller()) {
202 UserImageScreen
* screen
= wizard_controller
->GetUserImageScreen();
203 if (wizard_controller
->current_screen() == screen
) {
204 if (screen
->user_selected_image())
211 } // namespace chromeos