| Index: chrome/browser/chromeos/login/user_image_manager_impl.cc
|
| diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
|
| deleted file mode 100644
|
| index 5ead90da988dd2ba95170665ed5b67d77b642c47..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/chromeos/login/user_image_manager_impl.cc
|
| +++ /dev/null
|
| @@ -1,1003 +0,0 @@
|
| -// Copyright (c) 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_manager_impl.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/debug/trace_event.h"
|
| -#include "base/file_util.h"
|
| -#include "base/files/file_path.h"
|
| -#include "base/logging.h"
|
| -#include "base/message_loop/message_loop_proxy.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/path_service.h"
|
| -#include "base/prefs/pref_registry_simple.h"
|
| -#include "base/prefs/pref_service.h"
|
| -#include "base/prefs/scoped_user_pref_update.h"
|
| -#include "base/rand_util.h"
|
| -#include "base/sequenced_task_runner.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/threading/sequenced_worker_pool.h"
|
| -#include "base/time/time.h"
|
| -#include "base/values.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/helper.h"
|
| -#include "chrome/browser/chromeos/login/user_image.h"
|
| -#include "chrome/browser/chromeos/login/user_image_sync_observer.h"
|
| -#include "chrome/browser/chromeos/login/user_manager.h"
|
| -#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
|
| -#include "chrome/browser/profiles/profile_downloader.h"
|
| -#include "chrome/browser/profiles/profile_manager.h"
|
| -#include "chrome/common/chrome_paths.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/notification_service.h"
|
| -#include "policy/policy_constants.h"
|
| -#include "ui/gfx/image/image_skia.h"
|
| -
|
| -namespace chromeos {
|
| -
|
| -namespace {
|
| -
|
| -// A dictionary that maps user_ids to old user image data with images stored in
|
| -// PNG format. Deprecated.
|
| -// TODO(ivankr): remove this const char after migration is gone.
|
| -const char kUserImages[] = "UserImages";
|
| -
|
| -// A dictionary that maps user_ids to user image data with images stored in
|
| -// JPEG format.
|
| -const char kUserImageProperties[] = "user_image_info";
|
| -
|
| -// Names of user image properties.
|
| -const char kImagePathNodeName[] = "path";
|
| -const char kImageIndexNodeName[] = "index";
|
| -const char kImageURLNodeName[] = "url";
|
| -
|
| -// Delay betweeen user login and attempt to update user's profile data.
|
| -const int kProfileDataDownloadDelaySec = 10;
|
| -
|
| -// Interval betweeen retries to update user's profile data.
|
| -const int kProfileDataDownloadRetryIntervalSec = 300;
|
| -
|
| -// Delay betweeen subsequent profile refresh attempts (24 hrs).
|
| -const int kProfileRefreshIntervalSec = 24 * 3600;
|
| -
|
| -const char kSafeImagePathExtension[] = ".jpg";
|
| -
|
| -// Enum for reporting histograms about profile picture download.
|
| -enum ProfileDownloadResult {
|
| - kDownloadSuccessChanged,
|
| - kDownloadSuccess,
|
| - kDownloadFailure,
|
| - kDownloadDefault,
|
| - kDownloadCached,
|
| -
|
| - // Must be the last, convenient count.
|
| - kDownloadResultsCount
|
| -};
|
| -
|
| -// Time histogram prefix for a cached profile image download.
|
| -const char kProfileDownloadCachedTime[] =
|
| - "UserImage.ProfileDownloadTime.Cached";
|
| -// Time histogram prefix for the default profile image download.
|
| -const char kProfileDownloadDefaultTime[] =
|
| - "UserImage.ProfileDownloadTime.Default";
|
| -// Time histogram prefix for a failed profile image download.
|
| -const char kProfileDownloadFailureTime[] =
|
| - "UserImage.ProfileDownloadTime.Failure";
|
| -// Time histogram prefix for a successful profile image download.
|
| -const char kProfileDownloadSuccessTime[] =
|
| - "UserImage.ProfileDownloadTime.Success";
|
| -// Time histogram suffix for a profile image download after login.
|
| -const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
|
| -// Time histogram suffix for a profile image download when the user chooses the
|
| -// profile image but it has not been downloaded yet.
|
| -const char kProfileDownloadReasonProfileImageChosen[] = "ProfileImageChosen";
|
| -// Time histogram suffix for a scheduled profile image download.
|
| -const char kProfileDownloadReasonScheduled[] = "Scheduled";
|
| -// Time histogram suffix for a profile image download retry.
|
| -const char kProfileDownloadReasonRetry[] = "Retry";
|
| -
|
| -static bool g_ignore_profile_data_download_delay_ = false;
|
| -
|
| -// Add a histogram showing the time it takes to download profile image.
|
| -// Separate histograms are reported for each download |reason| and |result|.
|
| -void AddProfileImageTimeHistogram(ProfileDownloadResult result,
|
| - const std::string& download_reason,
|
| - const base::TimeDelta& time_delta) {
|
| - std::string histogram_name;
|
| - switch (result) {
|
| - case kDownloadFailure:
|
| - histogram_name = kProfileDownloadFailureTime;
|
| - break;
|
| - case kDownloadDefault:
|
| - histogram_name = kProfileDownloadDefaultTime;
|
| - break;
|
| - case kDownloadSuccess:
|
| - histogram_name = kProfileDownloadSuccessTime;
|
| - break;
|
| - case kDownloadCached:
|
| - histogram_name = kProfileDownloadCachedTime;
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - if (!download_reason.empty()) {
|
| - histogram_name += ".";
|
| - histogram_name += download_reason;
|
| - }
|
| -
|
| - static const base::TimeDelta min_time = base::TimeDelta::FromMilliseconds(1);
|
| - static const base::TimeDelta max_time = base::TimeDelta::FromSeconds(50);
|
| - const size_t bucket_count(50);
|
| -
|
| - base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
|
| - histogram_name, min_time, max_time, bucket_count,
|
| - base::HistogramBase::kUmaTargetedHistogramFlag);
|
| - counter->AddTime(time_delta);
|
| -
|
| - DVLOG(1) << "Profile image download time: " << time_delta.InSecondsF();
|
| -}
|
| -
|
| -// Converts |image_index| to UMA histogram value.
|
| -int ImageIndexToHistogramIndex(int image_index) {
|
| - switch (image_index) {
|
| - case User::kExternalImageIndex:
|
| - // TODO(ivankr): Distinguish this from selected from file.
|
| - return kHistogramImageFromCamera;
|
| - case User::kProfileImageIndex:
|
| - return kHistogramImageFromProfile;
|
| - default:
|
| - return image_index;
|
| - }
|
| -}
|
| -
|
| -bool SaveImage(const UserImage& user_image, const base::FilePath& image_path) {
|
| - UserImage safe_image;
|
| - const UserImage::RawImage* encoded_image = NULL;
|
| - if (!user_image.is_safe_format()) {
|
| - safe_image = UserImage::CreateAndEncode(user_image.image());
|
| - encoded_image = &safe_image.raw_image();
|
| - UMA_HISTOGRAM_MEMORY_KB("UserImage.RecodedJpegSize", encoded_image->size());
|
| - } else if (user_image.has_raw_image()) {
|
| - encoded_image = &user_image.raw_image();
|
| - } else {
|
| - NOTREACHED() << "Raw image missing.";
|
| - return false;
|
| - }
|
| -
|
| - if (!encoded_image->size() ||
|
| - base::WriteFile(image_path,
|
| - reinterpret_cast<const char*>(&(*encoded_image)[0]),
|
| - encoded_image->size()) == -1) {
|
| - LOG(ERROR) << "Failed to save image to file.";
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -void UserImageManager::RegisterPrefs(PrefRegistrySimple* registry) {
|
| - registry->RegisterDictionaryPref(kUserImages);
|
| - registry->RegisterDictionaryPref(kUserImageProperties);
|
| -}
|
| -
|
| -// Every image load or update is encapsulated by a Job. The Job is allowed to
|
| -// perform tasks on background threads or in helper processes but:
|
| -// * Changes to User objects and local state as well as any calls to the
|
| -// |parent_| must be performed on the thread that the Job is created on only.
|
| -// * File writes and deletions must be performed via the |parent_|'s
|
| -// |background_task_runner_| only.
|
| -//
|
| -// Only one of the Load*() and Set*() methods may be called per Job.
|
| -class UserImageManagerImpl::Job {
|
| - public:
|
| - // The |Job| will update the user object corresponding to |parent|.
|
| - explicit Job(UserImageManagerImpl* parent);
|
| - ~Job();
|
| -
|
| - // Loads the image at |image_path| or one of the default images,
|
| - // depending on |image_index|, and updates the user object with the
|
| - // new image.
|
| - void LoadImage(base::FilePath image_path,
|
| - const int image_index,
|
| - const GURL& image_url);
|
| -
|
| - // Sets the user image in local state to the default image indicated
|
| - // by |default_image_index|. Also updates the user object with the
|
| - // new image.
|
| - void SetToDefaultImage(int default_image_index);
|
| -
|
| - // Saves the |user_image| to disk and sets the user image in local
|
| - // state to that image. Also updates the user with the new image.
|
| - void SetToImage(int image_index, const UserImage& user_image);
|
| -
|
| - // Decodes the JPEG image |data|, crops and resizes the image, saves
|
| - // it to disk and sets the user image in local state to that image.
|
| - // Also updates the user object with the new image.
|
| - void SetToImageData(scoped_ptr<std::string> data);
|
| -
|
| - // Loads the image at |path|, transcodes it to JPEG format, saves
|
| - // the image to disk and sets the user image in local state to that
|
| - // image. If |resize| is true, the image is cropped and resized
|
| - // before transcoding. Also updates the user object with the new
|
| - // image.
|
| - void SetToPath(const base::FilePath& path,
|
| - int image_index,
|
| - const GURL& image_url,
|
| - bool resize);
|
| -
|
| - private:
|
| - // Called back after an image has been loaded from disk.
|
| - void OnLoadImageDone(bool save, const UserImage& user_image);
|
| -
|
| - // Updates the user object with |user_image_|.
|
| - void UpdateUser();
|
| -
|
| - // Saves |user_image_| to disk in JPEG format. Local state will be updated
|
| - // when a callback indicates that the image has been saved.
|
| - void SaveImageAndUpdateLocalState();
|
| -
|
| - // Called back after the |user_image_| has been saved to
|
| - // disk. Updates the user image information in local state. The
|
| - // information is only updated if |success| is true (indicating that
|
| - // the image was saved successfully) or the user image is the
|
| - // profile image (indicating that even if the image could not be
|
| - // saved because it is not available right now, it will be
|
| - // downloaded eventually).
|
| - void OnSaveImageDone(bool success);
|
| -
|
| - // Updates the user image in local state, setting it to one of the
|
| - // default images or the saved |user_image_|, depending on
|
| - // |image_index_|.
|
| - void UpdateLocalState();
|
| -
|
| - // Notifies the |parent_| that the Job is done.
|
| - void NotifyJobDone();
|
| -
|
| - const std::string& user_id() const { return parent_->user_id(); }
|
| -
|
| - UserImageManagerImpl* parent_;
|
| -
|
| - // Whether one of the Load*() or Set*() methods has been run already.
|
| - bool run_;
|
| -
|
| - int image_index_;
|
| - GURL image_url_;
|
| - base::FilePath image_path_;
|
| -
|
| - UserImage user_image_;
|
| -
|
| - base::WeakPtrFactory<Job> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Job);
|
| -};
|
| -
|
| -UserImageManagerImpl::Job::Job(UserImageManagerImpl* parent)
|
| - : parent_(parent),
|
| - run_(false),
|
| - weak_factory_(this) {
|
| -}
|
| -
|
| -UserImageManagerImpl::Job::~Job() {
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::LoadImage(base::FilePath image_path,
|
| - const int image_index,
|
| - const GURL& image_url) {
|
| - DCHECK(!run_);
|
| - run_ = true;
|
| -
|
| - image_index_ = image_index;
|
| - image_url_ = image_url;
|
| - image_path_ = image_path;
|
| -
|
| - if (image_index_ >= 0 && image_index_ < kDefaultImagesCount) {
|
| - // Load one of the default images. This happens synchronously.
|
| - user_image_ = UserImage(GetDefaultImage(image_index_));
|
| - UpdateUser();
|
| - NotifyJobDone();
|
| - } else if (image_index_ == User::kExternalImageIndex ||
|
| - image_index_ == User::kProfileImageIndex) {
|
| - // Load the user image from a file referenced by |image_path|. This happens
|
| - // asynchronously. The JPEG image loader can be used here because
|
| - // LoadImage() is called only for users whose user image has previously
|
| - // been set by one of the Set*() methods, which transcode to JPEG format.
|
| - DCHECK(!image_path_.empty());
|
| - parent_->image_loader_->Start(image_path_.value(),
|
| - 0,
|
| - base::Bind(&Job::OnLoadImageDone,
|
| - weak_factory_.GetWeakPtr(),
|
| - false));
|
| - } else {
|
| - NOTREACHED();
|
| - NotifyJobDone();
|
| - }
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::SetToDefaultImage(int default_image_index) {
|
| - DCHECK(!run_);
|
| - run_ = true;
|
| -
|
| - DCHECK_LE(0, default_image_index);
|
| - DCHECK_GT(kDefaultImagesCount, default_image_index);
|
| -
|
| - image_index_ = default_image_index;
|
| - user_image_ = UserImage(GetDefaultImage(image_index_));
|
| -
|
| - UpdateUser();
|
| - UpdateLocalState();
|
| - NotifyJobDone();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::SetToImage(int image_index,
|
| - const UserImage& user_image) {
|
| - DCHECK(!run_);
|
| - run_ = true;
|
| -
|
| - DCHECK(image_index == User::kExternalImageIndex ||
|
| - image_index == User::kProfileImageIndex);
|
| -
|
| - image_index_ = image_index;
|
| - user_image_ = user_image;
|
| -
|
| - UpdateUser();
|
| - SaveImageAndUpdateLocalState();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::SetToImageData(scoped_ptr<std::string> data) {
|
| - DCHECK(!run_);
|
| - run_ = true;
|
| -
|
| - image_index_ = User::kExternalImageIndex;
|
| -
|
| - // This method uses the image_loader_, not the unsafe_image_loader_:
|
| - // * This is necessary because the method is used to update the user image
|
| - // whenever the policy for a user is set. In the case of device-local
|
| - // accounts, policy may change at any time, even if the user is not
|
| - // currently logged in (and thus, the unsafe_image_loader_ may not be used).
|
| - // * This is possible because only JPEG |data| is accepted. No support for
|
| - // other image file formats is needed.
|
| - // * This is safe because the image_loader_ employs a hardened JPEG decoder
|
| - // that protects against malicious invalid image data being used to attack
|
| - // the login screen or another user session currently in progress.
|
| - parent_->image_loader_->Start(data.Pass(),
|
| - login::kMaxUserImageSize,
|
| - base::Bind(&Job::OnLoadImageDone,
|
| - weak_factory_.GetWeakPtr(),
|
| - true));
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::SetToPath(const base::FilePath& path,
|
| - int image_index,
|
| - const GURL& image_url,
|
| - bool resize) {
|
| - DCHECK(!run_);
|
| - run_ = true;
|
| -
|
| - image_index_ = image_index;
|
| - image_url_ = image_url;
|
| -
|
| - DCHECK(!path.empty());
|
| - parent_->unsafe_image_loader_->Start(path.value(),
|
| - resize ? login::kMaxUserImageSize : 0,
|
| - base::Bind(&Job::OnLoadImageDone,
|
| - weak_factory_.GetWeakPtr(),
|
| - true));
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::OnLoadImageDone(bool save,
|
| - const UserImage& user_image) {
|
| - user_image_ = user_image;
|
| - UpdateUser();
|
| - if (save)
|
| - SaveImageAndUpdateLocalState();
|
| - else
|
| - NotifyJobDone();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::UpdateUser() {
|
| - User* user = parent_->user_manager_->FindUserAndModify(user_id());
|
| - if (!user)
|
| - return;
|
| -
|
| - if (!user_image_.image().isNull())
|
| - user->SetImage(user_image_, image_index_);
|
| - else
|
| - user->SetStubImage(image_index_, false);
|
| - user->SetImageURL(image_url_);
|
| -
|
| - parent_->OnJobChangedUserImage();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::SaveImageAndUpdateLocalState() {
|
| - base::FilePath user_data_dir;
|
| - PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
|
| - image_path_ = user_data_dir.Append(user_id() + kSafeImagePathExtension);
|
| -
|
| - base::PostTaskAndReplyWithResult(
|
| - parent_->background_task_runner_,
|
| - FROM_HERE,
|
| - base::Bind(&SaveImage, user_image_, image_path_),
|
| - base::Bind(&Job::OnSaveImageDone, weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::OnSaveImageDone(bool success) {
|
| - if (success || image_index_ == User::kProfileImageIndex)
|
| - UpdateLocalState();
|
| - NotifyJobDone();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::UpdateLocalState() {
|
| - // Ignore if data stored or cached outside the user's cryptohome is to be
|
| - // treated as ephemeral.
|
| - if (parent_->user_manager_->IsUserNonCryptohomeDataEphemeral(user_id()))
|
| - return;
|
| -
|
| - scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
|
| - entry->Set(kImagePathNodeName, new base::StringValue(image_path_.value()));
|
| - entry->Set(kImageIndexNodeName, new base::FundamentalValue(image_index_));
|
| - if (!image_url_.is_empty())
|
| - entry->Set(kImageURLNodeName, new base::StringValue(image_url_.spec()));
|
| - DictionaryPrefUpdate update(g_browser_process->local_state(),
|
| - kUserImageProperties);
|
| - update->SetWithoutPathExpansion(user_id(), entry.release());
|
| -
|
| - parent_->user_manager_->NotifyLocalStateChanged();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Job::NotifyJobDone() {
|
| - parent_->OnJobDone();
|
| -}
|
| -
|
| -UserImageManagerImpl::UserImageManagerImpl(const std::string& user_id,
|
| - UserManager* user_manager)
|
| - : UserImageManager(user_id),
|
| - user_manager_(user_manager),
|
| - downloading_profile_image_(false),
|
| - profile_image_requested_(false),
|
| - has_managed_image_(false),
|
| - user_needs_migration_(false),
|
| - weak_factory_(this) {
|
| - base::SequencedWorkerPool* blocking_pool =
|
| - content::BrowserThread::GetBlockingPool();
|
| - background_task_runner_ =
|
| - blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
|
| - blocking_pool->GetSequenceToken(),
|
| - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
|
| - image_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
|
| - background_task_runner_);
|
| - unsafe_image_loader_ = new UserImageLoader(ImageDecoder::DEFAULT_CODEC,
|
| - background_task_runner_);
|
| -}
|
| -
|
| -UserImageManagerImpl::~UserImageManagerImpl() {}
|
| -
|
| -void UserImageManagerImpl::LoadUserImage() {
|
| - PrefService* local_state = g_browser_process->local_state();
|
| - const base::DictionaryValue* prefs_images_unsafe =
|
| - local_state->GetDictionary(kUserImages);
|
| - const base::DictionaryValue* prefs_images =
|
| - local_state->GetDictionary(kUserImageProperties);
|
| - if (!prefs_images && !prefs_images_unsafe)
|
| - return;
|
| - User* user = GetUserAndModify();
|
| - bool needs_migration = false;
|
| -
|
| - // If entries are found in both |prefs_images_unsafe| and |prefs_images|,
|
| - // |prefs_images| is honored for now but |prefs_images_unsafe| will be
|
| - // migrated, overwriting the |prefs_images| entry, when the user logs in.
|
| - const base::DictionaryValue* image_properties = NULL;
|
| - if (prefs_images_unsafe) {
|
| - needs_migration = prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
|
| - user_id(), &image_properties);
|
| - if (needs_migration)
|
| - user_needs_migration_ = true;
|
| - }
|
| - if (prefs_images) {
|
| - prefs_images->GetDictionaryWithoutPathExpansion(user_id(),
|
| - &image_properties);
|
| - }
|
| -
|
| - // If the user image for |user_id| is managed by policy and the policy-set
|
| - // image is being loaded and persisted right now, let that job continue. It
|
| - // will update the user image when done.
|
| - if (IsUserImageManaged() && job_.get())
|
| - return;
|
| -
|
| - if (!image_properties) {
|
| - SetInitialUserImage();
|
| - return;
|
| - }
|
| -
|
| - int image_index = User::kInvalidImageIndex;
|
| - image_properties->GetInteger(kImageIndexNodeName, &image_index);
|
| - if (image_index >= 0 && image_index < kDefaultImagesCount) {
|
| - user->SetImage(UserImage(GetDefaultImage(image_index)),
|
| - image_index);
|
| - return;
|
| - }
|
| -
|
| - if (image_index != User::kExternalImageIndex &&
|
| - image_index != User::kProfileImageIndex) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| - std::string image_url_string;
|
| - image_properties->GetString(kImageURLNodeName, &image_url_string);
|
| - GURL image_url(image_url_string);
|
| - std::string image_path;
|
| - image_properties->GetString(kImagePathNodeName, &image_path);
|
| -
|
| - user->SetImageURL(image_url);
|
| - user->SetStubImage(image_index, true);
|
| - DCHECK(!image_path.empty() || image_index == User::kProfileImageIndex);
|
| - if (image_path.empty() || needs_migration) {
|
| - // Return if either of the following is true:
|
| - // * The profile image is to be used but has not been downloaded yet. The
|
| - // profile image will be downloaded after login.
|
| - // * The image needs migration. Migration will be performed after login.
|
| - return;
|
| - }
|
| -
|
| - job_.reset(new Job(this));
|
| - job_->LoadImage(base::FilePath(image_path), image_index, image_url);
|
| -}
|
| -
|
| -void UserImageManagerImpl::UserLoggedIn(bool user_is_new,
|
| - bool user_is_local) {
|
| - const User* user = GetUser();
|
| - if (user_is_new) {
|
| - if (!user_is_local)
|
| - SetInitialUserImage();
|
| - } else {
|
| - UMA_HISTOGRAM_ENUMERATION("UserImage.LoggedIn",
|
| - ImageIndexToHistogramIndex(user->image_index()),
|
| - kHistogramImagesCount);
|
| -
|
| - if (!IsUserImageManaged() && user_needs_migration_) {
|
| - const base::DictionaryValue* prefs_images_unsafe =
|
| - g_browser_process->local_state()->GetDictionary(kUserImages);
|
| - const base::DictionaryValue* image_properties = NULL;
|
| - if (prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
|
| - user_id(), &image_properties)) {
|
| - std::string image_path;
|
| - image_properties->GetString(kImagePathNodeName, &image_path);
|
| - job_.reset(new Job(this));
|
| - if (!image_path.empty()) {
|
| - VLOG(0) << "Loading old user image, then migrating it.";
|
| - job_->SetToPath(base::FilePath(image_path),
|
| - user->image_index(),
|
| - user->image_url(),
|
| - false);
|
| - } else {
|
| - job_->SetToDefaultImage(user->image_index());
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Reset the downloaded profile image as a new user logged in.
|
| - downloaded_profile_image_ = gfx::ImageSkia();
|
| - profile_image_url_ = GURL();
|
| - profile_image_requested_ = false;
|
| -
|
| - if (IsUserLoggedInAndRegular()) {
|
| - TryToInitDownloadedProfileImage();
|
| -
|
| - // Schedule an initial download of the profile data (full name and
|
| - // optionally image).
|
| - profile_download_one_shot_timer_.Start(
|
| - FROM_HERE,
|
| - g_ignore_profile_data_download_delay_ ?
|
| - base::TimeDelta() :
|
| - base::TimeDelta::FromSeconds(kProfileDataDownloadDelaySec),
|
| - base::Bind(&UserImageManagerImpl::DownloadProfileData,
|
| - base::Unretained(this),
|
| - kProfileDownloadReasonLoggedIn));
|
| - // Schedule periodic refreshes of the profile data.
|
| - profile_download_periodic_timer_.Start(
|
| - FROM_HERE,
|
| - base::TimeDelta::FromSeconds(kProfileRefreshIntervalSec),
|
| - base::Bind(&UserImageManagerImpl::DownloadProfileData,
|
| - base::Unretained(this),
|
| - kProfileDownloadReasonScheduled));
|
| - } else {
|
| - profile_download_one_shot_timer_.Stop();
|
| - profile_download_periodic_timer_.Stop();
|
| - }
|
| -
|
| - user_image_sync_observer_.reset();
|
| - TryToCreateImageSyncObserver();
|
| -}
|
| -
|
| -void UserImageManagerImpl::SaveUserDefaultImageIndex(int default_image_index) {
|
| - if (IsUserImageManaged())
|
| - return;
|
| - job_.reset(new Job(this));
|
| - job_->SetToDefaultImage(default_image_index);
|
| -}
|
| -
|
| -void UserImageManagerImpl::SaveUserImage(const UserImage& user_image) {
|
| - if (IsUserImageManaged())
|
| - return;
|
| - job_.reset(new Job(this));
|
| - job_->SetToImage(User::kExternalImageIndex, user_image);
|
| -}
|
| -
|
| -void UserImageManagerImpl::SaveUserImageFromFile(const base::FilePath& path) {
|
| - if (IsUserImageManaged())
|
| - return;
|
| - job_.reset(new Job(this));
|
| - job_->SetToPath(path, User::kExternalImageIndex, GURL(), true);
|
| -}
|
| -
|
| -void UserImageManagerImpl::SaveUserImageFromProfileImage() {
|
| - if (IsUserImageManaged())
|
| - return;
|
| - // Use the profile image if it has been downloaded already. Otherwise, use a
|
| - // stub image (gray avatar).
|
| - job_.reset(new Job(this));
|
| - job_->SetToImage(User::kProfileImageIndex,
|
| - downloaded_profile_image_.isNull() ?
|
| - UserImage() :
|
| - UserImage::CreateAndEncode(downloaded_profile_image_));
|
| - // If no profile image has been downloaded yet, ensure that a download is
|
| - // started.
|
| - if (downloaded_profile_image_.isNull())
|
| - DownloadProfileData(kProfileDownloadReasonProfileImageChosen);
|
| -}
|
| -
|
| -void UserImageManagerImpl::DeleteUserImage() {
|
| - job_.reset();
|
| - DeleteUserImageAndLocalStateEntry(kUserImages);
|
| - DeleteUserImageAndLocalStateEntry(kUserImageProperties);
|
| -}
|
| -
|
| -void UserImageManagerImpl::DownloadProfileImage(const std::string& reason) {
|
| - profile_image_requested_ = true;
|
| - DownloadProfileData(reason);
|
| -}
|
| -
|
| -const gfx::ImageSkia& UserImageManagerImpl::DownloadedProfileImage() const {
|
| - return downloaded_profile_image_;
|
| -}
|
| -
|
| -UserImageSyncObserver* UserImageManagerImpl::GetSyncObserver() const {
|
| - return user_image_sync_observer_.get();
|
| -}
|
| -
|
| -void UserImageManagerImpl::Shutdown() {
|
| - profile_downloader_.reset();
|
| - user_image_sync_observer_.reset();
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnExternalDataSet(const std::string& policy) {
|
| - DCHECK_EQ(policy::key::kUserAvatarImage, policy);
|
| - if (IsUserImageManaged())
|
| - return;
|
| -
|
| - has_managed_image_ = true;
|
| - job_.reset();
|
| -
|
| - const User* user = GetUser();
|
| - // If the user image for the currently logged-in user became managed, stop the
|
| - // sync observer so that the policy-set image does not get synced out.
|
| - if (user && user->is_logged_in())
|
| - user_image_sync_observer_.reset();
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnExternalDataCleared(const std::string& policy) {
|
| - DCHECK_EQ(policy::key::kUserAvatarImage, policy);
|
| - has_managed_image_ = false;
|
| - TryToCreateImageSyncObserver();
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnExternalDataFetched(const std::string& policy,
|
| - scoped_ptr<std::string> data) {
|
| - DCHECK_EQ(policy::key::kUserAvatarImage, policy);
|
| - DCHECK(IsUserImageManaged());
|
| - if (data) {
|
| - job_.reset(new Job(this));
|
| - job_->SetToImageData(data.Pass());
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void UserImageManagerImpl::IgnoreProfileDataDownloadDelayForTesting() {
|
| - g_ignore_profile_data_download_delay_ = true;
|
| -}
|
| -
|
| -bool UserImageManagerImpl::NeedsProfilePicture() const {
|
| - return downloading_profile_image_;
|
| -}
|
| -
|
| -int UserImageManagerImpl::GetDesiredImageSideLength() const {
|
| - return GetCurrentUserImageSize();
|
| -}
|
| -
|
| -Profile* UserImageManagerImpl::GetBrowserProfile() {
|
| - return user_manager_->GetProfileByUser(GetUser());
|
| -}
|
| -
|
| -std::string UserImageManagerImpl::GetCachedPictureURL() const {
|
| - return profile_image_url_.spec();
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnProfileDownloadSuccess(
|
| - ProfileDownloader* downloader) {
|
| - // Ensure that the |profile_downloader_| is deleted when this method returns.
|
| - scoped_ptr<ProfileDownloader> profile_downloader(
|
| - profile_downloader_.release());
|
| - DCHECK_EQ(downloader, profile_downloader.get());
|
| -
|
| - user_manager_->UpdateUserAccountData(
|
| - user_id(),
|
| - UserManager::UserAccountData(downloader->GetProfileFullName(),
|
| - downloader->GetProfileGivenName(),
|
| - downloader->GetProfileLocale()));
|
| - if (!downloading_profile_image_)
|
| - return;
|
| -
|
| - ProfileDownloadResult result = kDownloadFailure;
|
| - switch (downloader->GetProfilePictureStatus()) {
|
| - case ProfileDownloader::PICTURE_SUCCESS:
|
| - result = kDownloadSuccess;
|
| - break;
|
| - case ProfileDownloader::PICTURE_CACHED:
|
| - result = kDownloadCached;
|
| - break;
|
| - case ProfileDownloader::PICTURE_DEFAULT:
|
| - result = kDownloadDefault;
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -
|
| - UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
|
| - result,
|
| - kDownloadResultsCount);
|
| - DCHECK(!profile_image_load_start_time_.is_null());
|
| - AddProfileImageTimeHistogram(
|
| - result,
|
| - profile_image_download_reason_,
|
| - base::TimeTicks::Now() - profile_image_load_start_time_);
|
| -
|
| - // Ignore the image if it is no longer needed.
|
| - if (!NeedProfileImage())
|
| - return;
|
| -
|
| - if (result == kDownloadDefault) {
|
| - content::NotificationService::current()->Notify(
|
| - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
|
| - content::Source<UserImageManager>(this),
|
| - content::NotificationService::NoDetails());
|
| - } else {
|
| - profile_image_requested_ = false;
|
| - }
|
| -
|
| - // Nothing to do if the picture is cached or is the default avatar.
|
| - if (result != kDownloadSuccess)
|
| - return;
|
| -
|
| - downloaded_profile_image_ = gfx::ImageSkia::CreateFrom1xBitmap(
|
| - downloader->GetProfilePicture());
|
| - profile_image_url_ = GURL(downloader->GetProfilePictureURL());
|
| -
|
| - const User* user = GetUser();
|
| - if (user->image_index() == User::kProfileImageIndex) {
|
| - VLOG(1) << "Updating profile image for logged-in user.";
|
| - UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
|
| - kDownloadSuccessChanged,
|
| - kDownloadResultsCount);
|
| - // This will persist |downloaded_profile_image_| to disk.
|
| - SaveUserImageFromProfileImage();
|
| - }
|
| -
|
| - content::NotificationService::current()->Notify(
|
| - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
|
| - content::Source<UserImageManager>(this),
|
| - content::Details<const gfx::ImageSkia>(&downloaded_profile_image_));
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnProfileDownloadFailure(
|
| - ProfileDownloader* downloader,
|
| - ProfileDownloaderDelegate::FailureReason reason) {
|
| - DCHECK_EQ(downloader, profile_downloader_.get());
|
| - profile_downloader_.reset();
|
| -
|
| - if (downloading_profile_image_) {
|
| - UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
|
| - kDownloadFailure,
|
| - kDownloadResultsCount);
|
| - DCHECK(!profile_image_load_start_time_.is_null());
|
| - AddProfileImageTimeHistogram(
|
| - kDownloadFailure,
|
| - profile_image_download_reason_,
|
| - base::TimeTicks::Now() - profile_image_load_start_time_);
|
| - }
|
| -
|
| - if (reason == ProfileDownloaderDelegate::NETWORK_ERROR) {
|
| - // Retry download after a delay if a network error occurred.
|
| - profile_download_one_shot_timer_.Start(
|
| - FROM_HERE,
|
| - base::TimeDelta::FromSeconds(kProfileDataDownloadRetryIntervalSec),
|
| - base::Bind(&UserImageManagerImpl::DownloadProfileData,
|
| - base::Unretained(this),
|
| - kProfileDownloadReasonRetry));
|
| - }
|
| -
|
| - content::NotificationService::current()->Notify(
|
| - chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
|
| - content::Source<UserImageManager>(this),
|
| - content::NotificationService::NoDetails());
|
| -}
|
| -
|
| -bool UserImageManagerImpl::IsUserImageManaged() const {
|
| - return has_managed_image_;
|
| -}
|
| -
|
| -void UserImageManagerImpl::SetInitialUserImage() {
|
| - // Choose a random default image.
|
| - SaveUserDefaultImageIndex(base::RandInt(kFirstDefaultImageIndex,
|
| - kDefaultImagesCount - 1));
|
| -}
|
| -
|
| -void UserImageManagerImpl::TryToInitDownloadedProfileImage() {
|
| - const User* user = GetUser();
|
| - if (user->image_index() == User::kProfileImageIndex &&
|
| - downloaded_profile_image_.isNull() &&
|
| - !user->image_is_stub()) {
|
| - // Initialize the |downloaded_profile_image_| for the currently logged-in
|
| - // user if it has not been initialized already, the user image is the
|
| - // profile image and the user image has been loaded successfully.
|
| - VLOG(1) << "Profile image initialized from disk.";
|
| - downloaded_profile_image_ = user->GetImage();
|
| - profile_image_url_ = user->image_url();
|
| - }
|
| -}
|
| -
|
| -bool UserImageManagerImpl::NeedProfileImage() const {
|
| - const User* user = GetUser();
|
| - return IsUserLoggedInAndRegular() &&
|
| - (user->image_index() == User::kProfileImageIndex ||
|
| - profile_image_requested_);
|
| -}
|
| -
|
| -void UserImageManagerImpl::DownloadProfileData(const std::string& reason) {
|
| - // GAIA profiles exist for regular users only.
|
| - if (!IsUserLoggedInAndRegular())
|
| - return;
|
| -
|
| - // If a download is already in progress, allow it to continue, with one
|
| - // exception: If the current download does not include the profile image but
|
| - // the image has since become necessary, start a new download that includes
|
| - // the profile image.
|
| - if (profile_downloader_ &&
|
| - (downloading_profile_image_ || !NeedProfileImage())) {
|
| - return;
|
| - }
|
| -
|
| - downloading_profile_image_ = NeedProfileImage();
|
| - profile_image_download_reason_ = reason;
|
| - profile_image_load_start_time_ = base::TimeTicks::Now();
|
| - profile_downloader_.reset(new ProfileDownloader(this));
|
| - profile_downloader_->Start();
|
| -}
|
| -
|
| -void UserImageManagerImpl::DeleteUserImageAndLocalStateEntry(
|
| - const char* prefs_dict_root) {
|
| - DictionaryPrefUpdate update(g_browser_process->local_state(),
|
| - prefs_dict_root);
|
| - const base::DictionaryValue* image_properties;
|
| - if (!update->GetDictionaryWithoutPathExpansion(user_id(), &image_properties))
|
| - return;
|
| -
|
| - std::string image_path;
|
| - image_properties->GetString(kImagePathNodeName, &image_path);
|
| - if (!image_path.empty()) {
|
| - background_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(base::IgnoreResult(&base::DeleteFile),
|
| - base::FilePath(image_path),
|
| - false));
|
| - }
|
| - update->RemoveWithoutPathExpansion(user_id(), NULL);
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnJobChangedUserImage() {
|
| - if (GetUser()->is_logged_in())
|
| - TryToInitDownloadedProfileImage();
|
| -
|
| - content::NotificationService::current()->Notify(
|
| - chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
|
| - content::Source<UserImageManagerImpl>(this),
|
| - content::Details<const User>(GetUser()));
|
| -}
|
| -
|
| -void UserImageManagerImpl::OnJobDone() {
|
| - if (job_.get())
|
| - base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, job_.release());
|
| - else
|
| - NOTREACHED();
|
| -
|
| - if (!user_needs_migration_)
|
| - return;
|
| - // Migration completed for |user_id|.
|
| - user_needs_migration_ = false;
|
| -
|
| - const base::DictionaryValue* prefs_images_unsafe =
|
| - g_browser_process->local_state()->GetDictionary(kUserImages);
|
| - const base::DictionaryValue* image_properties = NULL;
|
| - if (!prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
|
| - user_id(), &image_properties)) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| -
|
| - int image_index = User::kInvalidImageIndex;
|
| - image_properties->GetInteger(kImageIndexNodeName, &image_index);
|
| - UMA_HISTOGRAM_ENUMERATION("UserImage.Migration",
|
| - ImageIndexToHistogramIndex(image_index),
|
| - kHistogramImagesCount);
|
| -
|
| - std::string image_path;
|
| - image_properties->GetString(kImagePathNodeName, &image_path);
|
| - if (!image_path.empty()) {
|
| - // If an old image exists, delete it and remove |user_id| from the old prefs
|
| - // dictionary only after the deletion has completed. This ensures that no
|
| - // orphaned image is left behind if the browser crashes before the deletion
|
| - // has been performed: In that case, local state will be unchanged and the
|
| - // migration will be run again on the user's next login.
|
| - background_task_runner_->PostTaskAndReply(
|
| - FROM_HERE,
|
| - base::Bind(base::IgnoreResult(&base::DeleteFile),
|
| - base::FilePath(image_path),
|
| - false),
|
| - base::Bind(&UserImageManagerImpl::UpdateLocalStateAfterMigration,
|
| - weak_factory_.GetWeakPtr()));
|
| - } else {
|
| - // If no old image exists, remove |user_id| from the old prefs dictionary.
|
| - UpdateLocalStateAfterMigration();
|
| - }
|
| -}
|
| -
|
| -void UserImageManagerImpl::UpdateLocalStateAfterMigration() {
|
| - DictionaryPrefUpdate update(g_browser_process->local_state(),
|
| - kUserImages);
|
| - update->RemoveWithoutPathExpansion(user_id(), NULL);
|
| -}
|
| -
|
| -void UserImageManagerImpl::TryToCreateImageSyncObserver() {
|
| - const User* user = GetUser();
|
| - // If the currently logged-in user's user image is managed, the sync observer
|
| - // must not be started so that the policy-set image does not get synced out.
|
| - if (!user_image_sync_observer_ &&
|
| - user && user->CanSyncImage() &&
|
| - !IsUserImageManaged()) {
|
| - user_image_sync_observer_.reset(new UserImageSyncObserver(user));
|
| - }
|
| -}
|
| -
|
| -const User* UserImageManagerImpl::GetUser() const {
|
| - return user_manager_->FindUser(user_id());
|
| -}
|
| -
|
| -User* UserImageManagerImpl::GetUserAndModify() const {
|
| - return user_manager_->FindUserAndModify(user_id());
|
| -}
|
| -
|
| -bool UserImageManagerImpl::IsUserLoggedInAndRegular() const {
|
| - const User* user = GetUser();
|
| - if (!user)
|
| - return false;
|
| - return user->is_logged_in() && user->GetType() == User::USER_TYPE_REGULAR;
|
| -}
|
| -
|
| -} // namespace chromeos
|
|
|