1 // Copyright 2014 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/users/avatar/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/chrome_notification_types.h"
11 #include "chrome/browser/chromeos/login/screens/user_image_screen.h"
12 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
13 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
14 #include "chrome/browser/chromeos/login/wizard_controller.h"
15 #include "chrome/browser/chromeos/profiles/profile_helper.h"
16 #include "chrome/browser/prefs/pref_service_syncable.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/user_manager/user.h"
19 #include "components/user_manager/user_image/default_user_images.h"
20 #include "components/user_manager/user_manager.h"
21 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_service.h"
27 // A dictionary containing info about user image.
28 const char kUserImageInfo
[] = "user_image_info";
29 // Path to value with image index.
30 const char kImageIndex
[] = "image_index";
32 bool IsIndexSupported(int index
) {
33 return (index
>= user_manager::kFirstDefaultImageIndex
&&
34 index
< user_manager::kDefaultImagesCount
) ||
35 (index
== user_manager::User::USER_IMAGE_PROFILE
);
38 } // anonymous namespace
40 UserImageSyncObserver::Observer::~Observer() {}
42 UserImageSyncObserver::UserImageSyncObserver(const user_manager::User
* user
)
46 local_image_changed_(false) {
47 notification_registrar_
.reset(new content::NotificationRegistrar
);
48 notification_registrar_
->Add(this,
49 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
,
50 content::NotificationService::AllSources());
51 if (Profile
* profile
= ProfileHelper::Get()->GetProfileByUser(user
)) {
52 OnProfileGained(profile
);
54 notification_registrar_
->Add(this,
55 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
56 content::NotificationService::AllSources());
60 UserImageSyncObserver::~UserImageSyncObserver() {
61 if (!is_synced_
&& prefs_
)
62 prefs_
->RemoveObserver(this);
63 if (pref_change_registrar_
)
64 pref_change_registrar_
->RemoveAll();
68 void UserImageSyncObserver::RegisterProfilePrefs(
69 user_prefs::PrefRegistrySyncable
* registry_
) {
70 registry_
->RegisterDictionaryPref(
72 user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF
);
75 void UserImageSyncObserver::AddObserver(Observer
* observer
) {
76 observer_list_
.AddObserver(observer
);
79 void UserImageSyncObserver::RemoveObserver(Observer
* observer
) {
80 observer_list_
.RemoveObserver(observer
);
83 void UserImageSyncObserver::OnProfileGained(Profile
* profile
) {
84 prefs_
= PrefServiceSyncable::FromProfile(profile
);
85 pref_change_registrar_
.reset(new PrefChangeRegistrar
);
86 pref_change_registrar_
->Init(prefs_
);
87 pref_change_registrar_
->Add(kUserImageInfo
,
88 base::Bind(&UserImageSyncObserver::OnPreferenceChanged
,
89 base::Unretained(this)));
90 is_synced_
= prefs_
->IsPrioritySyncing();
92 prefs_
->AddObserver(this);
98 void UserImageSyncObserver::OnInitialSync() {
100 bool local_image_updated
= false;
101 if (!GetSyncedImageIndex(&synced_index
) || local_image_changed_
) {
102 UpdateSyncedImageFromLocal();
103 } else if (IsIndexSupported(synced_index
) && CanUpdateLocalImageNow()) {
104 UpdateLocalImageFromSynced();
105 local_image_updated
= true;
107 FOR_EACH_OBSERVER(UserImageSyncObserver::Observer
, observer_list_
,
108 OnInitialSync(local_image_updated
));
111 void UserImageSyncObserver::OnPreferenceChanged(const std::string
& pref_name
) {
112 // OnPreferenceChanged can be called before OnIsSyncingChanged.
115 prefs_
->RemoveObserver(this);
117 } else if (CanUpdateLocalImageNow()) {
118 UpdateLocalImageFromSynced();
122 void UserImageSyncObserver::Observe(
124 const content::NotificationSource
& source
,
125 const content::NotificationDetails
& details
) {
126 if (type
== chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
) {
127 if (Profile
* profile
= ProfileHelper::Get()->GetProfileByUser(user_
)) {
128 notification_registrar_
->Remove(
130 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
131 content::NotificationService::AllSources());
132 OnProfileGained(profile
);
134 } else if (type
== chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
) {
136 UpdateSyncedImageFromLocal();
138 local_image_changed_
= true;
144 void UserImageSyncObserver::OnIsSyncingChanged() {
145 is_synced_
= prefs_
->IsPrioritySyncing();
147 prefs_
->RemoveObserver(this);
152 void UserImageSyncObserver::UpdateSyncedImageFromLocal() {
153 int local_index
= user_
->image_index();
154 if (!IsIndexSupported(local_index
)) {
155 local_index
= user_manager::User::USER_IMAGE_INVALID
;
158 if (GetSyncedImageIndex(&synced_index
) && (synced_index
== local_index
))
160 DictionaryPrefUpdate
update(prefs_
, kUserImageInfo
);
161 base::DictionaryValue
* dict
= update
.Get();
162 dict
->SetInteger(kImageIndex
, local_index
);
163 VLOG(1) << "Saved avatar index " << local_index
<< " to sync.";
166 void UserImageSyncObserver::UpdateLocalImageFromSynced() {
168 GetSyncedImageIndex(&synced_index
);
169 int local_index
= user_
->image_index();
170 if ((synced_index
== local_index
) || !IsIndexSupported(synced_index
))
172 UserImageManager
* image_manager
=
173 ChromeUserManager::Get()->GetUserImageManager(user_
->email());
174 if (synced_index
== user_manager::User::USER_IMAGE_PROFILE
) {
175 image_manager
->SaveUserImageFromProfileImage();
177 image_manager
->SaveUserDefaultImageIndex(synced_index
);
179 VLOG(1) << "Loaded avatar index " << synced_index
<< " from sync.";
182 bool UserImageSyncObserver::GetSyncedImageIndex(int* index
) {
183 *index
= user_manager::User::USER_IMAGE_INVALID
;
184 const base::DictionaryValue
* dict
= prefs_
->GetDictionary(kUserImageInfo
);
185 return dict
&& dict
->GetInteger(kImageIndex
, index
);
188 bool UserImageSyncObserver::CanUpdateLocalImageNow() {
189 if (WizardController
* wizard_controller
=
190 WizardController::default_controller()) {
191 UserImageScreen
* screen
= UserImageScreen::Get(wizard_controller
);
192 if (wizard_controller
->current_screen() == screen
) {
193 if (screen
->user_selected_image())
200 } // namespace chromeos