Remove debug in WallpaperManagerBrowserTest.DisplayChange.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / wallpaper_manager.cc
blob7b2c8584c3dc50c3304b048d3753228e76a993ac
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.
5 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
7 #include <numeric>
8 #include <vector>
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"
52 using content::BrowserThread;
54 namespace chromeos {
56 namespace {
58 // The amount of delay before starts to move custom wallpapers to the new place.
59 const int kMoveCustomWallpaperDelaySeconds = 30;
61 // Default quality for encoding wallpaper.
62 const int kDefaultEncodingQuality = 90;
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";
68 const int kCacheWallpaperDelayMs = 500;
70 // A dictionary pref that maps usernames to wallpaper properties.
71 const char kUserWallpapersProperties[] = "UserWallpapersProperties";
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";
80 // Maximum number of wallpapers cached by CacheUsersWallpapers().
81 const int kMaxWallpapersToCache = 3;
83 // Maximum number of entries in WallpaperManager::last_load_times_ .
84 const size_t kLastLoadsStatsMsMaxSize = 4;
86 // Minimum delay between wallpaper loads, milliseconds.
87 const unsigned kLoadMinDelayMs = 50;
89 // Default wallpaper load delay, milliseconds.
90 const unsigned kLoadDefaultDelayMs = 200;
92 // Maximum wallpaper load delay, milliseconds.
93 const unsigned kLoadMaxDelayMs = 2000;
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));
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);
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;
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);
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();
138 return !(pref_service->FindPreference(
139 prefs::kCustomizationDefaultWallpaperURL)
140 ->IsDefaultValue());
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);
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();
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);
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;
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;
213 return index;
216 } // namespace
218 const char kWallpaperSequenceTokenName[] = "wallpaper-sequence";
220 const char kSmallWallpaperSuffix[] = "_small";
221 const char kLargeWallpaperSuffix[] = "_large";
223 const char kSmallWallpaperSubDir[] = "small";
224 const char kLargeWallpaperSubDir[] = "large";
225 const char kOriginalWallpaperSubDir[] = "original";
226 const char kThumbnailWallpaperSubDir[] = "thumb";
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;
235 static WallpaperManager* g_wallpaper_manager = NULL;
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);
243 bool AllSizesExist() const;
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();
250 const base::FilePath& path_downloaded() const { return path_downloaded_; }
251 const base::FilePath& path_rescaled_small() const {
252 return path_rescaled_small_;
254 const base::FilePath& path_rescaled_large() const {
255 return path_rescaled_large_;
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_; }
262 private:
263 // Must be called on BlockingPool.
264 void CheckCustomizedWallpaperFilesExist();
266 const base::FilePath path_downloaded_;
267 const base::FilePath path_rescaled_small_;
268 const base::FilePath path_rescaled_large_;
270 bool downloaded_exists_;
271 bool rescaled_small_exists_;
272 bool rescaled_large_exists_;
274 DISALLOW_COPY_AND_ASSIGN(CustomizedWallpaperRescaledFiles);
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) {
289 base::Closure
290 WallpaperManager::CustomizedWallpaperRescaledFiles::CreateCheckerClosure() {
291 return base::Bind(&WallpaperManager::CustomizedWallpaperRescaledFiles::
292 CheckCustomizedWallpaperFilesExist,
293 base::Unretained(this));
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_);
304 bool WallpaperManager::CustomizedWallpaperRescaledFiles::AllSizesExist() const {
305 return rescaled_small_exists_ && rescaled_large_exists_;
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) {
317 ~MovableOnDestroyCallback() {
318 if (!callback_.is_null())
319 callback_.Run();
322 private:
323 base::Closure callback_;
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));
340 WallpaperManager::PendingWallpaper::~PendingWallpaper() {}
342 void WallpaperManager::PendingWallpaper::ResetSetWallpaperImage(
343 const gfx::ImageSkia& image,
344 const WallpaperInfo& info) {
345 SetMode(image, info, base::FilePath(), false);
348 void WallpaperManager::PendingWallpaper::ResetLoadWallpaper(
349 const WallpaperInfo& info) {
350 SetMode(gfx::ImageSkia(), info, base::FilePath(), false);
353 void WallpaperManager::PendingWallpaper::ResetSetCustomWallpaper(
354 const WallpaperInfo& info,
355 const base::FilePath& wallpaper_path) {
356 SetMode(gfx::ImageSkia(), info, wallpaper_path, false);
359 void WallpaperManager::PendingWallpaper::ResetSetDefaultWallpaper() {
360 SetMode(gfx::ImageSkia(), WallpaperInfo(), base::FilePath(), true);
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;
374 void WallpaperManager::PendingWallpaper::ProcessRequest() {
375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
377 timer.Stop(); // Erase reference to self.
379 WallpaperManager* manager = WallpaperManager::Get();
380 if (manager->pending_inactive_ == this)
381 manager->pending_inactive_ = NULL;
383 started_load_at_ = base::Time::Now();
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();
409 on_finish_.reset();
412 void WallpaperManager::PendingWallpaper::OnWallpaperSet() {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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.
420 timer.Stop(); // Erase reference to self.
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);
427 if (manager->pending_inactive_ == this) {
428 // ProcessRequest() was never executed.
429 manager->pending_inactive_ = NULL;
432 // Destroy self.
433 manager->RemovePendingWallpaperFromList(this);
436 // WallpaperManager, public: ---------------------------------------------------
438 // TestApi. For testing purpose
439 WallpaperManager::TestApi::TestApi(WallpaperManager* wallpaper_manager)
440 : wallpaper_manager_(wallpaper_manager) {
443 WallpaperManager::TestApi::~TestApi() {
446 base::FilePath WallpaperManager::TestApi::current_wallpaper_path() {
447 return wallpaper_manager_->current_wallpaper_path_;
450 bool WallpaperManager::TestApi::GetWallpaperFromCache(
451 const std::string& user_id, gfx::ImageSkia* image) {
452 return wallpaper_manager_->GetWallpaperFromCache(user_id, image);
455 void WallpaperManager::TestApi::SetWallpaperCache(const std::string& user_id,
456 const gfx::ImageSkia& image) {
457 DCHECK(!image.isNull());
458 wallpaper_manager_->wallpaper_cache_[user_id] = image;
461 void WallpaperManager::TestApi::ClearDisposableWallpaperCache() {
462 wallpaper_manager_->ClearDisposableWallpaperCache();
465 // static
466 WallpaperManager* WallpaperManager::Get() {
467 if (!g_wallpaper_manager)
468 g_wallpaper_manager = new WallpaperManager();
469 return g_wallpaper_manager;
472 WallpaperManager::WallpaperManager()
473 : loaded_wallpapers_(0),
474 command_line_for_testing_(NULL),
475 should_cache_wallpaper_(false),
476 weak_factory_(this),
477 pending_inactive_(NULL) {
478 SetDefaultWallpaperPathsFromCommandLine(
479 base::CommandLine::ForCurrentProcess());
480 registrar_.Add(this,
481 chrome::NOTIFICATION_LOGIN_USER_CHANGED,
482 content::NotificationService::AllSources());
483 registrar_.Add(this,
484 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
485 content::NotificationService::AllSources());
486 registrar_.Add(this,
487 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
488 content::NotificationService::AllSources());
489 sequence_token_ = BrowserThread::GetBlockingPool()->
490 GetNamedSequenceToken(kWallpaperSequenceTokenName);
491 task_runner_ = BrowserThread::GetBlockingPool()->
492 GetSequencedTaskRunnerWithShutdownBehavior(
493 sequence_token_,
494 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
495 wallpaper_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
496 task_runner_);
499 WallpaperManager::~WallpaperManager() {
500 // TODO(bshe): Lifetime of WallpaperManager needs more consideration.
501 // http://crbug.com/171694
502 DCHECK(!show_user_name_on_signin_subscription_);
504 ClearObsoleteWallpaperPrefs();
505 weak_factory_.InvalidateWeakPtrs();
508 void WallpaperManager::Shutdown() {
509 show_user_name_on_signin_subscription_.reset();
512 // static
513 void WallpaperManager::RegisterPrefs(PrefRegistrySimple* registry) {
514 registry->RegisterDictionaryPref(prefs::kUsersWallpaperInfo);
515 registry->RegisterDictionaryPref(kUserWallpapers);
516 registry->RegisterDictionaryPref(kUserWallpapersProperties);
519 void WallpaperManager::AddObservers() {
520 show_user_name_on_signin_subscription_ =
521 CrosSettings::Get()->AddSettingsObserver(
522 kAccountsPrefShowUserNamesOnSignIn,
523 base::Bind(&WallpaperManager::InitializeRegisteredDeviceWallpaper,
524 base::Unretained(this)));
527 void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
528 // Some browser tests do not have a shell instance. As no wallpaper is needed
529 // in these tests anyway, avoid loading one, preventing crashes and speeding
530 // up the tests.
531 if (!ash::Shell::HasInstance())
532 return;
534 WallpaperInfo info;
535 if (GetLoggedInUserWallpaperInfo(&info)) {
536 // TODO(sschmitz): We need an index for default wallpapers for the new UI.
537 RecordUma(info.type, -1);
538 if (info == current_user_wallpaper_info_)
539 return;
541 SetUserWallpaperNow(UserManager::Get()->GetLoggedInUser()->email());
544 void WallpaperManager::ClearDisposableWallpaperCache() {
545 // Cancel callback for previous cache requests.
546 weak_factory_.InvalidateWeakPtrs();
547 if (!UserManager::IsMultipleProfilesAllowed()) {
548 wallpaper_cache_.clear();
549 } else {
550 // Keep the wallpaper of logged in users in cache at multi-profile mode.
551 std::set<std::string> logged_in_users_names;
552 const UserList& logged_users = UserManager::Get()->GetLoggedInUsers();
553 for (UserList::const_iterator it = logged_users.begin();
554 it != logged_users.end();
555 ++it) {
556 logged_in_users_names.insert((*it)->email());
559 CustomWallpaperMap logged_in_users_cache;
560 for (CustomWallpaperMap::iterator it = wallpaper_cache_.begin();
561 it != wallpaper_cache_.end(); ++it) {
562 if (logged_in_users_names.find(it->first) !=
563 logged_in_users_names.end()) {
564 logged_in_users_cache.insert(*it);
567 wallpaper_cache_ = logged_in_users_cache;
571 base::FilePath WallpaperManager::GetCustomWallpaperPath(
572 const char* sub_dir,
573 const std::string& user_id_hash,
574 const std::string& file) const {
575 base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir);
576 return custom_wallpaper_path.Append(user_id_hash).Append(file);
579 bool WallpaperManager::GetLoggedInUserWallpaperInfo(WallpaperInfo* info) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
582 if (UserManager::Get()->IsLoggedInAsStub()) {
583 info->file = current_user_wallpaper_info_.file = "";
584 info->layout = current_user_wallpaper_info_.layout =
585 ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
586 info->type = current_user_wallpaper_info_.type = User::DEFAULT;
587 info->date = current_user_wallpaper_info_.date =
588 base::Time::Now().LocalMidnight();
589 return true;
592 return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
593 info);
596 void WallpaperManager::InitializeWallpaper() {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
598 UserManager* user_manager = UserManager::Get();
600 // Apply device customization.
601 if (ShouldUseCustomizedDefaultWallpaper()) {
602 SetDefaultWallpaperPath(
603 GetCustomizedWallpaperDefaultRescaledFileName(kSmallWallpaperSuffix),
604 scoped_ptr<gfx::ImageSkia>().Pass(),
605 GetCustomizedWallpaperDefaultRescaledFileName(kLargeWallpaperSuffix),
606 scoped_ptr<gfx::ImageSkia>().Pass());
609 CommandLine* command_line = GetCommandLine();
610 if (command_line->HasSwitch(chromeos::switches::kGuestSession)) {
611 // Guest wallpaper should be initialized when guest login.
612 // Note: This maybe called before login. So IsLoggedInAsGuest can not be
613 // used here to determine if current user is guest.
614 return;
617 if (command_line->HasSwitch(::switches::kTestType))
618 WizardController::SetZeroDelays();
620 // Zero delays is also set in autotests.
621 if (WizardController::IsZeroDelayEnabled()) {
622 // Ensure tests have some sort of wallpaper.
623 ash::Shell::GetInstance()->desktop_background_controller()->
624 CreateEmptyWallpaper();
625 return;
628 if (!user_manager->IsUserLoggedIn()) {
629 if (!StartupUtils::IsDeviceRegistered())
630 SetDefaultWallpaperDelayed(UserManager::kSignInUser);
631 else
632 InitializeRegisteredDeviceWallpaper();
633 return;
635 SetUserWallpaperDelayed(user_manager->GetLoggedInUser()->email());
638 void WallpaperManager::Observe(int type,
639 const content::NotificationSource& source,
640 const content::NotificationDetails& details) {
641 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
642 switch (type) {
643 case chrome::NOTIFICATION_LOGIN_USER_CHANGED: {
644 ClearDisposableWallpaperCache();
645 BrowserThread::PostDelayedTask(
646 BrowserThread::UI,
647 FROM_HERE,
648 base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper,
649 weak_factory_.GetWeakPtr()),
650 base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds));
651 break;
653 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
654 if (!GetCommandLine()->HasSwitch(switches::kDisableBootAnimation)) {
655 BrowserThread::PostDelayedTask(
656 BrowserThread::UI, FROM_HERE,
657 base::Bind(&WallpaperManager::CacheUsersWallpapers,
658 weak_factory_.GetWeakPtr()),
659 base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
660 } else {
661 should_cache_wallpaper_ = true;
663 break;
665 case chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED: {
666 NotifyAnimationFinished();
667 if (should_cache_wallpaper_) {
668 BrowserThread::PostDelayedTask(
669 BrowserThread::UI, FROM_HERE,
670 base::Bind(&WallpaperManager::CacheUsersWallpapers,
671 weak_factory_.GetWeakPtr()),
672 base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
673 should_cache_wallpaper_ = false;
675 break;
677 default:
678 NOTREACHED() << "Unexpected notification " << type;
682 void WallpaperManager::RemoveUserWallpaperInfo(const std::string& user_id) {
683 WallpaperInfo info;
684 GetUserWallpaperInfo(user_id, &info);
685 PrefService* prefs = g_browser_process->local_state();
686 DictionaryPrefUpdate prefs_wallpapers_info_update(prefs,
687 prefs::kUsersWallpaperInfo);
688 prefs_wallpapers_info_update->RemoveWithoutPathExpansion(user_id, NULL);
689 DeleteUserWallpapers(user_id, info.file);
692 // static
693 bool WallpaperManager::ResizeImage(const gfx::ImageSkia& image,
694 ash::WallpaperLayout layout,
695 int preferred_width,
696 int preferred_height,
697 scoped_refptr<base::RefCountedBytes>* output,
698 gfx::ImageSkia* output_skia) {
699 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
700 int width = image.width();
701 int height = image.height();
702 int resized_width;
703 int resized_height;
704 *output = new base::RefCountedBytes();
706 if (layout == ash::WALLPAPER_LAYOUT_CENTER_CROPPED) {
707 // Do not resize custom wallpaper if it is smaller than preferred size.
708 if (!(width > preferred_width && height > preferred_height))
709 return false;
711 double horizontal_ratio = static_cast<double>(preferred_width) / width;
712 double vertical_ratio = static_cast<double>(preferred_height) / height;
713 if (vertical_ratio > horizontal_ratio) {
714 resized_width =
715 RoundPositive(static_cast<double>(width) * vertical_ratio);
716 resized_height = preferred_height;
717 } else {
718 resized_width = preferred_width;
719 resized_height =
720 RoundPositive(static_cast<double>(height) * horizontal_ratio);
722 } else if (layout == ash::WALLPAPER_LAYOUT_STRETCH) {
723 resized_width = preferred_width;
724 resized_height = preferred_height;
725 } else {
726 resized_width = width;
727 resized_height = height;
730 gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
731 image,
732 skia::ImageOperations::RESIZE_LANCZOS3,
733 gfx::Size(resized_width, resized_height));
735 SkBitmap bitmap = *(resized_image.bitmap());
736 SkAutoLockPixels lock_input(bitmap);
737 gfx::JPEGCodec::Encode(
738 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
739 gfx::JPEGCodec::FORMAT_SkBitmap,
740 bitmap.width(),
741 bitmap.height(),
742 bitmap.width() * bitmap.bytesPerPixel(),
743 kDefaultEncodingQuality,
744 &(*output)->data());
746 if (output_skia) {
747 resized_image.MakeThreadSafe();
748 *output_skia = resized_image;
751 return true;
754 // static
755 bool WallpaperManager::ResizeAndSaveWallpaper(const gfx::ImageSkia& image,
756 const base::FilePath& path,
757 ash::WallpaperLayout layout,
758 int preferred_width,
759 int preferred_height,
760 gfx::ImageSkia* output_skia) {
761 if (layout == ash::WALLPAPER_LAYOUT_CENTER) {
762 // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
763 if (base::PathExists(path))
764 base::DeleteFile(path, false);
765 return false;
767 scoped_refptr<base::RefCountedBytes> data;
768 if (ResizeImage(image,
769 layout,
770 preferred_width,
771 preferred_height,
772 &data,
773 output_skia)) {
774 return SaveWallpaperInternal(
775 path, reinterpret_cast<const char*>(data->front()), data->size());
777 return false;
780 bool WallpaperManager::IsPolicyControlled(const std::string& user_id) const {
781 chromeos::WallpaperInfo info;
782 if (!GetUserWallpaperInfo(user_id, &info))
783 return false;
784 return info.type == chromeos::User::POLICY;
787 void WallpaperManager::OnPolicySet(const std::string& policy,
788 const std::string& user_id) {
789 WallpaperInfo info;
790 GetUserWallpaperInfo(user_id, &info);
791 info.type = User::POLICY;
792 SetUserWallpaperInfo(user_id, info, true /* is_persistent */);
795 void WallpaperManager::OnPolicyCleared(const std::string& policy,
796 const std::string& user_id) {
797 WallpaperInfo info;
798 GetUserWallpaperInfo(user_id, &info);
799 info.type = User::DEFAULT;
800 SetUserWallpaperInfo(user_id, info, true /* is_persistent */);
801 SetDefaultWallpaperNow(user_id);
804 void WallpaperManager::OnPolicyFetched(const std::string& policy,
805 const std::string& user_id,
806 scoped_ptr<std::string> data) {
807 if (!data)
808 return;
810 wallpaper_loader_->Start(
811 data.Pass(),
812 0, // Do not crop.
813 base::Bind(&WallpaperManager::SetPolicyControlledWallpaper,
814 weak_factory_.GetWeakPtr(),
815 user_id));
818 // static
819 WallpaperManager::WallpaperResolution
820 WallpaperManager::GetAppropriateResolution() {
821 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
822 gfx::Size size =
823 ash::DesktopBackgroundController::GetMaxDisplaySizeInNative();
824 return (size.width() > kSmallWallpaperMaxWidth ||
825 size.height() > kSmallWallpaperMaxHeight)
826 ? WALLPAPER_RESOLUTION_LARGE
827 : WALLPAPER_RESOLUTION_SMALL;
830 void WallpaperManager::SetPolicyControlledWallpaper(
831 const std::string& user_id,
832 const UserImage& user_image) {
833 const User *user = chromeos::UserManager::Get()->FindUser(user_id);
834 if (!user) {
835 NOTREACHED() << "Unknown user.";
836 return;
838 SetCustomWallpaper(user_id,
839 user->username_hash(),
840 "policy-controlled.jpeg",
841 ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
842 User::POLICY,
843 user_image.image(),
844 true /* update wallpaper */);
847 void WallpaperManager::SetCustomWallpaper(const std::string& user_id,
848 const std::string& user_id_hash,
849 const std::string& file,
850 ash::WallpaperLayout layout,
851 User::WallpaperType type,
852 const gfx::ImageSkia& image,
853 bool update_wallpaper) {
854 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
855 DCHECK(UserManager::Get()->IsUserLoggedIn());
857 // There is no visible background in kiosk mode.
858 if (UserManager::Get()->IsLoggedInAsKioskApp())
859 return;
861 // Don't allow custom wallpapers while policy is in effect.
862 if (type != User::POLICY && IsPolicyControlled(user_id))
863 return;
865 base::FilePath wallpaper_path =
866 GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id_hash, file);
868 // If decoded wallpaper is empty, we have probably failed to decode the file.
869 // Use default wallpaper in this case.
870 if (image.isNull()) {
871 SetDefaultWallpaperDelayed(user_id);
872 return;
875 bool is_persistent =
876 !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id);
878 WallpaperInfo wallpaper_info = {
879 wallpaper_path.value(),
880 layout,
881 type,
882 // Date field is not used.
883 base::Time::Now().LocalMidnight()
885 if (is_persistent) {
886 image.EnsureRepsForSupportedScales();
887 scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy());
888 // Block shutdown on this task. Otherwise, we may lose the custom wallpaper
889 // that the user selected.
890 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
891 BrowserThread::GetBlockingPool()
892 ->GetSequencedTaskRunnerWithShutdownBehavior(
893 sequence_token_, base::SequencedWorkerPool::BLOCK_SHUTDOWN);
894 // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
895 blocking_task_runner->PostTask(
896 FROM_HERE,
897 base::Bind(&WallpaperManager::SaveCustomWallpaper,
898 base::Unretained(this),
899 user_id_hash,
900 base::FilePath(wallpaper_info.file),
901 wallpaper_info.layout,
902 base::Passed(deep_copy.Pass())));
905 std::string relative_path = base::FilePath(user_id_hash).Append(file).value();
906 // User's custom wallpaper path is determined by relative path and the
907 // appropriate wallpaper resolution in GetCustomWallpaperInternal.
908 WallpaperInfo info = {
909 relative_path,
910 layout,
911 type,
912 base::Time::Now().LocalMidnight()
914 SetUserWallpaperInfo(user_id, info, is_persistent);
915 if (update_wallpaper) {
916 GetPendingWallpaper(user_id, false)->ResetSetWallpaperImage(image, info);
919 if (UserManager::IsMultipleProfilesAllowed())
920 wallpaper_cache_[user_id] = image;
923 void WallpaperManager::SetDefaultWallpaperNow(const std::string& user_id) {
924 GetPendingWallpaper(user_id, false)->ResetSetDefaultWallpaper();
927 void WallpaperManager::SetDefaultWallpaperDelayed(const std::string& user_id) {
928 GetPendingWallpaper(user_id, true)->ResetSetDefaultWallpaper();
931 void WallpaperManager::DoSetDefaultWallpaper(
932 const std::string& user_id,
933 MovableOnDestroyCallbackHolder on_finish) {
934 // There is no visible background in kiosk mode.
935 if (UserManager::Get()->IsLoggedInAsKioskApp())
936 return;
937 current_wallpaper_path_.clear();
938 wallpaper_cache_.erase(user_id);
939 // Some browser tests do not have a shell instance. As no wallpaper is needed
940 // in these tests anyway, avoid loading one, preventing crashes and speeding
941 // up the tests.
942 if (!ash::Shell::HasInstance())
943 return;
945 WallpaperResolution resolution = GetAppropriateResolution();
946 const bool use_small = (resolution == WALLPAPER_RESOLUTION_SMALL);
948 const base::FilePath* file = NULL;
950 if (UserManager::Get()->IsLoggedInAsGuest()) {
951 file =
952 use_small ? &guest_small_wallpaper_file_ : &guest_large_wallpaper_file_;
953 } else {
954 file = use_small ? &default_small_wallpaper_file_
955 : &default_large_wallpaper_file_;
957 const ash::WallpaperLayout layout =
958 use_small ? ash::WALLPAPER_LAYOUT_CENTER
959 : ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
960 DCHECK(file);
961 if (!default_wallpaper_image_.get() ||
962 default_wallpaper_image_->file_path() != file->value()) {
963 default_wallpaper_image_.reset();
964 if (!file->empty()) {
965 loaded_wallpapers_++;
966 StartLoadAndSetDefaultWallpaper(
967 *file, layout, on_finish.Pass(), &default_wallpaper_image_);
968 return;
971 const int resource_id = use_small ? IDR_AURA_WALLPAPER_DEFAULT_SMALL
972 : IDR_AURA_WALLPAPER_DEFAULT_LARGE;
974 loaded_wallpapers_ += ash::Shell::GetInstance()
975 ->desktop_background_controller()
976 ->SetWallpaperResource(resource_id, layout);
977 return;
979 ash::Shell::GetInstance()->desktop_background_controller()->SetWallpaperImage(
980 default_wallpaper_image_->image(), layout);
983 void WallpaperManager::InitInitialUserWallpaper(const std::string& user_id,
984 bool is_persistent) {
985 current_user_wallpaper_info_.file = "";
986 current_user_wallpaper_info_.layout = ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
987 current_user_wallpaper_info_.type = User::DEFAULT;
988 current_user_wallpaper_info_.date = base::Time::Now().LocalMidnight();
990 WallpaperInfo info = current_user_wallpaper_info_;
991 SetUserWallpaperInfo(user_id, info, is_persistent);
994 void WallpaperManager::SetUserWallpaperInfo(const std::string& user_id,
995 const WallpaperInfo& info,
996 bool is_persistent) {
997 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
998 current_user_wallpaper_info_ = info;
999 if (!is_persistent)
1000 return;
1002 PrefService* local_state = g_browser_process->local_state();
1003 DictionaryPrefUpdate wallpaper_update(local_state,
1004 prefs::kUsersWallpaperInfo);
1006 base::DictionaryValue* wallpaper_info_dict = new base::DictionaryValue();
1007 wallpaper_info_dict->SetString(kNewWallpaperDateNodeName,
1008 base::Int64ToString(info.date.ToInternalValue()));
1009 wallpaper_info_dict->SetString(kNewWallpaperFileNodeName, info.file);
1010 wallpaper_info_dict->SetInteger(kNewWallpaperLayoutNodeName, info.layout);
1011 wallpaper_info_dict->SetInteger(kNewWallpaperTypeNodeName, info.type);
1012 wallpaper_update->SetWithoutPathExpansion(user_id, wallpaper_info_dict);
1015 void WallpaperManager::SetUserWallpaperDelayed(const std::string& user_id) {
1016 ScheduleSetUserWallpaper(user_id, true);
1019 void WallpaperManager::SetUserWallpaperNow(const std::string& user_id) {
1020 ScheduleSetUserWallpaper(user_id, false);
1023 void WallpaperManager::ScheduleSetUserWallpaper(const std::string& user_id,
1024 bool delayed) {
1025 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1026 // Some unit tests come here without a UserManager or without a pref system.
1027 if (!UserManager::IsInitialized() || !g_browser_process->local_state())
1028 return;
1029 // There is no visible background in kiosk mode.
1030 if (UserManager::Get()->IsLoggedInAsKioskApp())
1031 return;
1032 // Guest user, regular user in ephemeral mode, or kiosk app.
1033 const User* user = UserManager::Get()->FindUser(user_id);
1034 if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id) ||
1035 (user != NULL && user->GetType() == User::USER_TYPE_KIOSK_APP)) {
1036 InitInitialUserWallpaper(user_id, false);
1037 GetPendingWallpaper(user_id, delayed)->ResetSetDefaultWallpaper();
1038 return;
1041 if (!UserManager::Get()->IsKnownUser(user_id))
1042 return;
1044 last_selected_user_ = user_id;
1046 WallpaperInfo info;
1048 if (!GetUserWallpaperInfo(user_id, &info)) {
1049 InitInitialUserWallpaper(user_id, true);
1050 GetUserWallpaperInfo(user_id, &info);
1053 gfx::ImageSkia user_wallpaper;
1054 current_user_wallpaper_info_ = info;
1055 if (GetWallpaperFromCache(user_id, &user_wallpaper)) {
1056 GetPendingWallpaper(user_id, delayed)
1057 ->ResetSetWallpaperImage(user_wallpaper, info);
1058 } else {
1059 if (info.type == User::CUSTOMIZED || info.type == User::POLICY) {
1060 const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
1061 // Wallpaper is not resized when layout is ash::WALLPAPER_LAYOUT_CENTER.
1062 // Original wallpaper should be used in this case.
1063 // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
1064 if (info.layout == ash::WALLPAPER_LAYOUT_CENTER)
1065 sub_dir = kOriginalWallpaperSubDir;
1066 base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
1067 wallpaper_path = wallpaper_path.Append(info.file);
1068 if (current_wallpaper_path_ == wallpaper_path)
1069 return;
1070 current_wallpaper_path_ = wallpaper_path;
1071 loaded_wallpapers_++;
1073 GetPendingWallpaper(user_id, delayed)
1074 ->ResetSetCustomWallpaper(info, wallpaper_path);
1075 return;
1078 if (info.file.empty()) {
1079 // Uses default built-in wallpaper when file is empty. Eventually, we
1080 // will only ship one built-in wallpaper in ChromeOS image.
1081 GetPendingWallpaper(user_id, delayed)->ResetSetDefaultWallpaper();
1082 return;
1085 // Load downloaded ONLINE or converted DEFAULT wallpapers.
1086 GetPendingWallpaper(user_id, delayed)->ResetLoadWallpaper(info);
1090 void WallpaperManager::SetWallpaperFromImageSkia(const std::string& user_id,
1091 const gfx::ImageSkia& image,
1092 ash::WallpaperLayout layout,
1093 bool update_wallpaper) {
1094 DCHECK(UserManager::Get()->IsUserLoggedIn());
1096 // There is no visible background in kiosk mode.
1097 if (UserManager::Get()->IsLoggedInAsKioskApp())
1098 return;
1099 WallpaperInfo info;
1100 info.layout = layout;
1101 if (UserManager::IsMultipleProfilesAllowed())
1102 wallpaper_cache_[user_id] = image;
1104 if (update_wallpaper) {
1105 GetPendingWallpaper(last_selected_user_, false /* Not delayed */)
1106 ->ResetSetWallpaperImage(image, info);
1110 void WallpaperManager::UpdateWallpaper(bool clear_cache) {
1111 FOR_EACH_OBSERVER(Observer, observers_, OnUpdateWallpaperForTesting());
1112 if (clear_cache)
1113 wallpaper_cache_.clear();
1114 current_wallpaper_path_.clear();
1115 // For GAIA login flow, the last_selected_user_ may not be set before user
1116 // login. If UpdateWallpaper is called at GAIA login screen, no wallpaper will
1117 // be set. It could result a black screen on external monitors.
1118 // See http://crbug.com/265689 for detail.
1119 if (last_selected_user_.empty()) {
1120 SetDefaultWallpaperNow(UserManager::kSignInUser);
1121 return;
1123 SetUserWallpaperNow(last_selected_user_);
1126 void WallpaperManager::AddObserver(WallpaperManager::Observer* observer) {
1127 observers_.AddObserver(observer);
1130 void WallpaperManager::RemoveObserver(WallpaperManager::Observer* observer) {
1131 observers_.RemoveObserver(observer);
1134 void WallpaperManager::NotifyAnimationFinished() {
1135 FOR_EACH_OBSERVER(
1136 Observer, observers_, OnWallpaperAnimationFinished(last_selected_user_));
1139 // WallpaperManager, private: --------------------------------------------------
1141 bool WallpaperManager::GetWallpaperFromCache(const std::string& user_id,
1142 gfx::ImageSkia* image) {
1143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1144 CustomWallpaperMap::const_iterator it = wallpaper_cache_.find(user_id);
1145 if (it != wallpaper_cache_.end()) {
1146 *image = (*it).second;
1147 return true;
1149 return false;
1152 void WallpaperManager::CacheUsersWallpapers() {
1153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1154 UserList users = UserManager::Get()->GetUsers();
1156 if (!users.empty()) {
1157 UserList::const_iterator it = users.begin();
1158 // Skip the wallpaper of first user in the list. It should have been cached.
1159 it++;
1160 for (int cached = 0;
1161 it != users.end() && cached < kMaxWallpapersToCache;
1162 ++it, ++cached) {
1163 std::string user_id = (*it)->email();
1164 CacheUserWallpaper(user_id);
1169 void WallpaperManager::CacheUserWallpaper(const std::string& user_id) {
1170 if (wallpaper_cache_.find(user_id) != wallpaper_cache_.end())
1171 return;
1172 WallpaperInfo info;
1173 if (GetUserWallpaperInfo(user_id, &info)) {
1174 base::FilePath wallpaper_dir;
1175 base::FilePath wallpaper_path;
1176 if (info.type == User::CUSTOMIZED || info.type == User::POLICY) {
1177 const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution();
1178 base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
1179 wallpaper_path = wallpaper_path.Append(info.file);
1180 task_runner_->PostTask(
1181 FROM_HERE,
1182 base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
1183 base::Unretained(this),
1184 user_id,
1185 info,
1186 wallpaper_path,
1187 false /* do not update wallpaper */,
1188 base::Passed(MovableOnDestroyCallbackHolder())));
1189 return;
1191 LoadWallpaper(user_id,
1192 info,
1193 false /* do not update wallpaper */,
1194 MovableOnDestroyCallbackHolder().Pass());
1198 void WallpaperManager::ClearObsoleteWallpaperPrefs() {
1199 PrefService* prefs = g_browser_process->local_state();
1200 DictionaryPrefUpdate wallpaper_properties_pref(prefs,
1201 kUserWallpapersProperties);
1202 wallpaper_properties_pref->Clear();
1203 DictionaryPrefUpdate wallpapers_pref(prefs, kUserWallpapers);
1204 wallpapers_pref->Clear();
1207 void WallpaperManager::DeleteUserWallpapers(const std::string& user_id,
1208 const std::string& path_to_file) {
1209 std::vector<base::FilePath> file_to_remove;
1210 // Remove small user wallpaper.
1211 base::FilePath wallpaper_path =
1212 GetCustomWallpaperDir(kSmallWallpaperSubDir);
1213 // Remove old directory if exists
1214 file_to_remove.push_back(wallpaper_path.Append(user_id));
1215 wallpaper_path = wallpaper_path.Append(path_to_file).DirName();
1216 file_to_remove.push_back(wallpaper_path);
1218 // Remove large user wallpaper.
1219 wallpaper_path = GetCustomWallpaperDir(kLargeWallpaperSubDir);
1220 file_to_remove.push_back(wallpaper_path.Append(user_id));
1221 wallpaper_path = wallpaper_path.Append(path_to_file);
1222 file_to_remove.push_back(wallpaper_path);
1224 // Remove user wallpaper thumbnail.
1225 wallpaper_path = GetCustomWallpaperDir(kThumbnailWallpaperSubDir);
1226 file_to_remove.push_back(wallpaper_path.Append(user_id));
1227 wallpaper_path = wallpaper_path.Append(path_to_file);
1228 file_to_remove.push_back(wallpaper_path);
1230 // Remove original user wallpaper.
1231 wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
1232 file_to_remove.push_back(wallpaper_path.Append(user_id));
1233 wallpaper_path = wallpaper_path.Append(path_to_file);
1234 file_to_remove.push_back(wallpaper_path);
1236 base::WorkerPool::PostTask(
1237 FROM_HERE,
1238 base::Bind(&DeleteWallpaperInList, file_to_remove),
1239 false);
1242 void WallpaperManager::SetCommandLineForTesting(
1243 base::CommandLine* command_line) {
1244 command_line_for_testing_ = command_line;
1245 SetDefaultWallpaperPathsFromCommandLine(command_line);
1248 CommandLine* WallpaperManager::GetCommandLine() {
1249 CommandLine* command_line = command_line_for_testing_ ?
1250 command_line_for_testing_ : CommandLine::ForCurrentProcess();
1251 return command_line;
1254 void WallpaperManager::InitializeRegisteredDeviceWallpaper() {
1255 if (UserManager::Get()->IsUserLoggedIn())
1256 return;
1258 bool disable_boot_animation =
1259 GetCommandLine()->HasSwitch(switches::kDisableBootAnimation);
1260 bool show_users = true;
1261 bool result = CrosSettings::Get()->GetBoolean(
1262 kAccountsPrefShowUserNamesOnSignIn, &show_users);
1263 DCHECK(result) << "Unable to fetch setting "
1264 << kAccountsPrefShowUserNamesOnSignIn;
1265 const chromeos::UserList& users = UserManager::Get()->GetUsers();
1266 int public_session_user_index = FindPublicSession(users);
1267 if ((!show_users && public_session_user_index == -1) || users.empty()) {
1268 // Boot into sign in form, preload default wallpaper.
1269 SetDefaultWallpaperDelayed(UserManager::kSignInUser);
1270 return;
1273 if (!disable_boot_animation) {
1274 int index = public_session_user_index != -1 ? public_session_user_index : 0;
1275 // Normal boot, load user wallpaper.
1276 // If normal boot animation is disabled wallpaper would be set
1277 // asynchronously once user pods are loaded.
1278 SetUserWallpaperDelayed(users[index]->email());
1282 void WallpaperManager::LoadWallpaper(const std::string& user_id,
1283 const WallpaperInfo& info,
1284 bool update_wallpaper,
1285 MovableOnDestroyCallbackHolder on_finish) {
1286 base::FilePath wallpaper_dir;
1287 base::FilePath wallpaper_path;
1288 if (info.type == User::ONLINE) {
1289 std::string file_name = GURL(info.file).ExtractFileName();
1290 WallpaperResolution resolution = GetAppropriateResolution();
1291 // Only solid color wallpapers have stretch layout and they have only one
1292 // resolution.
1293 if (info.layout != ash::WALLPAPER_LAYOUT_STRETCH &&
1294 resolution == WALLPAPER_RESOLUTION_SMALL) {
1295 file_name = base::FilePath(file_name).InsertBeforeExtension(
1296 kSmallWallpaperSuffix).value();
1298 CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
1299 wallpaper_path = wallpaper_dir.Append(file_name);
1300 if (current_wallpaper_path_ == wallpaper_path)
1301 return;
1303 if (update_wallpaper)
1304 current_wallpaper_path_ = wallpaper_path;
1306 loaded_wallpapers_++;
1307 StartLoad(
1308 user_id, info, update_wallpaper, wallpaper_path, on_finish.Pass());
1309 } else if (info.type == User::DEFAULT) {
1310 // Default wallpapers are migrated from M21 user profiles. A code refactor
1311 // overlooked that case and caused these wallpapers not being loaded at all.
1312 // On some slow devices, it caused login webui not visible after upgrade to
1313 // M26 from M21. See crosbug.com/38429 for details.
1314 base::FilePath user_data_dir;
1315 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
1316 wallpaper_path = user_data_dir.Append(info.file);
1317 StartLoad(
1318 user_id, info, update_wallpaper, wallpaper_path, on_finish.Pass());
1319 } else {
1320 // In unexpected cases, revert to default wallpaper to fail safely. See
1321 // crosbug.com/38429.
1322 LOG(ERROR) << "Wallpaper reverts to default unexpected.";
1323 DoSetDefaultWallpaper(user_id, on_finish.Pass());
1327 bool WallpaperManager::GetUserWallpaperInfo(const std::string& user_id,
1328 WallpaperInfo* info) const {
1329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1331 if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id)) {
1332 // Default to the values cached in memory.
1333 *info = current_user_wallpaper_info_;
1335 // Ephemeral users do not save anything to local state. But we have got
1336 // wallpaper info from memory. Returns true.
1337 return true;
1340 const base::DictionaryValue* info_dict;
1341 if (!g_browser_process->local_state()->
1342 GetDictionary(prefs::kUsersWallpaperInfo)->
1343 GetDictionaryWithoutPathExpansion(user_id, &info_dict)) {
1344 return false;
1347 // Use temporary variables to keep |info| untouched in the error case.
1348 std::string file;
1349 if (!info_dict->GetString(kNewWallpaperFileNodeName, &file))
1350 return false;
1351 int layout;
1352 if (!info_dict->GetInteger(kNewWallpaperLayoutNodeName, &layout))
1353 return false;
1354 int type;
1355 if (!info_dict->GetInteger(kNewWallpaperTypeNodeName, &type))
1356 return false;
1357 std::string date_string;
1358 if (!info_dict->GetString(kNewWallpaperDateNodeName, &date_string))
1359 return false;
1360 int64 date_val;
1361 if (!base::StringToInt64(date_string, &date_val))
1362 return false;
1364 info->file = file;
1365 info->layout = static_cast<ash::WallpaperLayout>(layout);
1366 info->type = static_cast<User::WallpaperType>(type);
1367 info->date = base::Time::FromInternalValue(date_val);
1368 return true;
1371 void WallpaperManager::MoveCustomWallpapersOnWorker(
1372 const std::string& user_id,
1373 const std::string& user_id_hash) {
1374 DCHECK(BrowserThread::GetBlockingPool()->
1375 IsRunningSequenceOnCurrentThread(sequence_token_));
1376 if (MoveCustomWallpaperDirectory(
1377 kOriginalWallpaperSubDir, user_id, user_id_hash)) {
1378 // Consider success if the original wallpaper is moved to the new directory.
1379 // Original wallpaper is the fallback if the correct resolution wallpaper
1380 // can not be found.
1381 BrowserThread::PostTask(
1382 BrowserThread::UI,
1383 FROM_HERE,
1384 base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess,
1385 base::Unretained(this),
1386 user_id,
1387 user_id_hash));
1389 MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, user_id, user_id_hash);
1390 MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, user_id, user_id_hash);
1391 MoveCustomWallpaperDirectory(
1392 kThumbnailWallpaperSubDir, user_id, user_id_hash);
1395 void WallpaperManager::MoveCustomWallpapersSuccess(
1396 const std::string& user_id,
1397 const std::string& user_id_hash) {
1398 WallpaperInfo info;
1399 GetUserWallpaperInfo(user_id, &info);
1400 if (info.type == User::CUSTOMIZED) {
1401 // New file field should include user id hash in addition to file name.
1402 // This is needed because at login screen, user id hash is not available.
1403 std::string relative_path =
1404 base::FilePath(user_id_hash).Append(info.file).value();
1405 info.file = relative_path;
1406 bool is_persistent =
1407 !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id);
1408 SetUserWallpaperInfo(user_id, info, is_persistent);
1412 void WallpaperManager::MoveLoggedInUserCustomWallpaper() {
1413 const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
1414 task_runner_->PostTask(
1415 FROM_HERE,
1416 base::Bind(&WallpaperManager::MoveCustomWallpapersOnWorker,
1417 base::Unretained(this),
1418 logged_in_user->email(),
1419 logged_in_user->username_hash()));
1422 void WallpaperManager::GetCustomWallpaperInternal(
1423 const std::string& user_id,
1424 const WallpaperInfo& info,
1425 const base::FilePath& wallpaper_path,
1426 bool update_wallpaper,
1427 MovableOnDestroyCallbackHolder on_finish) {
1428 DCHECK(BrowserThread::GetBlockingPool()->
1429 IsRunningSequenceOnCurrentThread(sequence_token_));
1431 base::FilePath valid_path = wallpaper_path;
1432 if (!base::PathExists(wallpaper_path)) {
1433 // Falls back on original file if the correct resolution file does not
1434 // exist. This may happen when the original custom wallpaper is small or
1435 // browser shutdown before resized wallpaper saved.
1436 valid_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
1437 valid_path = valid_path.Append(info.file);
1440 if (!base::PathExists(valid_path)) {
1441 // Falls back to custom wallpaper that uses email as part of its file path.
1442 // Note that email is used instead of user_id_hash here.
1443 valid_path =
1444 GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id, info.file);
1447 if (!base::PathExists(valid_path)) {
1448 LOG(ERROR) << "Failed to load previously selected custom wallpaper. " <<
1449 "Fallback to default wallpaper";
1450 BrowserThread::PostTask(BrowserThread::UI,
1451 FROM_HERE,
1452 base::Bind(&WallpaperManager::DoSetDefaultWallpaper,
1453 base::Unretained(this),
1454 user_id,
1455 base::Passed(on_finish.Pass())));
1456 } else {
1457 BrowserThread::PostTask(BrowserThread::UI,
1458 FROM_HERE,
1459 base::Bind(&WallpaperManager::StartLoad,
1460 base::Unretained(this),
1461 user_id,
1462 info,
1463 update_wallpaper,
1464 valid_path,
1465 base::Passed(on_finish.Pass())));
1469 void WallpaperManager::OnWallpaperDecoded(
1470 const std::string& user_id,
1471 ash::WallpaperLayout layout,
1472 bool update_wallpaper,
1473 MovableOnDestroyCallbackHolder on_finish,
1474 const UserImage& user_image) {
1475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1476 TRACE_EVENT_ASYNC_END0("ui", "LoadAndDecodeWallpaper", this);
1478 // If decoded wallpaper is empty, we have probably failed to decode the file.
1479 // Use default wallpaper in this case.
1480 if (user_image.image().isNull()) {
1481 // Updates user pref to default wallpaper.
1482 WallpaperInfo info = {
1484 ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
1485 User::DEFAULT,
1486 base::Time::Now().LocalMidnight()
1488 SetUserWallpaperInfo(user_id, info, true);
1490 if (update_wallpaper)
1491 DoSetDefaultWallpaper(user_id, on_finish.Pass());
1492 return;
1495 // Only cache the user wallpaper at login screen and for multi profile users.
1496 if (!UserManager::Get()->IsUserLoggedIn() ||
1497 UserManager::IsMultipleProfilesAllowed()) {
1498 wallpaper_cache_[user_id] = user_image.image();
1501 if (update_wallpaper) {
1502 ash::Shell::GetInstance()
1503 ->desktop_background_controller()
1504 ->SetWallpaperImage(user_image.image(), layout);
1508 void WallpaperManager::SaveCustomWallpaper(
1509 const std::string& user_id_hash,
1510 const base::FilePath& original_path,
1511 ash::WallpaperLayout layout,
1512 scoped_ptr<gfx::ImageSkia> image) const {
1513 DCHECK(BrowserThread::GetBlockingPool()->
1514 IsRunningSequenceOnCurrentThread(sequence_token_));
1515 EnsureCustomWallpaperDirectories(user_id_hash);
1516 std::string file_name = original_path.BaseName().value();
1517 base::FilePath small_wallpaper_path =
1518 GetCustomWallpaperPath(kSmallWallpaperSubDir, user_id_hash, file_name);
1519 base::FilePath large_wallpaper_path =
1520 GetCustomWallpaperPath(kLargeWallpaperSubDir, user_id_hash, file_name);
1522 // Re-encode orginal file to jpeg format and saves the result in case that
1523 // resized wallpaper is not generated (i.e. chrome shutdown before resized
1524 // wallpaper is saved).
1525 ResizeAndSaveWallpaper(*image,
1526 original_path,
1527 ash::WALLPAPER_LAYOUT_STRETCH,
1528 image->width(),
1529 image->height(),
1530 NULL);
1531 DeleteAllExcept(original_path);
1533 ResizeAndSaveWallpaper(*image,
1534 small_wallpaper_path,
1535 layout,
1536 kSmallWallpaperMaxWidth,
1537 kSmallWallpaperMaxHeight,
1538 NULL);
1539 DeleteAllExcept(small_wallpaper_path);
1540 ResizeAndSaveWallpaper(*image,
1541 large_wallpaper_path,
1542 layout,
1543 kLargeWallpaperMaxWidth,
1544 kLargeWallpaperMaxHeight,
1545 NULL);
1546 DeleteAllExcept(large_wallpaper_path);
1549 void WallpaperManager::RecordUma(User::WallpaperType type, int index) const {
1550 UMA_HISTOGRAM_ENUMERATION("Ash.Wallpaper.Type", type,
1551 User::WALLPAPER_TYPE_COUNT);
1554 void WallpaperManager::StartLoad(const std::string& user_id,
1555 const WallpaperInfo& info,
1556 bool update_wallpaper,
1557 const base::FilePath& wallpaper_path,
1558 MovableOnDestroyCallbackHolder on_finish) {
1559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1560 TRACE_EVENT_ASYNC_BEGIN0("ui", "LoadAndDecodeWallpaper", this);
1562 wallpaper_loader_->Start(wallpaper_path.value(),
1563 0, // Do not crop.
1564 base::Bind(&WallpaperManager::OnWallpaperDecoded,
1565 base::Unretained(this),
1566 user_id,
1567 info.layout,
1568 update_wallpaper,
1569 base::Passed(on_finish.Pass())));
1572 void WallpaperManager::SaveLastLoadTime(const base::TimeDelta elapsed) {
1573 while (last_load_times_.size() >= kLastLoadsStatsMsMaxSize)
1574 last_load_times_.pop_front();
1576 if (elapsed > base::TimeDelta::FromMicroseconds(0)) {
1577 last_load_times_.push_back(elapsed);
1578 last_load_finished_at_ = base::Time::Now();
1582 base::TimeDelta WallpaperManager::GetWallpaperLoadDelay() const {
1583 base::TimeDelta delay;
1585 if (last_load_times_.size() == 0) {
1586 delay = base::TimeDelta::FromMilliseconds(kLoadDefaultDelayMs);
1587 } else {
1588 delay = std::accumulate(last_load_times_.begin(),
1589 last_load_times_.end(),
1590 base::TimeDelta(),
1591 std::plus<base::TimeDelta>()) /
1592 last_load_times_.size();
1595 if (delay < base::TimeDelta::FromMilliseconds(kLoadMinDelayMs))
1596 delay = base::TimeDelta::FromMilliseconds(kLoadMinDelayMs);
1597 else if (delay > base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs))
1598 delay = base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs);
1600 // If we had ever loaded wallpaper, adjust wait delay by time since last load.
1601 if (!last_load_finished_at_.is_null()) {
1602 const base::TimeDelta interval = base::Time::Now() - last_load_finished_at_;
1603 if (interval > delay)
1604 delay = base::TimeDelta::FromMilliseconds(0);
1605 else if (interval > base::TimeDelta::FromMilliseconds(0))
1606 delay -= interval;
1608 return delay;
1611 void WallpaperManager::SetCustomizedDefaultWallpaperAfterCheck(
1612 const GURL& wallpaper_url,
1613 const base::FilePath& downloaded_file,
1614 scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files) {
1615 PrefService* pref_service = g_browser_process->local_state();
1617 std::string current_url =
1618 pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
1619 if (current_url != wallpaper_url.spec() || !rescaled_files->AllSizesExist()) {
1620 DCHECK(rescaled_files->downloaded_exists());
1622 // Either resized images do not exist or cached version is incorrect.
1623 // Need to start resize again.
1624 wallpaper_loader_->Start(
1625 downloaded_file.value(),
1626 0, // Do not crop.
1627 base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperDecoded,
1628 weak_factory_.GetWeakPtr(),
1629 wallpaper_url,
1630 base::Passed(rescaled_files.Pass())));
1631 } else {
1632 SetDefaultWallpaperPath(rescaled_files->path_rescaled_small(),
1633 scoped_ptr<gfx::ImageSkia>().Pass(),
1634 rescaled_files->path_rescaled_large(),
1635 scoped_ptr<gfx::ImageSkia>().Pass());
1639 void WallpaperManager::OnCustomizedDefaultWallpaperDecoded(
1640 const GURL& wallpaper_url,
1641 scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files,
1642 const UserImage& wallpaper) {
1643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1645 // If decoded wallpaper is empty, we have probably failed to decode the file.
1646 if (wallpaper.image().isNull()) {
1647 LOG(WARNING) << "Failed to decode customized wallpaper.";
1648 return;
1651 wallpaper.image().EnsureRepsForSupportedScales();
1652 scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper.image().DeepCopy());
1654 scoped_ptr<bool> success(new bool(false));
1655 scoped_ptr<gfx::ImageSkia> small_wallpaper_image(new gfx::ImageSkia);
1656 scoped_ptr<gfx::ImageSkia> large_wallpaper_image(new gfx::ImageSkia);
1658 // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
1659 base::Closure resize_closure =
1660 base::Bind(&WallpaperManager::ResizeCustomizedDefaultWallpaper,
1661 base::Unretained(this),
1662 base::Passed(&deep_copy),
1663 wallpaper.raw_image(),
1664 base::Unretained(rescaled_files.get()),
1665 base::Unretained(success.get()),
1666 base::Unretained(small_wallpaper_image.get()),
1667 base::Unretained(large_wallpaper_image.get()));
1668 base::Closure on_resized_closure =
1669 base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperResized,
1670 weak_factory_.GetWeakPtr(),
1671 wallpaper_url,
1672 base::Passed(rescaled_files.Pass()),
1673 base::Passed(success.Pass()),
1674 base::Passed(small_wallpaper_image.Pass()),
1675 base::Passed(large_wallpaper_image.Pass()));
1677 if (!task_runner_->PostTaskAndReply(
1678 FROM_HERE, resize_closure, on_resized_closure)) {
1679 LOG(WARNING) << "Failed to start Customized Wallpaper resize.";
1683 void WallpaperManager::ResizeCustomizedDefaultWallpaper(
1684 scoped_ptr<gfx::ImageSkia> image,
1685 const UserImage::RawImage& raw_image,
1686 const CustomizedWallpaperRescaledFiles* rescaled_files,
1687 bool* success,
1688 gfx::ImageSkia* small_wallpaper_image,
1689 gfx::ImageSkia* large_wallpaper_image) {
1690 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
1691 sequence_token_));
1693 *success = true;
1695 *success &= ResizeAndSaveWallpaper(*image,
1696 rescaled_files->path_rescaled_small(),
1697 ash::WALLPAPER_LAYOUT_STRETCH,
1698 kSmallWallpaperMaxWidth,
1699 kSmallWallpaperMaxHeight,
1700 small_wallpaper_image);
1702 *success &= ResizeAndSaveWallpaper(*image,
1703 rescaled_files->path_rescaled_large(),
1704 ash::WALLPAPER_LAYOUT_STRETCH,
1705 kLargeWallpaperMaxWidth,
1706 kLargeWallpaperMaxHeight,
1707 large_wallpaper_image);
1710 void WallpaperManager::OnCustomizedDefaultWallpaperResized(
1711 const GURL& wallpaper_url,
1712 scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files,
1713 scoped_ptr<bool> success,
1714 scoped_ptr<gfx::ImageSkia> small_wallpaper_image,
1715 scoped_ptr<gfx::ImageSkia> large_wallpaper_image) {
1716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1717 DCHECK(rescaled_files);
1718 DCHECK(success.get());
1719 if (!*success) {
1720 LOG(WARNING) << "Failed to save resized customized default wallpaper";
1721 return;
1723 PrefService* pref_service = g_browser_process->local_state();
1724 pref_service->SetString(prefs::kCustomizationDefaultWallpaperURL,
1725 wallpaper_url.spec());
1726 SetDefaultWallpaperPath(rescaled_files->path_rescaled_small(),
1727 small_wallpaper_image.Pass(),
1728 rescaled_files->path_rescaled_large(),
1729 large_wallpaper_image.Pass());
1730 VLOG(1) << "Customized default wallpaper applied.";
1733 WallpaperManager::PendingWallpaper* WallpaperManager::GetPendingWallpaper(
1734 const std::string& user_id,
1735 bool delayed) {
1736 if (!pending_inactive_) {
1737 loading_.push_back(new WallpaperManager::PendingWallpaper(
1738 (delayed ? GetWallpaperLoadDelay()
1739 : base::TimeDelta::FromMilliseconds(0)),
1740 user_id));
1741 pending_inactive_ = loading_.back();
1743 return pending_inactive_;
1746 void WallpaperManager::RemovePendingWallpaperFromList(
1747 PendingWallpaper* pending) {
1748 DCHECK(loading_.size() > 0);
1749 for (WallpaperManager::PendingList::iterator i = loading_.begin();
1750 i != loading_.end();
1751 ++i) {
1752 if (i->get() == pending) {
1753 loading_.erase(i);
1754 break;
1758 if (loading_.empty())
1759 FOR_EACH_OBSERVER(Observer, observers_, OnPendingListEmptyForTesting());
1762 void WallpaperManager::SetCustomizedDefaultWallpaper(
1763 const GURL& wallpaper_url,
1764 const base::FilePath& downloaded_file,
1765 const base::FilePath& resized_directory) {
1766 // Should fail if this ever happens in tests.
1767 DCHECK(wallpaper_url.is_valid());
1768 if (!wallpaper_url.is_valid()) {
1769 if (!wallpaper_url.is_empty()) {
1770 LOG(WARNING) << "Invalid Customized Wallpaper URL '"
1771 << wallpaper_url.spec() << "'";
1773 return;
1775 std::string downloaded_file_name = downloaded_file.BaseName().value();
1776 scoped_ptr<CustomizedWallpaperRescaledFiles> rescaled_files(
1777 new CustomizedWallpaperRescaledFiles(
1778 downloaded_file,
1779 resized_directory.Append(downloaded_file_name +
1780 kSmallWallpaperSuffix),
1781 resized_directory.Append(downloaded_file_name +
1782 kLargeWallpaperSuffix)));
1784 base::Closure check_file_exists = rescaled_files->CreateCheckerClosure();
1785 base::Closure on_checked_closure =
1786 base::Bind(&WallpaperManager::SetCustomizedDefaultWallpaperAfterCheck,
1787 weak_factory_.GetWeakPtr(),
1788 wallpaper_url,
1789 downloaded_file,
1790 base::Passed(rescaled_files.Pass()));
1791 if (!BrowserThread::PostBlockingPoolTaskAndReply(
1792 FROM_HERE, check_file_exists, on_checked_closure)) {
1793 LOG(WARNING) << "Failed to start check CheckCustomizedWallpaperFilesExist.";
1797 size_t WallpaperManager::GetPendingListSizeForTesting() const {
1798 return loading_.size();
1801 void WallpaperManager::SetDefaultWallpaperPathsFromCommandLine(
1802 base::CommandLine* command_line) {
1803 default_small_wallpaper_file_ = command_line->GetSwitchValuePath(
1804 ash::switches::kAshDefaultWallpaperSmall);
1805 default_large_wallpaper_file_ = command_line->GetSwitchValuePath(
1806 ash::switches::kAshDefaultWallpaperLarge);
1807 guest_small_wallpaper_file_ =
1808 command_line->GetSwitchValuePath(ash::switches::kAshGuestWallpaperSmall);
1809 guest_large_wallpaper_file_ =
1810 command_line->GetSwitchValuePath(ash::switches::kAshGuestWallpaperLarge);
1811 default_wallpaper_image_.reset();
1814 void WallpaperManager::OnDefaultWallpaperDecoded(
1815 const base::FilePath& path,
1816 const ash::WallpaperLayout layout,
1817 scoped_ptr<chromeos::UserImage>* result_out,
1818 MovableOnDestroyCallbackHolder on_finish,
1819 const UserImage& user_image) {
1820 result_out->reset(new UserImage(user_image));
1821 ash::Shell::GetInstance()->desktop_background_controller()->SetWallpaperImage(
1822 user_image.image(), layout);
1825 void WallpaperManager::StartLoadAndSetDefaultWallpaper(
1826 const base::FilePath& path,
1827 const ash::WallpaperLayout layout,
1828 MovableOnDestroyCallbackHolder on_finish,
1829 scoped_ptr<chromeos::UserImage>* result_out) {
1830 wallpaper_loader_->Start(
1831 path.value(),
1832 0, // Do not crop.
1833 base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded,
1834 weak_factory_.GetWeakPtr(),
1835 path,
1836 layout,
1837 base::Unretained(result_out),
1838 base::Passed(on_finish.Pass())));
1841 const char* WallpaperManager::GetCustomWallpaperSubdirForCurrentResolution() {
1842 WallpaperResolution resolution = GetAppropriateResolution();
1843 return resolution == WALLPAPER_RESOLUTION_SMALL ? kSmallWallpaperSubDir
1844 : kLargeWallpaperSubDir;
1847 void WallpaperManager::SetDefaultWallpaperPath(
1848 const base::FilePath& default_small_wallpaper_file,
1849 scoped_ptr<gfx::ImageSkia> small_wallpaper_image,
1850 const base::FilePath& default_large_wallpaper_file,
1851 scoped_ptr<gfx::ImageSkia> large_wallpaper_image) {
1852 default_small_wallpaper_file_ = default_small_wallpaper_file;
1853 default_large_wallpaper_file_ = default_large_wallpaper_file;
1855 ash::DesktopBackgroundController* dbc =
1856 ash::Shell::GetInstance()->desktop_background_controller();
1858 // |need_update_screen| is true if the previous default wallpaper is visible
1859 // now, so we need to update wallpaper on the screen.
1861 // Layout is ignored here, so ash::WALLPAPER_LAYOUT_CENTER is used
1862 // as a placeholder only.
1863 const bool need_update_screen =
1864 default_wallpaper_image_.get() &&
1865 dbc->WallpaperIsAlreadyLoaded(
1866 &(default_wallpaper_image_->image()),
1867 ash::DesktopBackgroundController::kInvalidResourceID,
1868 false /* compare_layouts */,
1869 ash::WALLPAPER_LAYOUT_CENTER);
1871 default_wallpaper_image_.reset();
1872 if (GetAppropriateResolution() == WALLPAPER_RESOLUTION_SMALL) {
1873 if (small_wallpaper_image) {
1874 default_wallpaper_image_.reset(new UserImage(*small_wallpaper_image));
1875 default_wallpaper_image_->set_file_path(
1876 default_small_wallpaper_file.value());
1878 } else {
1879 if (large_wallpaper_image) {
1880 default_wallpaper_image_.reset(new UserImage(*large_wallpaper_image));
1881 default_wallpaper_image_->set_file_path(
1882 default_large_wallpaper_file.value());
1886 if (need_update_screen) {
1887 DoSetDefaultWallpaper(std::string(),
1888 MovableOnDestroyCallbackHolder().Pass());
1892 } // namespace chromeos