Home | History | Annotate | Download | only in avatar
      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.
      4 
      5 #include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h"
      6 
      7 #include "base/bind.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"
     23 
     24 namespace chromeos {
     25 namespace {
     26 
     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";
     31 
     32 bool IsIndexSupported(int index) {
     33   return (index >= user_manager::kFirstDefaultImageIndex &&
     34           index < user_manager::kDefaultImagesCount) ||
     35          (index == user_manager::User::USER_IMAGE_PROFILE);
     36 }
     37 
     38 }  // anonymous namespace
     39 
     40 UserImageSyncObserver::Observer::~Observer() {}
     41 
     42 UserImageSyncObserver::UserImageSyncObserver(const user_manager::User* user)
     43     : user_(user),
     44       prefs_(NULL),
     45       is_synced_(false),
     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);
     53   } else {
     54     notification_registrar_->Add(this,
     55         chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
     56         content::NotificationService::AllSources());
     57   }
     58 }
     59 
     60 UserImageSyncObserver::~UserImageSyncObserver() {
     61   if (!is_synced_ && prefs_)
     62     prefs_->RemoveObserver(this);
     63   if (pref_change_registrar_)
     64     pref_change_registrar_->RemoveAll();
     65 }
     66 
     67 // static
     68 void UserImageSyncObserver::RegisterProfilePrefs(
     69     user_prefs::PrefRegistrySyncable* registry_) {
     70   registry_->RegisterDictionaryPref(
     71       kUserImageInfo,
     72       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
     73 }
     74 
     75 void UserImageSyncObserver::AddObserver(Observer* observer) {
     76   observer_list_.AddObserver(observer);
     77 }
     78 
     79 void UserImageSyncObserver::RemoveObserver(Observer* observer) {
     80   observer_list_.RemoveObserver(observer);
     81 }
     82 
     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();
     91   if (!is_synced_) {
     92     prefs_->AddObserver(this);
     93   } else {
     94     OnInitialSync();
     95   }
     96 }
     97 
     98 void UserImageSyncObserver::OnInitialSync() {
     99   int synced_index;
    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;
    106   }
    107   FOR_EACH_OBSERVER(UserImageSyncObserver::Observer, observer_list_,
    108       OnInitialSync(local_image_updated));
    109 }
    110 
    111 void UserImageSyncObserver::OnPreferenceChanged(const std::string& pref_name) {
    112   // OnPreferenceChanged can be called before OnIsSyncingChanged.
    113   if (!is_synced_) {
    114     is_synced_ = true;
    115     prefs_->RemoveObserver(this);
    116     OnInitialSync();
    117   } else if (CanUpdateLocalImageNow()) {
    118     UpdateLocalImageFromSynced();
    119   }
    120 }
    121 
    122 void UserImageSyncObserver::Observe(
    123     int type,
    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(
    129           this,
    130           chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
    131           content::NotificationService::AllSources());
    132       OnProfileGained(profile);
    133     }
    134   } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
    135     if (is_synced_)
    136       UpdateSyncedImageFromLocal();
    137     else
    138       local_image_changed_ = true;
    139   } else {
    140     NOTREACHED();
    141   }
    142 }
    143 
    144 void UserImageSyncObserver::OnIsSyncingChanged() {
    145   is_synced_ = prefs_->IsPrioritySyncing();
    146   if (is_synced_) {
    147     prefs_->RemoveObserver(this);
    148     OnInitialSync();
    149   }
    150 }
    151 
    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;
    156   }
    157   int synced_index;
    158   if (GetSyncedImageIndex(&synced_index) && (synced_index == local_index))
    159     return;
    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.";
    164 }
    165 
    166 void UserImageSyncObserver::UpdateLocalImageFromSynced() {
    167   int synced_index;
    168   GetSyncedImageIndex(&synced_index);
    169   int local_index = user_->image_index();
    170   if ((synced_index == local_index) || !IsIndexSupported(synced_index))
    171     return;
    172   UserImageManager* image_manager =
    173       ChromeUserManager::Get()->GetUserImageManager(user_->email());
    174   if (synced_index == user_manager::User::USER_IMAGE_PROFILE) {
    175     image_manager->SaveUserImageFromProfileImage();
    176   } else {
    177     image_manager->SaveUserDefaultImageIndex(synced_index);
    178   }
    179   VLOG(1) << "Loaded avatar index " << synced_index << " from sync.";
    180 }
    181 
    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);
    186 }
    187 
    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())
    194         return false;
    195     }
    196   }
    197   return true;
    198 }
    199 
    200 }  // namespace chromeos
    201 
    202