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