blob: c699a6030554213869341573525a205f803e8b8d [file] [log] [blame]
// Copyright 2013 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_sync_observer.h"
#include "base/bind.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/default_user_images.h"
#include "chrome/browser/chromeos/login/screens/user_image_screen.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_image_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
namespace chromeos {
namespace {
// A dictionary containing info about user image.
const char kUserImageInfo[] = "user_image_info";
// Path to value with image index.
const char kImageIndex[] = "image_index";
bool IsIndexSupported(int index) {
return (index >= kFirstDefaultImageIndex && index < kDefaultImagesCount) ||
(index == User::kProfileImageIndex);
}
Profile* GetUserProfile() {
ProfileManager* profile_manager = g_browser_process->profile_manager();
if (!profile_manager || !profile_manager->IsLoggedIn())
return NULL;
base::FilePath profile_path = profile_manager->user_data_dir().Append(
profile_manager->GetInitialProfileDir());
return profile_manager->GetProfileByPath(profile_path);
}
} // anonymous namespace
UserImageSyncObserver::Observer::~Observer() {}
UserImageSyncObserver::UserImageSyncObserver(const User* user)
: user_(user),
prefs_(NULL),
is_synced_(false),
local_image_changed_(false) {
notification_registrar_.reset(new content::NotificationRegistrar);
notification_registrar_->Add(this,
chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
content::NotificationService::AllSources());
Profile* profile = GetUserProfile();
if (profile) {
OnProfileGained(profile);
} else {
notification_registrar_->Add(this,
chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
content::NotificationService::AllSources());
}
}
UserImageSyncObserver::~UserImageSyncObserver() {
if (!is_synced_ && prefs_)
prefs_->RemoveObserver(this);
if (pref_change_registrar_)
pref_change_registrar_->RemoveAll();
}
// static
void UserImageSyncObserver::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry_) {
registry_->RegisterDictionaryPref(
kUserImageInfo,
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
}
void UserImageSyncObserver::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void UserImageSyncObserver::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void UserImageSyncObserver::OnProfileGained(Profile* profile) {
prefs_ = PrefServiceSyncable::FromProfile(profile);
pref_change_registrar_.reset(new PrefChangeRegistrar);
pref_change_registrar_->Init(prefs_);
pref_change_registrar_->Add(kUserImageInfo,
base::Bind(&UserImageSyncObserver::OnPreferenceChanged,
base::Unretained(this)));
is_synced_ = prefs_->IsPrioritySyncing();
if (!is_synced_) {
prefs_->AddObserver(this);
} else {
OnInitialSync();
}
}
void UserImageSyncObserver::OnInitialSync() {
int synced_index;
bool local_image_updated = false;
if (!GetSyncedImageIndex(&synced_index) || local_image_changed_) {
UpdateSyncedImageFromLocal();
} else if (IsIndexSupported(synced_index) && CanUpdateLocalImageNow()) {
UpdateLocalImageFromSynced();
local_image_updated = true;
}
FOR_EACH_OBSERVER(UserImageSyncObserver::Observer, observer_list_,
OnInitialSync(local_image_updated));
}
void UserImageSyncObserver::OnPreferenceChanged(const std::string& pref_name) {
// OnPreferenceChanged can be called before OnIsSyncingChanged.
if (!is_synced_) {
is_synced_ = true;
prefs_->RemoveObserver(this);
OnInitialSync();
} else if (CanUpdateLocalImageNow()) {
UpdateLocalImageFromSynced();
}
}
void UserImageSyncObserver::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
if (type == chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) {
Profile* profile = content::Details<Profile>(details).ptr();
if (GetUserProfile() != profile)
return;
notification_registrar_->Remove(
this,
chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
content::NotificationService::AllSources());
OnProfileGained(profile);
} else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
if (is_synced_)
UpdateSyncedImageFromLocal();
else
local_image_changed_ = true;
} else {
NOTREACHED();
}
}
void UserImageSyncObserver::OnIsSyncingChanged() {
is_synced_ = prefs_->IsPrioritySyncing();
if (is_synced_) {
prefs_->RemoveObserver(this);
OnInitialSync();
}
}
void UserImageSyncObserver::UpdateSyncedImageFromLocal() {
int local_index = user_->image_index();
if (!IsIndexSupported(local_index)) {
local_index = User::kInvalidImageIndex;
}
int synced_index;
if (GetSyncedImageIndex(&synced_index) && (synced_index == local_index))
return;
DictionaryPrefUpdate update(prefs_, kUserImageInfo);
base::DictionaryValue* dict = update.Get();
dict->SetInteger(kImageIndex, local_index);
VLOG(1) << "Saved avatar index " << local_index << " to sync.";
}
void UserImageSyncObserver::UpdateLocalImageFromSynced() {
int synced_index;
GetSyncedImageIndex(&synced_index);
int local_index = user_->image_index();
if ((synced_index == local_index) || !IsIndexSupported(synced_index))
return;
UserImageManager* image_manager =
UserManager::Get()->GetUserImageManager(user_->email());
if (synced_index == User::kProfileImageIndex) {
image_manager->SaveUserImageFromProfileImage();
} else {
image_manager->SaveUserDefaultImageIndex(synced_index);
}
VLOG(1) << "Loaded avatar index " << synced_index << " from sync.";
}
bool UserImageSyncObserver::GetSyncedImageIndex(int* index) {
*index = User::kInvalidImageIndex;
const base::DictionaryValue* dict = prefs_->GetDictionary(kUserImageInfo);
return dict && dict->GetInteger(kImageIndex, index);
}
bool UserImageSyncObserver::CanUpdateLocalImageNow() {
if (WizardController* wizard_controller =
WizardController::default_controller()) {
UserImageScreen* screen = wizard_controller->GetUserImageScreen();
if (wizard_controller->current_screen() == screen) {
if (screen->user_selected_image())
return false;
}
}
return true;
}
} // namespace chromeos