Home | History | Annotate | Download | only in wallpaper
      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/wallpaper/wallpaper_manager.h"
      6 
      7 #include <numeric>
      8 #include <vector>
      9 
     10 #include "ash/ash_constants.h"
     11 #include "ash/ash_switches.h"
     12 #include "ash/desktop_background/desktop_background_controller.h"
     13 #include "ash/shell.h"
     14 #include "base/command_line.h"
     15 #include "base/debug/trace_event.h"
     16 #include "base/file_util.h"
     17 #include "base/files/file_enumerator.h"
     18 #include "base/files/file_path.h"
     19 #include "base/logging.h"
     20 #include "base/metrics/histogram.h"
     21 #include "base/path_service.h"
     22 #include "base/prefs/pref_registry_simple.h"
     23 #include "base/prefs/pref_service.h"
     24 #include "base/prefs/scoped_user_pref_update.h"
     25 #include "base/strings/string_number_conversions.h"
     26 #include "base/strings/string_util.h"
     27 #include "base/strings/stringprintf.h"
     28 #include "base/sys_info.h"
     29 #include "base/threading/worker_pool.h"
     30 #include "base/time/time.h"
     31 #include "base/values.h"
     32 #include "chrome/browser/browser_process.h"
     33 #include "chrome/browser/chrome_notification_types.h"
     34 #include "chrome/browser/chromeos/customization_document.h"
     35 #include "chrome/browser/chromeos/login/startup_utils.h"
     36 #include "chrome/browser/chromeos/login/users/avatar/user_image.h"
     37 #include "chrome/browser/chromeos/login/users/user.h"
     38 #include "chrome/browser/chromeos/login/users/user_manager.h"
     39 #include "chrome/browser/chromeos/login/wizard_controller.h"
     40 #include "chrome/browser/chromeos/settings/cros_settings.h"
     41 #include "chrome/common/chrome_paths.h"
     42 #include "chrome/common/chrome_switches.h"
     43 #include "chrome/common/pref_names.h"
     44 #include "chromeos/chromeos_switches.h"
     45 #include "chromeos/dbus/dbus_thread_manager.h"
     46 #include "content/public/browser/browser_thread.h"
     47 #include "content/public/browser/notification_service.h"
     48 #include "third_party/skia/include/core/SkColor.h"
     49 #include "ui/gfx/codec/jpeg_codec.h"
     50 #include "ui/gfx/image/image_skia_operations.h"
     51 #include "ui/gfx/skia_util.h"
     52 
     53 using content::BrowserThread;
     54 
     55 namespace chromeos {
     56 
     57 namespace {
     58 
     59 // The amount of delay before starts to move custom wallpapers to the new place.
     60 const int kMoveCustomWallpaperDelaySeconds = 30;
     61 
     62 // Default quality for encoding wallpaper.
     63 const int kDefaultEncodingQuality = 90;
     64 
     65 // A dictionary pref that maps usernames to file paths to their wallpapers.
     66 // Deprecated. Will remove this const char after done migration.
     67 const char kUserWallpapers[] = "UserWallpapers";
     68 
     69 const int kCacheWallpaperDelayMs = 500;
     70 
     71 // A dictionary pref that maps usernames to wallpaper properties.
     72 const char kUserWallpapersProperties[] = "UserWallpapersProperties";
     73 
     74 // Names of nodes with info about wallpaper in |kUserWallpapersProperties|
     75 // dictionary.
     76 const char kNewWallpaperDateNodeName[] = "date";
     77 const char kNewWallpaperLayoutNodeName[] = "layout";
     78 const char kNewWallpaperFileNodeName[] = "file";
     79 const char kNewWallpaperTypeNodeName[] = "type";
     80 
     81 // Maximum number of wallpapers cached by CacheUsersWallpapers().
     82 const int kMaxWallpapersToCache = 3;
     83 
     84 // Maximum number of entries in WallpaperManager::last_load_times_ .
     85 const size_t kLastLoadsStatsMsMaxSize = 4;
     86 
     87 // Minimum delay between wallpaper loads, milliseconds.
     88 const unsigned kLoadMinDelayMs = 50;
     89 
     90 // Default wallpaper load delay, milliseconds.
     91 const unsigned kLoadDefaultDelayMs = 200;
     92 
     93 // Maximum wallpaper load delay, milliseconds.
     94 const unsigned kLoadMaxDelayMs = 2000;
     95 
     96 // When no wallpaper image is specified, the screen is filled with a solid
     97 // color.
     98 const SkColor kDefaultWallpaperColor = SK_ColorGRAY;
     99 
    100 // For our scaling ratios we need to round positive numbers.
    101 int RoundPositive(double x) {
    102   return static_cast<int>(floor(x + 0.5));
    103 }
    104 
    105 // Returns custom wallpaper directory by appending corresponding |sub_dir|.
    106 base::FilePath GetCustomWallpaperDir(const char* sub_dir) {
    107   base::FilePath custom_wallpaper_dir;
    108   CHECK(PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
    109                          &custom_wallpaper_dir));
    110   return custom_wallpaper_dir.Append(sub_dir);
    111 }
    112 
    113 bool MoveCustomWallpaperDirectory(const char* sub_dir,
    114                                   const std::string& user_id,
    115                                   const std::string& user_id_hash) {
    116   base::FilePath base_path = GetCustomWallpaperDir(sub_dir);
    117   base::FilePath to_path = base_path.Append(user_id_hash);
    118   base::FilePath from_path = base_path.Append(user_id);
    119   if (base::PathExists(from_path))
    120     return base::Move(from_path, to_path);
    121   return false;
    122 }
    123 
    124 // These global default values are used to set customized default
    125 // wallpaper path in WallpaperManager::InitializeWallpaper().
    126 base::FilePath GetCustomizedWallpaperDefaultRescaledFileName(
    127     const std::string& suffix) {
    128   const base::FilePath default_downloaded_file_name =
    129       ServicesCustomizationDocument::GetCustomizedWallpaperDownloadedFileName();
    130   const base::FilePath default_cache_dir =
    131       ServicesCustomizationDocument::GetCustomizedWallpaperCacheDir();
    132   if (default_downloaded_file_name.empty() || default_cache_dir.empty())
    133     return base::FilePath();
    134   return default_cache_dir.Append(
    135       default_downloaded_file_name.BaseName().value() + suffix);
    136 }
    137 
    138 // Whether DesktopBackgroundController should start with customized default
    139 // wallpaper in WallpaperManager::InitializeWallpaper() or not.
    140 bool ShouldUseCustomizedDefaultWallpaper() {
    141   PrefService* pref_service = g_browser_process->local_state();
    142 
    143   return !(pref_service->FindPreference(
    144                              prefs::kCustomizationDefaultWallpaperURL)
    145                ->IsDefaultValue());
    146 }
    147 
    148 // Deletes everything else except |path| in the same directory.
    149 void DeleteAllExcept(const base::FilePath& path) {
    150   base::FilePath dir = path.DirName();
    151   if (base::DirectoryExists(dir)) {
    152     base::FileEnumerator files(dir, false, base::FileEnumerator::FILES);
    153     for (base::FilePath current = files.Next(); !current.empty();
    154          current = files.Next()) {
    155       if (current != path)
    156         base::DeleteFile(current, false);
    157     }
    158   }
    159 }
    160 
    161 // Deletes a list of wallpaper files in |file_list|.
    162 void DeleteWallpaperInList(const std::vector<base::FilePath>& file_list) {
    163   for (std::vector<base::FilePath>::const_iterator it = file_list.begin();
    164        it != file_list.end(); ++it) {
    165     base::FilePath path = *it;
    166     // Some users may still have legacy wallpapers with png extension. We need
    167     // to delete these wallpapers too.
    168     if (!base::DeleteFile(path, true) &&
    169         !base::DeleteFile(path.AddExtension(".png"), false)) {
    170       LOG(ERROR) << "Failed to remove user wallpaper at " << path.value();
    171     }
    172   }
    173 }
    174 
    175 // Creates all new custom wallpaper directories for |user_id_hash| if not exist.
    176 // static
    177 void EnsureCustomWallpaperDirectories(const std::string& user_id_hash) {
    178   base::FilePath dir;
    179   dir = GetCustomWallpaperDir(kSmallWallpaperSubDir);
    180   dir = dir.Append(user_id_hash);
    181   if (!base::PathExists(dir))
    182     base::CreateDirectory(dir);
    183   dir = GetCustomWallpaperDir(kLargeWallpaperSubDir);
    184   dir = dir.Append(user_id_hash);
    185   if (!base::PathExists(dir))
    186     base::CreateDirectory(dir);
    187   dir = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
    188   dir = dir.Append(user_id_hash);
    189   if (!base::PathExists(dir))
    190     base::CreateDirectory(dir);
    191   dir = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
    192   dir = dir.Append(user_id_hash);
    193   if (!base::PathExists(dir))
    194     base::CreateDirectory(dir);
    195 }
    196 
    197 // Saves wallpaper image raw |data| to |path| (absolute path) in file system.
    198 // Returns true on success.
    199 bool SaveWallpaperInternal(const base::FilePath& path,
    200                            const char* data,
    201                            int size) {
    202   int written_bytes = base::WriteFile(path, data, size);
    203   return written_bytes == size;
    204 }
    205 
    206 // Returns index of the first public session user found in |users|
    207 // or -1 otherwise.
    208 int FindPublicSession(const chromeos::UserList& users) {
    209   int index = -1;
    210   int i = 0;
    211   for (UserList::const_iterator it = users.begin();
    212        it != users.end(); ++it, ++i) {
    213     if ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
    214       index = i;
    215       break;
    216     }
    217   }
    218 
    219   return index;
    220 }
    221 
    222 }  // namespace
    223 
    224 const char kWallpaperSequenceTokenName[] = "wallpaper-sequence";
    225 
    226 const char kSmallWallpaperSuffix[] = "_small";
    227 const char kLargeWallpaperSuffix[] = "_large";
    228 
    229 const char kSmallWallpaperSubDir[] = "small";
    230 const char kLargeWallpaperSubDir[] = "large";
    231 const char kOriginalWallpaperSubDir[] = "original";
    232 const char kThumbnailWallpaperSubDir[] = "thumb";
    233 
    234 const int kSmallWallpaperMaxWidth = 1366;
    235 const int kSmallWallpaperMaxHeight = 800;
    236 const int kLargeWallpaperMaxWidth = 2560;
    237 const int kLargeWallpaperMaxHeight = 1700;
    238 const int kWallpaperThumbnailWidth = 108;
    239 const int kWallpaperThumbnailHeight = 68;
    240 
    241 static WallpaperManager* g_wallpaper_manager = NULL;
    242 
    243 class WallpaperManager::CustomizedWallpaperRescaledFiles {
    244  public:
    245   CustomizedWallpaperRescaledFiles(const base::FilePath& path_downloaded,
    246                                    const base::FilePath& path_rescaled_small,
    247                                    const base::FilePath& path_rescaled_large);
    248 
    249   bool AllSizesExist() const;
    250 
    251   // Closure will hold unretained pointer to this object. So caller must
    252   // make sure that the closure will be destoyed before this object.
    253   // Closure must be called on BlockingPool.
    254   base::Closure CreateCheckerClosure();
    255 
    256   const base::FilePath& path_downloaded() const { return path_downloaded_; }
    257   const base::FilePath& path_rescaled_small() const {
    258     return path_rescaled_small_;
    259   }
    260   const base::FilePath& path_rescaled_large() const {
    261     return path_rescaled_large_;
    262   }
    263 
    264   const bool downloaded_exists() const { return downloaded_exists_; }
    265   const bool rescaled_small_exists() const { return rescaled_small_exists_; }
    266   const bool rescaled_large_exists() const { return rescaled_large_exists_; }
    267 
    268  private:
    269   // Must be called on BlockingPool.
    270   void CheckCustomizedWallpaperFilesExist();
    271 
    272   const base::FilePath path_downloaded_;
    273   const base::FilePath path_rescaled_small_;
    274   const base::FilePath path_rescaled_large_;
    275 
    276   bool downloaded_exists_;
    277   bool rescaled_small_exists_;
    278   bool rescaled_large_exists_;
    279 
    280   DISALLOW_COPY_AND_ASSIGN(CustomizedWallpaperRescaledFiles);
    281 };
    282 
    283 WallpaperManager::CustomizedWallpaperRescaledFiles::
    284     CustomizedWallpaperRescaledFiles(const base::FilePath& path_downloaded,
    285                                      const base::FilePath& path_rescaled_small,
    286                                      const base::FilePath& path_rescaled_large)
    287     : path_downloaded_(path_downloaded),
    288       path_rescaled_small_(path_rescaled_small),
    289       path_rescaled_large_(path_rescaled_large),
    290       downloaded_exists_(false),
    291       rescaled_small_exists_(false),
    292       rescaled_large_exists_(false) {
    293 }
    294 
    295 base::Closure
    296 WallpaperManager::CustomizedWallpaperRescaledFiles::CreateCheckerClosure() {
    297   return base::Bind(&WallpaperManager::CustomizedWallpaperRescaledFiles::
    298                         CheckCustomizedWallpaperFilesExist,
    299                     base::Unretained(this));
    300 }
    301 
    302 void WallpaperManager::CustomizedWallpaperRescaledFiles::
    303     CheckCustomizedWallpaperFilesExist() {
    304   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
    305   downloaded_exists_ = base::PathExists(path_downloaded_);
    306   rescaled_small_exists_ = base::PathExists(path_rescaled_small_);
    307   rescaled_large_exists_ = base::PathExists(path_rescaled_large_);
    308 }
    309 
    310 bool WallpaperManager::CustomizedWallpaperRescaledFiles::AllSizesExist() const {
    311   return rescaled_small_exists_ && rescaled_large_exists_;
    312 }
    313 
    314 // This object is passed between several threads while wallpaper is being
    315 // loaded. It will notify callback when last reference to it is removed
    316 // (thus indicating that the last load action has finished).
    317 class MovableOnDestroyCallback {
    318  public:
    319   explicit MovableOnDestroyCallback(const base::Closure& callback)
    320       : callback_(callback) {
    321   }
    322 
    323   ~MovableOnDestroyCallback() {
    324     if (!callback_.is_null())
    325       callback_.Run();
    326   }
    327 
    328  private:
    329   base::Closure callback_;
    330 };
    331 
    332 WallpaperManager::PendingWallpaper::PendingWallpaper(
    333     const base::TimeDelta delay,
    334     const std::string& user_id)
    335     : user_id_(user_id),
    336       default_(false),
    337       on_finish_(new MovableOnDestroyCallback(
    338           base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet,
    339                      this))) {
    340   timer.Start(
    341       FROM_HERE,
    342       delay,
    343       base::Bind(&WallpaperManager::PendingWallpaper::ProcessRequest, this));
    344 }
    345 
    346 WallpaperManager::PendingWallpaper::~PendingWallpaper() {}
    347 
    348 void WallpaperManager::PendingWallpaper::ResetSetWallpaperImage(
    349     const gfx::ImageSkia& image,
    350     const WallpaperInfo& info) {
    351   SetMode(image, info, base::FilePath(), false);
    352 }
    353 
    354 void WallpaperManager::PendingWallpaper::ResetLoadWallpaper(
    355     const WallpaperInfo& info) {
    356   SetMode(gfx::ImageSkia(), info, base::FilePath(), false);
    357 }
    358 
    359 void WallpaperManager::PendingWallpaper::ResetSetCustomWallpaper(
    360     const WallpaperInfo& info,
    361     const base::FilePath& wallpaper_path) {
    362   SetMode(gfx::ImageSkia(), info, wallpaper_path, false);
    363 }
    364 
    365 void WallpaperManager::PendingWallpaper::ResetSetDefaultWallpaper() {
    366   SetMode(gfx::ImageSkia(), WallpaperInfo(), base::FilePath(), true);
    367 }
    368 
    369 void WallpaperManager::PendingWallpaper::SetMode(
    370     const gfx::ImageSkia& image,
    371     const WallpaperInfo& info,
    372     const base::FilePath& wallpaper_path,
    373     const bool is_default) {
    374   user_wallpaper_ = image;
    375   info_ = info;
    376   wallpaper_path_ = wallpaper_path;
    377   default_ = is_default;
    378 }
    379 
    380 void WallpaperManager::PendingWallpaper::ProcessRequest() {
    381   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    382 
    383   timer.Stop();  // Erase reference to self.
    384 
    385   WallpaperManager* manager = WallpaperManager::Get();
    386   if (manager->pending_inactive_ == this)
    387     manager->pending_inactive_ = NULL;
    388 
    389   started_load_at_ = base::Time::Now();
    390 
    391   if (default_) {
    392     manager->DoSetDefaultWallpaper(user_id_, on_finish_.Pass());
    393   } else if (!user_wallpaper_.isNull()) {
    394     ash::Shell::GetInstance()
    395         ->desktop_background_controller()
    396         ->SetWallpaperImage(user_wallpaper_, info_.layout);
    397   } else if (!wallpaper_path_.empty()) {
    398     manager->task_runner_->PostTask(
    399         FROM_HERE,
    400         base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
    401                    user_id_,
    402                    info_,
    403                    wallpaper_path_,
    404                    true /* update wallpaper */,
    405                    base::Passed(on_finish_.Pass()),
    406                    manager->weak_factory_.GetWeakPtr()));
    407   } else if (!info_.file.empty()) {
    408     manager->LoadWallpaper(user_id_, info_, true, on_finish_.Pass());
    409   } else {
    410     // PendingWallpaper was created and never initialized?
    411     NOTREACHED();
    412     // Error. Do not record time.
    413     started_load_at_ = base::Time();
    414   }
    415   on_finish_.reset();
    416 }
    417 
    418 void WallpaperManager::PendingWallpaper::OnWallpaperSet() {
    419   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    420 
    421   // The only known case for this check to fail is global destruction during
    422   // wallpaper load. It should never happen.
    423   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
    424     return; // We are in a process of global destruction.
    425 
    426   timer.Stop();  // Erase reference to self.
    427 
    428   WallpaperManager* manager = WallpaperManager::Get();
    429   if (!started_load_at_.is_null()) {
    430     const base::TimeDelta elapsed = base::Time::Now() - started_load_at_;
    431     manager->SaveLastLoadTime(elapsed);
    432   }
    433   if (manager->pending_inactive_ == this) {
    434     // ProcessRequest() was never executed.
    435     manager->pending_inactive_ = NULL;
    436   }
    437 
    438   // Destroy self.
    439   manager->RemovePendingWallpaperFromList(this);
    440 }
    441 
    442 // WallpaperManager, public: ---------------------------------------------------
    443 
    444 // TestApi. For testing purpose
    445 WallpaperManager::TestApi::TestApi(WallpaperManager* wallpaper_manager)
    446     : wallpaper_manager_(wallpaper_manager) {
    447 }
    448 
    449 WallpaperManager::TestApi::~TestApi() {
    450 }
    451 
    452 base::FilePath WallpaperManager::TestApi::current_wallpaper_path() {
    453   return wallpaper_manager_->current_wallpaper_path_;
    454 }
    455 
    456 bool WallpaperManager::TestApi::GetWallpaperFromCache(
    457     const std::string& user_id, gfx::ImageSkia* image) {
    458   return wallpaper_manager_->GetWallpaperFromCache(user_id, image);
    459 }
    460 
    461 void WallpaperManager::TestApi::SetWallpaperCache(const std::string& user_id,
    462                                                   const gfx::ImageSkia& image) {
    463   DCHECK(!image.isNull());
    464   wallpaper_manager_->wallpaper_cache_[user_id] = image;
    465 }
    466 
    467 void WallpaperManager::TestApi::ClearDisposableWallpaperCache() {
    468   wallpaper_manager_->ClearDisposableWallpaperCache();
    469 }
    470 
    471 // static
    472 WallpaperManager* WallpaperManager::Get() {
    473   if (!g_wallpaper_manager)
    474     g_wallpaper_manager = new WallpaperManager();
    475   return g_wallpaper_manager;
    476 }
    477 
    478 WallpaperManager::WallpaperManager()
    479     : loaded_wallpapers_(0),
    480       command_line_for_testing_(NULL),
    481       should_cache_wallpaper_(false),
    482       weak_factory_(this),
    483       pending_inactive_(NULL) {
    484   SetDefaultWallpaperPathsFromCommandLine(
    485       base::CommandLine::ForCurrentProcess());
    486   registrar_.Add(this,
    487                  chrome::NOTIFICATION_LOGIN_USER_CHANGED,
    488                  content::NotificationService::AllSources());
    489   registrar_.Add(this,
    490                  chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
    491                  content::NotificationService::AllSources());
    492   registrar_.Add(this,
    493                  chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
    494                  content::NotificationService::AllSources());
    495   sequence_token_ = BrowserThread::GetBlockingPool()->
    496       GetNamedSequenceToken(kWallpaperSequenceTokenName);
    497   task_runner_ = BrowserThread::GetBlockingPool()->
    498       GetSequencedTaskRunnerWithShutdownBehavior(
    499           sequence_token_,
    500           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    501   wallpaper_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
    502                                           task_runner_);
    503 }
    504 
    505 WallpaperManager::~WallpaperManager() {
    506   // TODO(bshe): Lifetime of WallpaperManager needs more consideration.
    507   // http://crbug.com/171694
    508   DCHECK(!show_user_name_on_signin_subscription_);
    509 
    510   ClearObsoleteWallpaperPrefs();
    511   weak_factory_.InvalidateWeakPtrs();
    512 }
    513 
    514 void WallpaperManager::Shutdown() {
    515   show_user_name_on_signin_subscription_.reset();
    516 }
    517 
    518 // static
    519 void WallpaperManager::RegisterPrefs(PrefRegistrySimple* registry) {
    520   registry->RegisterDictionaryPref(prefs::kUsersWallpaperInfo);
    521   registry->RegisterDictionaryPref(kUserWallpapers);
    522   registry->RegisterDictionaryPref(kUserWallpapersProperties);
    523 }
    524 
    525 void WallpaperManager::AddObservers() {
    526   show_user_name_on_signin_subscription_ =
    527       CrosSettings::Get()->AddSettingsObserver(
    528           kAccountsPrefShowUserNamesOnSignIn,
    529           base::Bind(&WallpaperManager::InitializeRegisteredDeviceWallpaper,
    530                      weak_factory_.GetWeakPtr()));
    531 }
    532 
    533 void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
    534   // Some browser tests do not have a shell instance. As no wallpaper is needed
    535   // in these tests anyway, avoid loading one, preventing crashes and speeding
    536   // up the tests.
    537   if (!ash::Shell::HasInstance())
    538     return;
    539 
    540   WallpaperInfo info;
    541   if (GetLoggedInUserWallpaperInfo(&info)) {
    542     // TODO(sschmitz): We need an index for default wallpapers for the new UI.
    543     RecordUma(info.type, -1);
    544     if (info == current_user_wallpaper_info_)
    545       return;
    546   }
    547   SetUserWallpaperNow(UserManager::Get()->GetLoggedInUser()->email());
    548 }
    549 
    550 void WallpaperManager::ClearDisposableWallpaperCache() {
    551   // Cancel callback for previous cache requests.
    552   weak_factory_.InvalidateWeakPtrs();
    553   // Keep the wallpaper of logged in users in cache at multi-profile mode.
    554   std::set<std::string> logged_in_users_names;
    555   const UserList& logged_users = UserManager::Get()->GetLoggedInUsers();
    556   for (UserList::const_iterator it = logged_users.begin();
    557        it != logged_users.end();
    558        ++it) {
    559     logged_in_users_names.insert((*it)->email());
    560   }
    561 
    562   CustomWallpaperMap logged_in_users_cache;
    563   for (CustomWallpaperMap::iterator it = wallpaper_cache_.begin();
    564        it != wallpaper_cache_.end(); ++it) {
    565     if (logged_in_users_names.find(it->first) !=
    566         logged_in_users_names.end()) {
    567       logged_in_users_cache.insert(*it);
    568     }
    569   }
    570   wallpaper_cache_ = logged_in_users_cache;
    571 }
    572 
    573 bool WallpaperManager::GetLoggedInUserWallpaperInfo(WallpaperInfo* info) {
    574   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    575 
    576   if (UserManager::Get()->IsLoggedInAsStub()) {
    577     info->file = current_user_wallpaper_info_.file = "";
    578     info->layout = current_user_wallpaper_info_.layout =
    579         ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
    580     info->type = current_user_wallpaper_info_.type = User::DEFAULT;
    581     info->date = current_user_wallpaper_info_.date =
    582         base::Time::Now().LocalMidnight();
    583     return true;
    584   }
    585 
    586   return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
    587                               info);
    588 }
    589 
    590 void WallpaperManager::InitializeWallpaper() {
    591   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    592   UserManager* user_manager = UserManager::Get();
    593 
    594   // Apply device customization.
    595   if (ShouldUseCustomizedDefaultWallpaper()) {
    596     SetDefaultWallpaperPath(
    597         GetCustomizedWallpaperDefaultRescaledFileName(kSmallWallpaperSuffix),
    598         scoped_ptr<gfx::ImageSkia>().Pass(),
    599         GetCustomizedWallpaperDefaultRescaledFileName(kLargeWallpaperSuffix),
    600         scoped_ptr<gfx::ImageSkia>().Pass());
    601   }
    602 
    603   CommandLine* command_line = GetCommandLine();
    604   if (command_line->HasSwitch(chromeos::switches::kGuestSession)) {
    605     // Guest wallpaper should be initialized when guest login.
    606     // Note: This maybe called before login. So IsLoggedInAsGuest can not be
    607     // used here to determine if current user is guest.
    608     return;
    609   }
    610 
    611   if (command_line->HasSwitch(::switches::kTestType))
    612     WizardController::SetZeroDelays();
    613 
    614   // Zero delays is also set in autotests.
    615   if (WizardController::IsZeroDelayEnabled()) {
    616     // Ensure tests have some sort of wallpaper.
    617     ash::Shell::GetInstance()->desktop_background_controller()->
    618         CreateEmptyWallpaper();
    619     return;
    620   }
    621 
    622   if (!user_manager->IsUserLoggedIn()) {
    623     if (!StartupUtils::IsDeviceRegistered())
    624       SetDefaultWallpaperDelayed(UserManager::kSignInUser);
    625     else
    626       InitializeRegisteredDeviceWallpaper();
    627     return;
    628   }
    629   SetUserWallpaperDelayed(user_manager->GetLoggedInUser()->email());
    630 }
    631 
    632 void WallpaperManager::Observe(int type,
    633                                const content::NotificationSource& source,
    634                                const content::NotificationDetails& details) {
    635   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    636   switch (type) {
    637     case chrome::NOTIFICATION_LOGIN_USER_CHANGED: {
    638       ClearDisposableWallpaperCache();
    639       BrowserThread::PostDelayedTask(
    640           BrowserThread::UI,
    641           FROM_HERE,
    642           base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper,
    643                      weak_factory_.GetWeakPtr()),
    644           base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds));
    645       break;
    646     }
    647     case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
    648       if (!GetCommandLine()->HasSwitch(switches::kDisableBootAnimation)) {
    649         BrowserThread::PostDelayedTask(
    650             BrowserThread::UI, FROM_HERE,
    651             base::Bind(&WallpaperManager::CacheUsersWallpapers,
    652                        weak_factory_.GetWeakPtr()),
    653             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
    654       } else {
    655         should_cache_wallpaper_ = true;
    656       }
    657       break;
    658     }
    659     case chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED: {
    660       NotifyAnimationFinished();
    661       if (should_cache_wallpaper_) {
    662         BrowserThread::PostDelayedTask(
    663             BrowserThread::UI, FROM_HERE,
    664             base::Bind(&WallpaperManager::CacheUsersWallpapers,
    665                        weak_factory_.GetWeakPtr()),
    666             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
    667         should_cache_wallpaper_ = false;
    668       }
    669       break;
    670     }
    671     default:
    672       NOTREACHED() << "Unexpected notification " << type;
    673   }
    674 }
    675 
    676 void WallpaperManager::RemoveUserWallpaperInfo(const std::string& user_id) {
    677   WallpaperInfo info;
    678   GetUserWallpaperInfo(user_id, &info);
    679   PrefService* prefs = g_browser_process->local_state();
    680   DictionaryPrefUpdate prefs_wallpapers_info_update(prefs,
    681       prefs::kUsersWallpaperInfo);
    682   prefs_wallpapers_info_update->RemoveWithoutPathExpansion(user_id, NULL);
    683   DeleteUserWallpapers(user_id, info.file);
    684 }
    685 
    686 // static
    687 bool WallpaperManager::ResizeImage(const gfx::ImageSkia& image,
    688                                    ash::WallpaperLayout layout,
    689                                    int preferred_width,
    690                                    int preferred_height,
    691                                    scoped_refptr<base::RefCountedBytes>* output,
    692                                    gfx::ImageSkia* output_skia) {
    693   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
    694   int width = image.width();
    695   int height = image.height();
    696   int resized_width;
    697   int resized_height;
    698   *output = new base::RefCountedBytes();
    699 
    700   if (layout == ash::WALLPAPER_LAYOUT_CENTER_CROPPED) {
    701     // Do not resize custom wallpaper if it is smaller than preferred size.
    702     if (!(width > preferred_width && height > preferred_height))
    703       return false;
    704 
    705     double horizontal_ratio = static_cast<double>(preferred_width) / width;
    706     double vertical_ratio = static_cast<double>(preferred_height) / height;
    707     if (vertical_ratio > horizontal_ratio) {
    708       resized_width =
    709           RoundPositive(static_cast<double>(width) * vertical_ratio);
    710       resized_height = preferred_height;
    711     } else {
    712       resized_width = preferred_width;
    713       resized_height =
    714           RoundPositive(static_cast<double>(height) * horizontal_ratio);
    715     }
    716   } else if (layout == ash::WALLPAPER_LAYOUT_STRETCH) {
    717     resized_width = preferred_width;
    718     resized_height = preferred_height;
    719   } else {
    720     resized_width = width;
    721     resized_height = height;
    722   }
    723 
    724   gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
    725       image,
    726       skia::ImageOperations::RESIZE_LANCZOS3,
    727       gfx::Size(resized_width, resized_height));
    728 
    729   SkBitmap bitmap = *(resized_image.bitmap());
    730   SkAutoLockPixels lock_input(bitmap);
    731   gfx::JPEGCodec::Encode(
    732       reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
    733       gfx::JPEGCodec::FORMAT_SkBitmap,
    734       bitmap.width(),
    735       bitmap.height(),
    736       bitmap.width() * bitmap.bytesPerPixel(),
    737       kDefaultEncodingQuality,
    738       &(*output)->data());
    739 
    740   if (output_skia) {
    741     resized_image.MakeThreadSafe();
    742     *output_skia = resized_image;
    743   }
    744 
    745   return true;
    746 }
    747 
    748 // static
    749 bool WallpaperManager::ResizeAndSaveWallpaper(const gfx::ImageSkia& image,
    750                                               const base::FilePath& path,
    751                                               ash::WallpaperLayout layout,
    752                                               int preferred_width,
    753                                               int preferred_height,
    754                                               gfx::ImageSkia* output_skia) {
    755   if (layout == ash::WALLPAPER_LAYOUT_CENTER) {
    756     // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
    757     if (base::PathExists(path))
    758       base::DeleteFile(path, false);
    759     return false;
    760   }
    761   scoped_refptr<base::RefCountedBytes> data;
    762   if (ResizeImage(image,
    763                   layout,
    764                   preferred_width,
    765                   preferred_height,
    766                   &data,
    767                   output_skia)) {
    768     return SaveWallpaperInternal(
    769         path, reinterpret_cast<const char*>(data->front()), data->size());
    770   }
    771   return false;
    772 }
    773 
    774 bool WallpaperManager::IsPolicyControlled(const std::string& user_id) const {
    775   chromeos::WallpaperInfo info;
    776   if (!GetUserWallpaperInfo(user_id, &info))
    777     return false;
    778   return info.type == chromeos::User::POLICY;
    779 }
    780 
    781 void WallpaperManager::OnPolicySet(const std::string& policy,
    782                                    const std::string& user_id) {
    783   WallpaperInfo info;
    784   GetUserWallpaperInfo(user_id, &info);
    785   info.type = User::POLICY;
    786   SetUserWallpaperInfo(user_id, info, true /* is_persistent */);
    787 }
    788 
    789 void WallpaperManager::OnPolicyCleared(const std::string& policy,
    790                                        const std::string& user_id) {
    791   WallpaperInfo info;
    792   GetUserWallpaperInfo(user_id, &info);
    793   info.type = User::DEFAULT;
    794   SetUserWallpaperInfo(user_id, info, true /* is_persistent */);
    795   SetDefaultWallpaperNow(user_id);
    796 }
    797 
    798 void WallpaperManager::OnPolicyFetched(const std::string& policy,
    799                                        const std::string& user_id,
    800                                        scoped_ptr<std::string> data) {
    801   if (!data)
    802     return;
    803 
    804   wallpaper_loader_->Start(
    805       data.Pass(),
    806       0,  // Do not crop.
    807       base::Bind(&WallpaperManager::SetPolicyControlledWallpaper,
    808                  weak_factory_.GetWeakPtr(),
    809                  user_id));
    810 }
    811 
    812 // static
    813 WallpaperManager::WallpaperResolution
    814 WallpaperManager::GetAppropriateResolution() {
    815   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    816   gfx::Size size =
    817       ash::DesktopBackgroundController::GetMaxDisplaySizeInNative();
    818   return (size.width() > kSmallWallpaperMaxWidth ||
    819           size.height() > kSmallWallpaperMaxHeight)
    820              ? WALLPAPER_RESOLUTION_LARGE
    821              : WALLPAPER_RESOLUTION_SMALL;
    822 }
    823 
    824 // static
    825 base::FilePath WallpaperManager::GetCustomWallpaperPath(
    826     const char* sub_dir,
    827     const std::string& user_id_hash,
    828     const std::string& file) {
    829   base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
    830   return custom_wallpaper_path.Append(user_id_hash).Append(file);
    831 }
    832 
    833 void WallpaperManager::SetPolicyControlledWallpaper(
    834     const std::string& user_id,
    835     const UserImage& user_image) {
    836   const User *user = chromeos::UserManager::Get()->FindUser(user_id);
    837   if (!user) {
    838     NOTREACHED() << "Unknown user.";
    839     return;
    840   }
    841   SetCustomWallpaper(user_id,
    842                      user->username_hash(),
    843                      "policy-controlled.jpeg",
    844                      ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
    845                      User::POLICY,
    846                      user_image.image(),
    847                      true /* update wallpaper */);
    848 }
    849 
    850 void WallpaperManager::SetCustomWallpaper(const std::string& user_id,
    851                                           const std::string& user_id_hash,
    852                                           const std::string& file,
    853                                           ash::WallpaperLayout layout,
    854                                           User::WallpaperType type,
    855                                           const gfx::ImageSkia& image,
    856                                           bool update_wallpaper) {
    857   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    858   DCHECK(UserManager::Get()->IsUserLoggedIn());
    859 
    860   // There is no visible background in kiosk mode.
    861   if (UserManager::Get()->IsLoggedInAsKioskApp())
    862     return;
    863 
    864   // Don't allow custom wallpapers while policy is in effect.
    865   if (type != User::POLICY && IsPolicyControlled(user_id))
    866     return;
    867 
    868   base::FilePath wallpaper_path =
    869       GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id_hash, file);
    870 
    871   // If decoded wallpaper is empty, we have probably failed to decode the file.
    872   // Use default wallpaper in this case.
    873   if (image.isNull()) {
    874     SetDefaultWallpaperDelayed(user_id);
    875     return;
    876   }
    877 
    878   bool is_persistent =
    879       !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id);
    880 
    881   WallpaperInfo wallpaper_info = {
    882       wallpaper_path.value(),
    883       layout,
    884       type,
    885       // Date field is not used.
    886       base::Time::Now().LocalMidnight()
    887   };
    888   if (is_persistent) {
    889     image.EnsureRepsForSupportedScales();
    890     scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy());
    891     // Block shutdown on this task. Otherwise, we may lose the custom wallpaper
    892     // that the user selected.
    893     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
    894         BrowserThread::GetBlockingPool()
    895             ->GetSequencedTaskRunnerWithShutdownBehavior(
    896                 sequence_token_, base::SequencedWorkerPool::BLOCK_SHUTDOWN);
    897     // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
    898     blocking_task_runner->PostTask(
    899         FROM_HERE,
    900         base::Bind(&WallpaperManager::SaveCustomWallpaper,
    901                    user_id_hash,
    902                    base::FilePath(wallpaper_info.file),
    903                    wallpaper_info.layout,
    904                    base::Passed(deep_copy.Pass())));
    905   }
    906 
    907   std::string relative_path = base::FilePath(user_id_hash).Append(file).value();
    908   // User's custom wallpaper path is determined by relative path and the
    909   // appropriate wallpaper resolution in GetCustomWallpaperInternal.
    910   WallpaperInfo info = {
    911       relative_path,
    912       layout,
    913       type,
    914       base::Time::Now().LocalMidnight()
    915   };
    916   SetUserWallpaperInfo(user_id, info, is_persistent);
    917   if (update_wallpaper) {
    918     GetPendingWallpaper(user_id, false)->ResetSetWallpaperImage(image, info);
    919   }
    920 
    921   wallpaper_cache_[user_id] = image;
    922 }
    923 
    924 void WallpaperManager::SetDefaultWallpaperNow(const std::string& user_id) {
    925   GetPendingWallpaper(user_id, false)->ResetSetDefaultWallpaper();
    926 }
    927 
    928 void WallpaperManager::SetDefaultWallpaperDelayed(const std::string& user_id) {
    929   GetPendingWallpaper(user_id, true)->ResetSetDefaultWallpaper();
    930 }
    931 
    932 void WallpaperManager::DoSetDefaultWallpaper(
    933     const std::string& user_id,
    934     MovableOnDestroyCallbackHolder on_finish) {
    935   // There is no visible background in kiosk mode.
    936   if (UserManager::Get()->IsLoggedInAsKioskApp())
    937     return;
    938   current_wallpaper_path_.clear();
    939   wallpaper_cache_.erase(user_id);
    940   // Some browser tests do not have a shell instance. As no wallpaper is needed
    941   // in these tests anyway, avoid loading one, preventing crashes and speeding
    942   // up the tests.
    943   if (!ash::Shell::HasInstance())
    944     return;
    945 
    946   WallpaperResolution resolution = GetAppropriateResolution();
    947   const bool use_small = (resolution == WALLPAPER_RESOLUTION_SMALL);
    948 
    949   const base::FilePath* file = NULL;
    950 
    951   if (UserManager::Get()->IsLoggedInAsGuest()) {
    952     file =
    953         use_small ? &guest_small_wallpaper_file_ : &guest_large_wallpaper_file_;
    954   } else {
    955     file = use_small ? &default_small_wallpaper_file_
    956                      : &default_large_wallpaper_file_;
    957   }
    958   ash::WallpaperLayout layout = use_small
    959                                     ? ash::WALLPAPER_LAYOUT_CENTER
    960                                     : ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
    961   DCHECK(file);
    962   if (!default_wallpaper_image_.get() ||
    963       default_wallpaper_image_->file_path() != file->value()) {
    964     default_wallpaper_image_.reset();
    965     if (!file->empty()) {
    966       loaded_wallpapers_++;
    967       StartLoadAndSetDefaultWallpaper(
    968           *file, layout, on_finish.Pass(), &default_wallpaper_image_);
    969       return;
    970     }
    971 
    972     CreateSolidDefaultWallpaper();
    973   }
    974   // 1x1 wallpaper is actually solid color, so it should be stretched.
    975   if (default_wallpaper_image_->image().width() == 1 &&
    976       default_wallpaper_image_->image().height() == 1)
    977     layout = ash::WALLPAPER_LAYOUT_STRETCH;
    978 
    979   ash::Shell::GetInstance()->desktop_background_controller()->SetWallpaperImage(
    980       default_wallpaper_image_->image(), layout);
    981 }
    982 
    983 // static
    984 void WallpaperManager::RecordUma(User::WallpaperType type, int index) {
    985   UMA_HISTOGRAM_ENUMERATION(
    986       "Ash.Wallpaper.Type", type, User::WALLPAPER_TYPE_COUNT);
    987 }
    988 
    989 // static
    990 void WallpaperManager::SaveCustomWallpaper(const std::string& user_id_hash,
    991                                            const base::FilePath& original_path,
    992                                            ash::WallpaperLayout layout,
    993                                            scoped_ptr<gfx::ImageSkia> image) {
    994   EnsureCustomWallpaperDirectories(user_id_hash);
    995   std::string file_name = original_path.BaseName().value();
    996   base::FilePath small_wallpaper_path =
    997       GetCustomWallpaperPath(kSmallWallpaperSubDir, user_id_hash, file_name);
    998   base::FilePath large_wallpaper_path =
    999       GetCustomWallpaperPath(kLargeWallpaperSubDir, user_id_hash, file_name);
   1000 
   1001   // Re-encode orginal file to jpeg format and saves the result in case that
   1002   // resized wallpaper is not generated (i.e. chrome shutdown before resized
   1003   // wallpaper is saved).
   1004   ResizeAndSaveWallpaper(*image,
   1005                          original_path,
   1006                          ash::WALLPAPER_LAYOUT_STRETCH,
   1007                          image->width(),
   1008                          image->height(),
   1009                          NULL);
   1010   DeleteAllExcept(original_path);
   1011 
   1012   ResizeAndSaveWallpaper(*image,
   1013                          small_wallpaper_path,
   1014                          layout,
   1015                          kSmallWallpaperMaxWidth,
   1016                          kSmallWallpaperMaxHeight,
   1017                          NULL);
   1018   DeleteAllExcept(small_wallpaper_path);
   1019   ResizeAndSaveWallpaper(*image,
   1020                          large_wallpaper_path,
   1021                          layout,
   1022                          kLargeWallpaperMaxWidth,
   1023                          kLargeWallpaperMaxHeight,
   1024                          NULL);
   1025   DeleteAllExcept(large_wallpaper_path);
   1026 }
   1027 
   1028 // static
   1029 void WallpaperManager::MoveCustomWallpapersOnWorker(
   1030     const std::string& user_id,
   1031     const std::string& user_id_hash,
   1032     base::WeakPtr<WallpaperManager> weak_ptr) {
   1033 
   1034   if (MoveCustomWallpaperDirectory(
   1035           kOriginalWallpaperSubDir, user_id, user_id_hash)) {
   1036     // Consider success if the original wallpaper is moved to the new directory.
   1037     // Original wallpaper is the fallback if the correct resolution wallpaper
   1038     // can not be found.
   1039     BrowserThread::PostTask(
   1040         BrowserThread::UI,
   1041         FROM_HERE,
   1042         base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess,
   1043                    weak_ptr,
   1044                    user_id,
   1045                    user_id_hash));
   1046   }
   1047   MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, user_id, user_id_hash);
   1048   MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, user_id, user_id_hash);
   1049   MoveCustomWallpaperDirectory(
   1050       kThumbnailWallpaperSubDir, user_id, user_id_hash);
   1051 }
   1052 
   1053 // static
   1054 void WallpaperManager::GetCustomWallpaperInternal(
   1055     const std::string& user_id,
   1056     const WallpaperInfo& info,
   1057     const base::FilePath& wallpaper_path,
   1058     bool update_wallpaper,
   1059     MovableOnDestroyCallbackHolder on_finish,
   1060     base::WeakPtr<WallpaperManager> weak_ptr) {
   1061 
   1062   base::FilePath valid_path = wallpaper_path;
   1063   if (!base::PathExists(wallpaper_path)) {
   1064     // Falls back on original file if the correct resolution file does not
   1065     // exist. This may happen when the original custom wallpaper is small or
   1066     // browser shutdown before resized wallpaper saved.
   1067     valid_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
   1068     valid_path = valid_path.Append(info.file);
   1069   }
   1070 
   1071   if (!base::PathExists(valid_path)) {
   1072     // Falls back to custom wallpaper that uses email as part of its file path.
   1073     // Note that email is used instead of user_id_hash here.
   1074     valid_path =
   1075         GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id, info.file);
   1076   }
   1077 
   1078   if (!base::PathExists(valid_path)) {
   1079     LOG(ERROR) << "Failed to load previously selected custom wallpaper. " <<
   1080                   "Fallback to default wallpaper";
   1081     BrowserThread::PostTask(BrowserThread::UI,
   1082                             FROM_HERE,
   1083                             base::Bind(&WallpaperManager::DoSetDefaultWallpaper,
   1084                                        weak_ptr,
   1085                                        user_id,
   1086                                        base::Passed(on_finish.Pass())));
   1087   } else {
   1088     BrowserThread::PostTask(BrowserThread::UI,
   1089                             FROM_HERE,
   1090                             base::Bind(&WallpaperManager::StartLoad,
   1091                                        weak_ptr,
   1092                                        user_id,
   1093                                        info,
   1094                                        update_wallpaper,
   1095                                        valid_path,
   1096                                        base::Passed(on_finish.Pass())));
   1097   }
   1098 }
   1099 
   1100 void WallpaperManager::InitInitialUserWallpaper(const std::string& user_id,
   1101                                                 bool is_persistent) {
   1102   current_user_wallpaper_info_.file = "";
   1103   current_user_wallpaper_info_.layout = ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
   1104   current_user_wallpaper_info_.type = User::DEFAULT;
   1105   current_user_wallpaper_info_.date = base::Time::Now().LocalMidnight();
   1106 
   1107   WallpaperInfo info = current_user_wallpaper_info_;
   1108   SetUserWallpaperInfo(user_id, info, is_persistent);
   1109 }
   1110 
   1111 void WallpaperManager::SetUserWallpaperInfo(const std::string& user_id,
   1112                                             const WallpaperInfo& info,
   1113                                             bool is_persistent) {
   1114   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1115   current_user_wallpaper_info_ = info;
   1116   if (!is_persistent)
   1117     return;
   1118 
   1119   PrefService* local_state = g_browser_process->local_state();
   1120   DictionaryPrefUpdate wallpaper_update(local_state,
   1121                                         prefs::kUsersWallpaperInfo);
   1122 
   1123   base::DictionaryValue* wallpaper_info_dict = new base::DictionaryValue();
   1124   wallpaper_info_dict->SetString(kNewWallpaperDateNodeName,
   1125       base::Int64ToString(info.date.ToInternalValue()));
   1126   wallpaper_info_dict->SetString(kNewWallpaperFileNodeName, info.file);
   1127   wallpaper_info_dict->SetInteger(kNewWallpaperLayoutNodeName, info.layout);
   1128   wallpaper_info_dict->SetInteger(kNewWallpaperTypeNodeName, info.type);
   1129   wallpaper_update->SetWithoutPathExpansion(user_id, wallpaper_info_dict);
   1130 }
   1131 
   1132 void WallpaperManager::SetUserWallpaperDelayed(const std::string& user_id) {
   1133   ScheduleSetUserWallpaper(user_id, true);
   1134 }
   1135 
   1136 void WallpaperManager::SetUserWallpaperNow(const std::string& user_id) {
   1137   ScheduleSetUserWallpaper(user_id, false);
   1138 }
   1139 
   1140 void WallpaperManager::ScheduleSetUserWallpaper(const std::string& user_id,
   1141                                                 bool delayed) {
   1142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1143   // Some unit tests come here without a UserManager or without a pref system.
   1144   if (!UserManager::IsInitialized() || !g_browser_process->local_state())
   1145     return;
   1146   // There is no visible background in kiosk mode.
   1147   if (UserManager::Get()->IsLoggedInAsKioskApp())
   1148     return;
   1149   // Guest user, regular user in ephemeral mode, or kiosk app.
   1150   const User* user = UserManager::Get()->FindUser(user_id);
   1151   if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id) ||
   1152       (user != NULL && user->GetType() == User::USER_TYPE_KIOSK_APP)) {
   1153     InitInitialUserWallpaper(user_id, false);
   1154     GetPendingWallpaper(user_id, delayed)->ResetSetDefaultWallpaper();
   1155     return;
   1156   }
   1157 
   1158   if (!UserManager::Get()->IsKnownUser(user_id))
   1159     return;
   1160 
   1161   last_selected_user_ = user_id;
   1162 
   1163   WallpaperInfo info;
   1164 
   1165   if (!GetUserWallpaperInfo(user_id, &info)) {
   1166     InitInitialUserWallpaper(user_id, true);
   1167     GetUserWallpaperInfo(user_id, &info);
   1168   }
   1169 
   1170   gfx::ImageSkia user_wallpaper;
   1171   current_user_wallpaper_info_ = info;
   1172   if (GetWallpaperFromCache(user_id, &user_wallpaper)) {
   1173     GetPendingWallpaper(user_id, delayed)
   1174         ->ResetSetWallpaperImage(user_wallpaper, info);
   1175   } else {
   1176     if (info.file.empty()) {
   1177       // Uses default built-in wallpaper when file is empty. Eventually, we
   1178       // will only ship one built-in wallpaper in ChromeOS image.
   1179       GetPendingWallpaper(user_id, delayed)->ResetSetDefaultWallpaper();
   1180       return;
   1181     }
   1182 
   1183     if (info.type == User::CUSTOMIZED || info.type == User::POLICY) {
   1184       const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
   1185       // Wallpaper is not resized when layout is ash::WALLPAPER_LAYOUT_CENTER.
   1186       // Original wallpaper should be used in this case.
   1187       // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
   1188       if (info.layout == ash::WALLPAPER_LAYOUT_CENTER)
   1189         sub_dir = kOriginalWallpaperSubDir;
   1190       base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
   1191       wallpaper_path = wallpaper_path.Append(info.file);
   1192       if (current_wallpaper_path_ == wallpaper_path)
   1193         return;
   1194       current_wallpaper_path_ = wallpaper_path;
   1195       loaded_wallpapers_++;
   1196 
   1197       GetPendingWallpaper(user_id, delayed)
   1198           ->ResetSetCustomWallpaper(info, wallpaper_path);
   1199       return;
   1200     }
   1201 
   1202     // Load downloaded ONLINE or converted DEFAULT wallpapers.
   1203     GetPendingWallpaper(user_id, delayed)->ResetLoadWallpaper(info);
   1204   }
   1205 }
   1206 
   1207 void WallpaperManager::SetWallpaperFromImageSkia(const std::string& user_id,
   1208                                                  const gfx::ImageSkia& image,
   1209                                                  ash::WallpaperLayout layout,
   1210                                                  bool update_wallpaper) {
   1211   DCHECK(UserManager::Get()->IsUserLoggedIn());
   1212 
   1213   // There is no visible background in kiosk mode.
   1214   if (UserManager::Get()->IsLoggedInAsKioskApp())
   1215     return;
   1216   WallpaperInfo info;
   1217   info.layout = layout;
   1218   wallpaper_cache_[user_id] = image;
   1219 
   1220   if (update_wallpaper) {
   1221     GetPendingWallpaper(last_selected_user_, false /* Not delayed */)
   1222         ->ResetSetWallpaperImage(image, info);
   1223   }
   1224 }
   1225 
   1226 void WallpaperManager::UpdateWallpaper(bool clear_cache) {
   1227   FOR_EACH_OBSERVER(Observer, observers_, OnUpdateWallpaperForTesting());
   1228   if (clear_cache)
   1229     wallpaper_cache_.clear();
   1230   current_wallpaper_path_.clear();
   1231   // For GAIA login flow, the last_selected_user_ may not be set before user
   1232   // login. If UpdateWallpaper is called at GAIA login screen, no wallpaper will
   1233   // be set. It could result a black screen on external monitors.
   1234   // See http://crbug.com/265689 for detail.
   1235   if (last_selected_user_.empty()) {
   1236     SetDefaultWallpaperNow(UserManager::kSignInUser);
   1237     return;
   1238   }
   1239   SetUserWallpaperNow(last_selected_user_);
   1240 }
   1241 
   1242 void WallpaperManager::AddObserver(WallpaperManager::Observer* observer) {
   1243   observers_.AddObserver(observer);
   1244 }
   1245 
   1246 void WallpaperManager::RemoveObserver(WallpaperManager::Observer* observer) {
   1247   observers_.RemoveObserver(observer);
   1248 }
   1249 
   1250 void WallpaperManager::NotifyAnimationFinished() {
   1251   FOR_EACH_OBSERVER(
   1252       Observer, observers_, OnWallpaperAnimationFinished(last_selected_user_));
   1253 }
   1254 
   1255 // WallpaperManager, private: --------------------------------------------------
   1256 
   1257 bool WallpaperManager::GetWallpaperFromCache(const std::string& user_id,
   1258                                              gfx::ImageSkia* image) {
   1259   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1260   CustomWallpaperMap::const_iterator it = wallpaper_cache_.find(user_id);
   1261   if (it != wallpaper_cache_.end()) {
   1262     *image = (*it).second;
   1263     return true;
   1264   }
   1265   return false;
   1266 }
   1267 
   1268 void WallpaperManager::CacheUsersWallpapers() {
   1269   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1270   UserList users = UserManager::Get()->GetUsers();
   1271 
   1272   if (!users.empty()) {
   1273     UserList::const_iterator it = users.begin();
   1274     // Skip the wallpaper of first user in the list. It should have been cached.
   1275     it++;
   1276     for (int cached = 0;
   1277          it != users.end() && cached < kMaxWallpapersToCache;
   1278          ++it, ++cached) {
   1279       std::string user_id = (*it)->email();
   1280       CacheUserWallpaper(user_id);
   1281     }
   1282   }
   1283 }
   1284 
   1285 void WallpaperManager::CacheUserWallpaper(const std::string& user_id) {
   1286   if (wallpaper_cache_.find(user_id) != wallpaper_cache_.end())
   1287     return;
   1288   WallpaperInfo info;
   1289   if (GetUserWallpaperInfo(user_id, &info)) {
   1290     if (info.file.empty())
   1291       return;
   1292 
   1293     base::FilePath wallpaper_dir;
   1294     base::FilePath wallpaper_path;
   1295     if (info.type == User::CUSTOMIZED || info.type == User::POLICY) {
   1296       const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
   1297       base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
   1298       wallpaper_path = wallpaper_path.Append(info.file);
   1299       task_runner_->PostTask(
   1300           FROM_HERE,
   1301           base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
   1302                      user_id,
   1303                      info,
   1304                      wallpaper_path,
   1305                      false /* do not update wallpaper */,
   1306                      base::Passed(MovableOnDestroyCallbackHolder()),
   1307                      weak_factory_.GetWeakPtr()));
   1308       return;
   1309     }
   1310     LoadWallpaper(user_id,
   1311                   info,
   1312                   false /* do not update wallpaper */,
   1313                   MovableOnDestroyCallbackHolder().Pass());
   1314   }
   1315 }
   1316 
   1317 void WallpaperManager::ClearObsoleteWallpaperPrefs() {
   1318   PrefService* prefs = g_browser_process->local_state();
   1319   DictionaryPrefUpdate wallpaper_properties_pref(prefs,
   1320       kUserWallpapersProperties);
   1321   wallpaper_properties_pref->Clear();
   1322   DictionaryPrefUpdate wallpapers_pref(prefs, kUserWallpapers);
   1323   wallpapers_pref->Clear();
   1324 }
   1325 
   1326 void WallpaperManager::DeleteUserWallpapers(const std::string& user_id,
   1327                                             const std::string& path_to_file) {
   1328   std::vector<base::FilePath> file_to_remove;
   1329   // Remove small user wallpaper.
   1330   base::FilePath wallpaper_path =
   1331       GetCustomWallpaperDir(kSmallWallpaperSubDir);
   1332   // Remove old directory if exists
   1333   file_to_remove.push_back(wallpaper_path.Append(user_id));
   1334   wallpaper_path = wallpaper_path.Append(path_to_file).DirName();
   1335   file_to_remove.push_back(wallpaper_path);
   1336 
   1337   // Remove large user wallpaper.
   1338   wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
   1339   file_to_remove.push_back(wallpaper_path.Append(user_id));
   1340   wallpaper_path = wallpaper_path.Append(path_to_file);
   1341   file_to_remove.push_back(wallpaper_path);
   1342 
   1343   // Remove user wallpaper thumbnail.
   1344   wallpaper_path = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
   1345   file_to_remove.push_back(wallpaper_path.Append(user_id));
   1346   wallpaper_path = wallpaper_path.Append(path_to_file);
   1347   file_to_remove.push_back(wallpaper_path);
   1348 
   1349   // Remove original user wallpaper.
   1350   wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
   1351   file_to_remove.push_back(wallpaper_path.Append(user_id));
   1352   wallpaper_path = wallpaper_path.Append(path_to_file);
   1353   file_to_remove.push_back(wallpaper_path);
   1354 
   1355   base::WorkerPool::PostTask(
   1356       FROM_HERE,
   1357       base::Bind(&DeleteWallpaperInList, file_to_remove),
   1358       false);
   1359 }
   1360 
   1361 void WallpaperManager::SetCommandLineForTesting(
   1362     base::CommandLine* command_line) {
   1363   command_line_for_testing_ = command_line;
   1364   SetDefaultWallpaperPathsFromCommandLine(command_line);
   1365 }
   1366 
   1367 CommandLine* WallpaperManager::GetCommandLine() {
   1368   CommandLine* command_line = command_line_for_testing_ ?
   1369       command_line_for_testing_ : CommandLine::ForCurrentProcess();
   1370   return command_line;
   1371 }
   1372 
   1373 void WallpaperManager::InitializeRegisteredDeviceWallpaper() {
   1374   if (UserManager::Get()->IsUserLoggedIn())
   1375     return;
   1376 
   1377   bool disable_boot_animation =
   1378       GetCommandLine()->HasSwitch(switches::kDisableBootAnimation);
   1379   bool show_users = true;
   1380   bool result = CrosSettings::Get()->GetBoolean(
   1381       kAccountsPrefShowUserNamesOnSignIn, &show_users);
   1382   DCHECK(result) << "Unable to fetch setting "
   1383                  << kAccountsPrefShowUserNamesOnSignIn;
   1384   const chromeos::UserList& users = UserManager::Get()->GetUsers();
   1385   int public_session_user_index = FindPublicSession(users);
   1386   if ((!show_users && public_session_user_index == -1) || users.empty()) {
   1387     // Boot into sign in form, preload default wallpaper.
   1388     SetDefaultWallpaperDelayed(UserManager::kSignInUser);
   1389     return;
   1390   }
   1391 
   1392   if (!disable_boot_animation) {
   1393     int index = public_session_user_index != -1 ? public_session_user_index : 0;
   1394     // Normal boot, load user wallpaper.
   1395     // If normal boot animation is disabled wallpaper would be set
   1396     // asynchronously once user pods are loaded.
   1397     SetUserWallpaperDelayed(users[index]->email());
   1398   }
   1399 }
   1400 
   1401 void WallpaperManager::LoadWallpaper(const std::string& user_id,
   1402                                      const WallpaperInfo& info,
   1403                                      bool update_wallpaper,
   1404                                      MovableOnDestroyCallbackHolder on_finish) {
   1405   base::FilePath wallpaper_dir;
   1406   base::FilePath wallpaper_path;
   1407 
   1408   // Do a sanity check that file path information is not empty.
   1409   if (info.type == User::ONLINE || info.type == User::DEFAULT) {
   1410     if (info.file.empty()) {
   1411       if (base::SysInfo::IsRunningOnChromeOS()) {
   1412         NOTREACHED() << "User wallpaper info appears to be broken: " << user_id;
   1413       } else {
   1414         // Filename might be empty on debug configurations when stub users
   1415         // were created directly in Local State (for testing). Ignore such
   1416         // errors i.e. allowsuch type of debug configurations on the desktop.
   1417         LOG(WARNING) << "User wallpaper info is empty: " << user_id;
   1418 
   1419         // |on_finish| callback will get called on destruction.
   1420         return;
   1421       }
   1422     }
   1423   }
   1424 
   1425   if (info.type == User::ONLINE) {
   1426     std::string file_name = GURL(info.file).ExtractFileName();
   1427     WallpaperResolution resolution = GetAppropriateResolution();
   1428     // Only solid color wallpapers have stretch layout and they have only one
   1429     // resolution.
   1430     if (info.layout != ash::WALLPAPER_LAYOUT_STRETCH &&
   1431         resolution == WALLPAPER_RESOLUTION_SMALL) {
   1432       file_name = base::FilePath(file_name).InsertBeforeExtension(
   1433           kSmallWallpaperSuffix).value();
   1434     }
   1435     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
   1436     wallpaper_path = wallpaper_dir.Append(file_name);
   1437     if (current_wallpaper_path_ == wallpaper_path)
   1438       return;
   1439 
   1440     if (update_wallpaper)
   1441       current_wallpaper_path_ = wallpaper_path;
   1442 
   1443     loaded_wallpapers_++;
   1444     StartLoad(
   1445         user_id, info, update_wallpaper, wallpaper_path, on_finish.Pass());
   1446   } else if (info.type == User::DEFAULT) {
   1447     // Default wallpapers are migrated from M21 user profiles. A code refactor
   1448     // overlooked that case and caused these wallpapers not being loaded at all.
   1449     // On some slow devices, it caused login webui not visible after upgrade to
   1450     // M26 from M21. See crosbug.com/38429 for details.
   1451     base::FilePath user_data_dir;
   1452     PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
   1453     wallpaper_path = user_data_dir.Append(info.file);
   1454     StartLoad(
   1455         user_id, info, update_wallpaper, wallpaper_path, on_finish.Pass());
   1456   } else {
   1457     // In unexpected cases, revert to default wallpaper to fail safely. See
   1458     // crosbug.com/38429.
   1459     LOG(ERROR) << "Wallpaper reverts to default unexpected.";
   1460     DoSetDefaultWallpaper(user_id, on_finish.Pass());
   1461   }
   1462 }
   1463 
   1464 bool WallpaperManager::GetUserWallpaperInfo(const std::string& user_id,
   1465                                             WallpaperInfo* info) const {
   1466   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1467 
   1468   if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id)) {
   1469     // Default to the values cached in memory.
   1470     *info = current_user_wallpaper_info_;
   1471 
   1472     // Ephemeral users do not save anything to local state. But we have got
   1473     // wallpaper info from memory. Returns true.
   1474     return true;
   1475   }
   1476 
   1477   const base::DictionaryValue* info_dict;
   1478   if (!g_browser_process->local_state()->
   1479           GetDictionary(prefs::kUsersWallpaperInfo)->
   1480               GetDictionaryWithoutPathExpansion(user_id, &info_dict)) {
   1481     return false;
   1482   }
   1483 
   1484   // Use temporary variables to keep |info| untouched in the error case.
   1485   std::string file;
   1486   if (!info_dict->GetString(kNewWallpaperFileNodeName, &file))
   1487     return false;
   1488   int layout;
   1489   if (!info_dict->GetInteger(kNewWallpaperLayoutNodeName, &layout))
   1490     return false;
   1491   int type;
   1492   if (!info_dict->GetInteger(kNewWallpaperTypeNodeName, &type))
   1493     return false;
   1494   std::string date_string;
   1495   if (!info_dict->GetString(kNewWallpaperDateNodeName, &date_string))
   1496     return false;
   1497   int64 date_val;
   1498   if (!base::StringToInt64(date_string, &date_val))
   1499     return false;
   1500 
   1501   info->file = file;
   1502   info->layout = static_cast<ash::WallpaperLayout>(layout);
   1503   info->type = static_cast<User::WallpaperType>(type);
   1504   info->date = base::Time::FromInternalValue(date_val);
   1505   return true;
   1506 }
   1507 
   1508 void WallpaperManager::MoveCustomWallpapersSuccess(
   1509     const std::string& user_id,
   1510     const std::string& user_id_hash) {
   1511   WallpaperInfo info;
   1512   GetUserWallpaperInfo(user_id, &info);
   1513   if (info.type == User::CUSTOMIZED) {
   1514     // New file field should include user id hash in addition to file name.
   1515     // This is needed because at login screen, user id hash is not available.
   1516     std::string relative_path =
   1517         base::FilePath(user_id_hash).Append(info.file).value();
   1518     info.file = relative_path;
   1519     bool is_persistent =
   1520         !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id);
   1521     SetUserWallpaperInfo(user_id, info, is_persistent);
   1522   }
   1523 }
   1524 
   1525 void WallpaperManager::MoveLoggedInUserCustomWallpaper() {
   1526   const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
   1527   task_runner_->PostTask(
   1528       FROM_HERE,
   1529       base::Bind(&WallpaperManager::MoveCustomWallpapersOnWorker,
   1530                  logged_in_user->email(),
   1531                  logged_in_user->username_hash(),
   1532                  weak_factory_.GetWeakPtr()));
   1533 }
   1534 
   1535 void WallpaperManager::OnWallpaperDecoded(
   1536     const std::string& user_id,
   1537     ash::WallpaperLayout layout,
   1538     bool update_wallpaper,
   1539     MovableOnDestroyCallbackHolder on_finish,
   1540     const UserImage& user_image) {
   1541   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1542   TRACE_EVENT_ASYNC_END0("ui", "LoadAndDecodeWallpaper", this);
   1543 
   1544   // If decoded wallpaper is empty, we have probably failed to decode the file.
   1545   // Use default wallpaper in this case.
   1546   if (user_image.image().isNull()) {
   1547     // Updates user pref to default wallpaper.
   1548     WallpaperInfo info = {
   1549                            "",
   1550                            ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
   1551                            User::DEFAULT,
   1552                            base::Time::Now().LocalMidnight()
   1553                          };
   1554     SetUserWallpaperInfo(user_id, info, true);
   1555 
   1556     if (update_wallpaper)
   1557       DoSetDefaultWallpaper(user_id, on_finish.Pass());
   1558     return;
   1559   }
   1560 
   1561   wallpaper_cache_[user_id] = user_image.image();
   1562 
   1563   if (update_wallpaper) {
   1564     ash::Shell::GetInstance()
   1565         ->desktop_background_controller()
   1566         ->SetWallpaperImage(user_image.image(), layout);
   1567   }
   1568 }
   1569 
   1570 void WallpaperManager::StartLoad(const std::string& user_id,
   1571                                  const WallpaperInfo& info,
   1572                                  bool update_wallpaper,
   1573                                  const base::FilePath& wallpaper_path,
   1574                                  MovableOnDestroyCallbackHolder on_finish) {
   1575   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1576   TRACE_EVENT_ASYNC_BEGIN0("ui", "LoadAndDecodeWallpaper", this);
   1577 
   1578   wallpaper_loader_->Start(wallpaper_path.value(),
   1579                            0,  // Do not crop.
   1580                            base::Bind(&WallpaperManager::OnWallpaperDecoded,
   1581                                       weak_factory_.GetWeakPtr(),
   1582                                       user_id,
   1583                                       info.layout,
   1584                                       update_wallpaper,
   1585                                       base::Passed(on_finish.Pass())));
   1586 }
   1587 
   1588 void WallpaperManager::SaveLastLoadTime(const base::TimeDelta elapsed) {
   1589   while (last_load_times_.size() >= kLastLoadsStatsMsMaxSize)
   1590     last_load_times_.pop_front();
   1591 
   1592   if (elapsed > base::TimeDelta::FromMicroseconds(0)) {
   1593     last_load_times_.push_back(elapsed);
   1594     last_load_finished_at_ = base::Time::Now();
   1595   }
   1596 }
   1597 
   1598 base::TimeDelta WallpaperManager::GetWallpaperLoadDelay() const {
   1599   base::TimeDelta delay;
   1600 
   1601   if (last_load_times_.size() == 0) {
   1602     delay = base::TimeDelta::FromMilliseconds(kLoadDefaultDelayMs);
   1603   } else {
   1604     delay = std::accumulate(last_load_times_.begin(),
   1605                             last_load_times_.end(),
   1606                             base::TimeDelta(),
   1607                             std::plus<base::TimeDelta>()) /
   1608             last_load_times_.size();
   1609   }
   1610 
   1611   if (delay < base::TimeDelta::FromMilliseconds(kLoadMinDelayMs))
   1612     delay = base::TimeDelta::FromMilliseconds(kLoadMinDelayMs);
   1613   else if (delay > base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs))
   1614     delay = base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs);
   1615 
   1616   // If we had ever loaded wallpaper, adjust wait delay by time since last load.
   1617   if (!last_load_finished_at_.is_null()) {
   1618     const base::TimeDelta interval = base::Time::Now() - last_load_finished_at_;
   1619     if (interval > delay)
   1620       delay = base::TimeDelta::FromMilliseconds(0);
   1621     else if (interval > base::TimeDelta::FromMilliseconds(0))
   1622       delay -= interval;
   1623   }
   1624   return delay;
   1625 }
   1626 
   1627 void WallpaperManager::SetCustomizedDefaultWallpaperAfterCheck(
   1628     const GURL& wallpaper_url,
   1629     const base::FilePath& downloaded_file,
   1630     scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files) {
   1631   PrefService* pref_service = g_browser_process->local_state();
   1632 
   1633   std::string current_url =
   1634       pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
   1635   if (current_url != wallpaper_url.spec() || !rescaled_files->AllSizesExist()) {
   1636     DCHECK(rescaled_files->downloaded_exists());
   1637 
   1638     // Either resized images do not exist or cached version is incorrect.
   1639     // Need to start resize again.
   1640     wallpaper_loader_->Start(
   1641         downloaded_file.value(),
   1642         0,  // Do not crop.
   1643         base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperDecoded,
   1644                    weak_factory_.GetWeakPtr(),
   1645                    wallpaper_url,
   1646                    base::Passed(rescaled_files.Pass())));
   1647   } else {
   1648     SetDefaultWallpaperPath(rescaled_files->path_rescaled_small(),
   1649                             scoped_ptr<gfx::ImageSkia>().Pass(),
   1650                             rescaled_files->path_rescaled_large(),
   1651                             scoped_ptr<gfx::ImageSkia>().Pass());
   1652   }
   1653 }
   1654 
   1655 void WallpaperManager::OnCustomizedDefaultWallpaperDecoded(
   1656     const GURL& wallpaper_url,
   1657     scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files,
   1658     const UserImage& wallpaper) {
   1659   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1660 
   1661   // If decoded wallpaper is empty, we have probably failed to decode the file.
   1662   if (wallpaper.image().isNull()) {
   1663     LOG(WARNING) << "Failed to decode customized wallpaper.";
   1664     return;
   1665   }
   1666 
   1667   wallpaper.image().EnsureRepsForSupportedScales();
   1668   scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper.image().DeepCopy());
   1669 
   1670   scoped_ptr<bool> success(new bool(false));
   1671   scoped_ptr<gfx::ImageSkia> small_wallpaper_image(new gfx::ImageSkia);
   1672   scoped_ptr<gfx::ImageSkia> large_wallpaper_image(new gfx::ImageSkia);
   1673 
   1674   // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
   1675   base::Closure resize_closure =
   1676       base::Bind(&WallpaperManager::ResizeCustomizedDefaultWallpaper,
   1677                  base::Passed(&deep_copy),
   1678                  wallpaper.raw_image(),
   1679                  base::Unretained(rescaled_files.get()),
   1680                  base::Unretained(success.get()),
   1681                  base::Unretained(small_wallpaper_image.get()),
   1682                  base::Unretained(large_wallpaper_image.get()));
   1683   base::Closure on_resized_closure =
   1684       base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperResized,
   1685                  weak_factory_.GetWeakPtr(),
   1686                  wallpaper_url,
   1687                  base::Passed(rescaled_files.Pass()),
   1688                  base::Passed(success.Pass()),
   1689                  base::Passed(small_wallpaper_image.Pass()),
   1690                  base::Passed(large_wallpaper_image.Pass()));
   1691 
   1692   if (!task_runner_->PostTaskAndReply(
   1693           FROM_HERE, resize_closure, on_resized_closure)) {
   1694     LOG(WARNING) << "Failed to start Customized Wallpaper resize.";
   1695   }
   1696 }
   1697 
   1698 void WallpaperManager::ResizeCustomizedDefaultWallpaper(
   1699     scoped_ptr<gfx::ImageSkia> image,
   1700     const UserImage::RawImage& raw_image,
   1701     const CustomizedWallpaperRescaledFiles* rescaled_files,
   1702     bool* success,
   1703     gfx::ImageSkia* small_wallpaper_image,
   1704     gfx::ImageSkia* large_wallpaper_image) {
   1705   *success = true;
   1706 
   1707   *success &= ResizeAndSaveWallpaper(*image,
   1708                                      rescaled_files->path_rescaled_small(),
   1709                                      ash::WALLPAPER_LAYOUT_STRETCH,
   1710                                      kSmallWallpaperMaxWidth,
   1711                                      kSmallWallpaperMaxHeight,
   1712                                      small_wallpaper_image);
   1713 
   1714   *success &= ResizeAndSaveWallpaper(*image,
   1715                                      rescaled_files->path_rescaled_large(),
   1716                                      ash::WALLPAPER_LAYOUT_STRETCH,
   1717                                      kLargeWallpaperMaxWidth,
   1718                                      kLargeWallpaperMaxHeight,
   1719                                      large_wallpaper_image);
   1720 }
   1721 
   1722 void WallpaperManager::OnCustomizedDefaultWallpaperResized(
   1723     const GURL& wallpaper_url,
   1724     scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files,
   1725     scoped_ptr<bool> success,
   1726     scoped_ptr<gfx::ImageSkia> small_wallpaper_image,
   1727     scoped_ptr<gfx::ImageSkia> large_wallpaper_image) {
   1728   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1729   DCHECK(rescaled_files);
   1730   DCHECK(success.get());
   1731   if (!*success) {
   1732     LOG(WARNING) << "Failed to save resized customized default wallpaper";
   1733     return;
   1734   }
   1735   PrefService* pref_service = g_browser_process->local_state();
   1736   pref_service->SetString(prefs::kCustomizationDefaultWallpaperURL,
   1737                           wallpaper_url.spec());
   1738   SetDefaultWallpaperPath(rescaled_files->path_rescaled_small(),
   1739                           small_wallpaper_image.Pass(),
   1740                           rescaled_files->path_rescaled_large(),
   1741                           large_wallpaper_image.Pass());
   1742   VLOG(1) << "Customized default wallpaper applied.";
   1743 }
   1744 
   1745 WallpaperManager::PendingWallpaper* WallpaperManager::GetPendingWallpaper(
   1746     const std::string& user_id,
   1747     bool delayed) {
   1748   if (!pending_inactive_) {
   1749     loading_.push_back(new WallpaperManager::PendingWallpaper(
   1750         (delayed ? GetWallpaperLoadDelay()
   1751                  : base::TimeDelta::FromMilliseconds(0)),
   1752         user_id));
   1753     pending_inactive_ = loading_.back();
   1754   }
   1755   return pending_inactive_;
   1756 }
   1757 
   1758 void WallpaperManager::RemovePendingWallpaperFromList(
   1759     PendingWallpaper* pending) {
   1760   DCHECK(loading_.size() > 0);
   1761   for (WallpaperManager::PendingList::iterator i = loading_.begin();
   1762        i != loading_.end();
   1763        ++i) {
   1764     if (i->get() == pending) {
   1765       loading_.erase(i);
   1766       break;
   1767     }
   1768   }
   1769 
   1770   if (loading_.empty())
   1771     FOR_EACH_OBSERVER(Observer, observers_, OnPendingListEmptyForTesting());
   1772 }
   1773 
   1774 void WallpaperManager::SetCustomizedDefaultWallpaper(
   1775     const GURL& wallpaper_url,
   1776     const base::FilePath& downloaded_file,
   1777     const base::FilePath& resized_directory) {
   1778   // Should fail if this ever happens in tests.
   1779   DCHECK(wallpaper_url.is_valid());
   1780   if (!wallpaper_url.is_valid()) {
   1781     if (!wallpaper_url.is_empty()) {
   1782       LOG(WARNING) << "Invalid Customized Wallpaper URL '"
   1783                    << wallpaper_url.spec() << "'";
   1784     }
   1785     return;
   1786   }
   1787   std::string downloaded_file_name = downloaded_file.BaseName().value();
   1788   scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files(
   1789       new CustomizedWallpaperRescaledFiles(
   1790           downloaded_file,
   1791           resized_directory.Append(downloaded_file_name +
   1792                                    kSmallWallpaperSuffix),
   1793           resized_directory.Append(downloaded_file_name +
   1794                                    kLargeWallpaperSuffix)));
   1795 
   1796   base::Closure check_file_exists = rescaled_files->CreateCheckerClosure();
   1797   base::Closure on_checked_closure =
   1798       base::Bind(&WallpaperManager::SetCustomizedDefaultWallpaperAfterCheck,
   1799                  weak_factory_.GetWeakPtr(),
   1800                  wallpaper_url,
   1801                  downloaded_file,
   1802                  base::Passed(rescaled_files.Pass()));
   1803   if (!BrowserThread::PostBlockingPoolTaskAndReply(
   1804           FROM_HERE, check_file_exists, on_checked_closure)) {
   1805     LOG(WARNING) << "Failed to start check CheckCustomizedWallpaperFilesExist.";
   1806   }
   1807 }
   1808 
   1809 size_t WallpaperManager::GetPendingListSizeForTesting() const {
   1810   return loading_.size();
   1811 }
   1812 
   1813 void WallpaperManager::SetDefaultWallpaperPathsFromCommandLine(
   1814     base::CommandLine* command_line) {
   1815   default_small_wallpaper_file_ = command_line->GetSwitchValuePath(
   1816       ash::switches::kAshDefaultWallpaperSmall);
   1817   default_large_wallpaper_file_ = command_line->GetSwitchValuePath(
   1818       ash::switches::kAshDefaultWallpaperLarge);
   1819   guest_small_wallpaper_file_ =
   1820       command_line->GetSwitchValuePath(ash::switches::kAshGuestWallpaperSmall);
   1821   guest_large_wallpaper_file_ =
   1822       command_line->GetSwitchValuePath(ash::switches::kAshGuestWallpaperLarge);
   1823   default_wallpaper_image_.reset();
   1824 }
   1825 
   1826 void WallpaperManager::OnDefaultWallpaperDecoded(
   1827     const base::FilePath& path,
   1828     const ash::WallpaperLayout layout,
   1829     scoped_ptr<chromeos::UserImage>* result_out,
   1830     MovableOnDestroyCallbackHolder on_finish,
   1831     const UserImage& user_image) {
   1832   result_out->reset(new UserImage(user_image));
   1833   ash::Shell::GetInstance()->desktop_background_controller()->SetWallpaperImage(
   1834       user_image.image(), layout);
   1835 }
   1836 
   1837 void WallpaperManager::StartLoadAndSetDefaultWallpaper(
   1838     const base::FilePath& path,
   1839     const ash::WallpaperLayout layout,
   1840     MovableOnDestroyCallbackHolder on_finish,
   1841     scoped_ptr<chromeos::UserImage>* result_out) {
   1842   wallpaper_loader_->Start(
   1843       path.value(),
   1844       0,  // Do not crop.
   1845       base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded,
   1846                  weak_factory_.GetWeakPtr(),
   1847                  path,
   1848                  layout,
   1849                  base::Unretained(result_out),
   1850                  base::Passed(on_finish.Pass())));
   1851 }
   1852 
   1853 const char* WallpaperManager::GetCustomWallpaperSubdirForCurrentResolution() {
   1854   WallpaperResolution resolution = GetAppropriateResolution();
   1855   return resolution == WALLPAPER_RESOLUTION_SMALL ? kSmallWallpaperSubDir
   1856                                                   : kLargeWallpaperSubDir;
   1857 }
   1858 
   1859 void WallpaperManager::SetDefaultWallpaperPath(
   1860     const base::FilePath& default_small_wallpaper_file,
   1861     scoped_ptr<gfx::ImageSkia> small_wallpaper_image,
   1862     const base::FilePath& default_large_wallpaper_file,
   1863     scoped_ptr<gfx::ImageSkia> large_wallpaper_image) {
   1864   default_small_wallpaper_file_ = default_small_wallpaper_file;
   1865   default_large_wallpaper_file_ = default_large_wallpaper_file;
   1866 
   1867   ash::DesktopBackgroundController* dbc =
   1868       ash::Shell::GetInstance()->desktop_background_controller();
   1869 
   1870   // |need_update_screen| is true if the previous default wallpaper is visible
   1871   // now, so we need to update wallpaper on the screen.
   1872   //
   1873   // Layout is ignored here, so ash::WALLPAPER_LAYOUT_CENTER is used
   1874   // as a placeholder only.
   1875   const bool need_update_screen =
   1876       default_wallpaper_image_.get() &&
   1877       dbc->WallpaperIsAlreadyLoaded(default_wallpaper_image_->image(),
   1878                                     false /* compare_layouts */,
   1879                                     ash::WALLPAPER_LAYOUT_CENTER);
   1880 
   1881   default_wallpaper_image_.reset();
   1882   if (GetAppropriateResolution() == WALLPAPER_RESOLUTION_SMALL) {
   1883     if (small_wallpaper_image) {
   1884       default_wallpaper_image_.reset(new UserImage(*small_wallpaper_image));
   1885       default_wallpaper_image_->set_file_path(
   1886           default_small_wallpaper_file.value());
   1887     }
   1888   } else {
   1889     if (large_wallpaper_image) {
   1890       default_wallpaper_image_.reset(new UserImage(*large_wallpaper_image));
   1891       default_wallpaper_image_->set_file_path(
   1892           default_large_wallpaper_file.value());
   1893     }
   1894   }
   1895 
   1896   if (need_update_screen) {
   1897     DoSetDefaultWallpaper(std::string(),
   1898                           MovableOnDestroyCallbackHolder().Pass());
   1899   }
   1900 }
   1901 
   1902 void WallpaperManager::CreateSolidDefaultWallpaper() {
   1903   loaded_wallpapers_++;
   1904   SkBitmap bitmap;
   1905   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1, 0);
   1906   bitmap.allocPixels();
   1907   bitmap.eraseColor(kDefaultWallpaperColor);
   1908   const gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
   1909   default_wallpaper_image_.reset(new UserImage(image));
   1910 }
   1911 
   1912 }  // namespace chromeos
   1913