root/chrome/browser/chromeos/login/user_image_sync_observer.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsIndexSupported
  2. GetUserProfile
  3. local_image_changed_
  4. RegisterProfilePrefs
  5. AddObserver
  6. RemoveObserver
  7. OnProfileGained
  8. OnInitialSync
  9. OnPreferenceChanged
  10. OnIsSyncingChanged
  11. UpdateSyncedImageFromLocal
  12. UpdateLocalImageFromSynced
  13. GetSyncedImageIndex
  14. CanUpdateLocalImageNow

// 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


/* [<][>][^][v][top][bottom][index][help] */