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