1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h"
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/bind.h"
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/prefs/pref_change_registrar.h"
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/chromeos/login/screens/user_image_screen.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/chromeos/login/wizard_controller.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/chromeos/profiles/profile_helper.h"
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/prefs/pref_service_syncable.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/pref_names.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_manager/user.h"
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_manager/user_image/default_user_images.h"
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h"
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_registrar.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_service.h"
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace chromeos {
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace {
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// A dictionary containing info about user image.
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const char kUserImageInfo[] = "user_image_info";
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Path to value with image index.
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const char kImageIndex[] = "image_index";
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool IsIndexSupported(int index) {
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return (index >= user_manager::kFirstDefaultImageIndex &&
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          index < user_manager::kDefaultImagesCount) ||
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         (index == user_manager::User::USER_IMAGE_PROFILE);
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // anonymous namespace
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)UserImageSyncObserver::Observer::~Observer() {}
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)UserImageSyncObserver::UserImageSyncObserver(const user_manager::User* user)
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : user_(user),
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      prefs_(NULL),
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      is_synced_(false),
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      local_image_changed_(false) {
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  notification_registrar_.reset(new content::NotificationRegistrar);
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  notification_registrar_->Add(this,
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      content::NotificationService::AllSources());
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (Profile* profile = ProfileHelper::Get()->GetProfileByUser(user)) {
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OnProfileGained(profile);
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    notification_registrar_->Add(this,
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        content::NotificationService::AllSources());
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)UserImageSyncObserver::~UserImageSyncObserver() {
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!is_synced_ && prefs_)
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    prefs_->RemoveObserver(this);
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (pref_change_registrar_)
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pref_change_registrar_->RemoveAll();
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// static
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::RegisterProfilePrefs(
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry_) {
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  registry_->RegisterDictionaryPref(
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      kUserImageInfo,
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::AddObserver(Observer* observer) {
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_list_.AddObserver(observer);
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::RemoveObserver(Observer* observer) {
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_list_.RemoveObserver(observer);
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::OnProfileGained(Profile* profile) {
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  prefs_ = PrefServiceSyncable::FromProfile(profile);
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pref_change_registrar_.reset(new PrefChangeRegistrar);
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pref_change_registrar_->Init(prefs_);
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pref_change_registrar_->Add(kUserImageInfo,
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&UserImageSyncObserver::OnPreferenceChanged,
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Unretained(this)));
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_synced_ = prefs_->IsPrioritySyncing();
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!is_synced_) {
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    prefs_->AddObserver(this);
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OnInitialSync();
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::OnInitialSync() {
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int synced_index;
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool local_image_updated = false;
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!GetSyncedImageIndex(&synced_index) || local_image_changed_) {
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateSyncedImageFromLocal();
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (IsIndexSupported(synced_index) && CanUpdateLocalImageNow()) {
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateLocalImageFromSynced();
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    local_image_updated = true;
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FOR_EACH_OBSERVER(UserImageSyncObserver::Observer, observer_list_,
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      OnInitialSync(local_image_updated));
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::OnPreferenceChanged(const std::string& pref_name) {
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // OnPreferenceChanged can be called before OnIsSyncingChanged.
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!is_synced_) {
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    is_synced_ = true;
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    prefs_->RemoveObserver(this);
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OnInitialSync();
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (CanUpdateLocalImageNow()) {
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateLocalImageFromSynced();
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::Observe(
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int type,
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const content::NotificationSource& source,
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const content::NotificationDetails& details) {
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (type == chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) {
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (Profile* profile = ProfileHelper::Get()->GetProfileByUser(user_)) {
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      notification_registrar_->Remove(
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          this,
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          content::NotificationService::AllSources());
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      OnProfileGained(profile);
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (is_synced_)
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UpdateSyncedImageFromLocal();
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    else
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      local_image_changed_ = true;
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED();
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::OnIsSyncingChanged() {
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  is_synced_ = prefs_->IsPrioritySyncing();
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (is_synced_) {
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    prefs_->RemoveObserver(this);
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    OnInitialSync();
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::UpdateSyncedImageFromLocal() {
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int local_index = user_->image_index();
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!IsIndexSupported(local_index)) {
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    local_index = user_manager::User::USER_IMAGE_INVALID;
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int synced_index;
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (GetSyncedImageIndex(&synced_index) && (synced_index == local_index))
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DictionaryPrefUpdate update(prefs_, kUserImageInfo);
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = update.Get();
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dict->SetInteger(kImageIndex, local_index);
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "Saved avatar index " << local_index << " to sync.";
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UserImageSyncObserver::UpdateLocalImageFromSynced() {
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int synced_index;
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  GetSyncedImageIndex(&synced_index);
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int local_index = user_->image_index();
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if ((synced_index == local_index) || !IsIndexSupported(synced_index))
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UserImageManager* image_manager =
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ChromeUserManager::Get()->GetUserImageManager(user_->email());
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (synced_index == user_manager::User::USER_IMAGE_PROFILE) {
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    image_manager->SaveUserImageFromProfileImage();
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    image_manager->SaveUserDefaultImageIndex(synced_index);
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "Loaded avatar index " << synced_index << " from sync.";
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool UserImageSyncObserver::GetSyncedImageIndex(int* index) {
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  *index = user_manager::User::USER_IMAGE_INVALID;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* dict = prefs_->GetDictionary(kUserImageInfo);
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return dict && dict->GetInteger(kImageIndex, index);
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool UserImageSyncObserver::CanUpdateLocalImageNow() {
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (WizardController* wizard_controller =
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          WizardController::default_controller()) {
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UserImageScreen* screen = UserImageScreen::Get(wizard_controller);
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (wizard_controller->current_screen() == screen) {
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (screen->user_selected_image())
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return false;
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace chromeos
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
202