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"
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
;
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|
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
);
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
)
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()) {
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
) {
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
,
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|
202 int FindPublicSession(const chromeos::UserList
& users
) {
205 for (UserList::const_iterator it
= users
.begin();
206 it
!= users
.end(); ++it
, ++i
) {
207 if ((*it
)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
) {
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
{
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_
; }
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) {
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
{
313 explicit MovableOnDestroyCallback(const base::Closure
& callback
)
314 : callback_(callback
) {
317 ~MovableOnDestroyCallback() {
318 if (!callback_
.is_null())
323 base::Closure callback_
;
326 WallpaperManager::PendingWallpaper::PendingWallpaper(
327 const base::TimeDelta delay
,
328 const std::string
& user_id
)
331 on_finish_(new MovableOnDestroyCallback(
332 base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet
,
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
;
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();
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(
394 base::Bind(&WallpaperManager::GetCustomWallpaperInternal
,
395 base::Unretained(manager
),
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());
404 // PendingWallpaper was created and never initialized?
406 // Error. Do not record time.
407 started_load_at_
= base::Time();
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
;
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();
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),
477 pending_inactive_(NULL
) {
478 SetDefaultWallpaperPathsFromCommandLine(
479 base::CommandLine::ForCurrentProcess());
481 chrome::NOTIFICATION_LOGIN_USER_CHANGED
,
482 content::NotificationService::AllSources());
484 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
,
485 content::NotificationService::AllSources());
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(
494 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
);
495 wallpaper_loader_
= new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC
,
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();
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
531 if (!ash::Shell::HasInstance())
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_
)
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();
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();
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(
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();
592 return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
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.
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();
628 if (!user_manager
->IsUserLoggedIn()) {
629 if (!StartupUtils::IsDeviceRegistered())
630 SetDefaultWallpaperDelayed(UserManager::kSignInUser
);
632 InitializeRegisteredDeviceWallpaper();
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
));
643 case chrome::NOTIFICATION_LOGIN_USER_CHANGED
: {
644 ClearDisposableWallpaperCache();
645 BrowserThread::PostDelayedTask(
648 base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper
,
649 weak_factory_
.GetWeakPtr()),
650 base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds
));
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
));
661 should_cache_wallpaper_
= true;
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;
678 NOTREACHED() << "Unexpected notification " << type
;
682 void WallpaperManager::RemoveUserWallpaperInfo(const std::string
& user_id
) {
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
);
693 bool WallpaperManager::ResizeImage(const gfx::ImageSkia
& image
,
694 ash::WallpaperLayout layout
,
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();
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
))
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
) {
715 RoundPositive(static_cast<double>(width
) * vertical_ratio
);
716 resized_height
= preferred_height
;
718 resized_width
= preferred_width
;
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
;
726 resized_width
= width
;
727 resized_height
= height
;
730 gfx::ImageSkia resized_image
= gfx::ImageSkiaOperations::CreateResizedImage(
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
,
742 bitmap
.width() * bitmap
.bytesPerPixel(),
743 kDefaultEncodingQuality
,
747 resized_image
.MakeThreadSafe();
748 *output_skia
= resized_image
;
755 bool WallpaperManager::ResizeAndSaveWallpaper(const gfx::ImageSkia
& image
,
756 const base::FilePath
& path
,
757 ash::WallpaperLayout layout
,
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);
767 scoped_refptr
<base::RefCountedBytes
> data
;
768 if (ResizeImage(image
,
774 return SaveWallpaperInternal(
775 path
, reinterpret_cast<const char*>(data
->front()), data
->size());
780 bool WallpaperManager::IsPolicyControlled(const std::string
& user_id
) const {
781 chromeos::WallpaperInfo info
;
782 if (!GetUserWallpaperInfo(user_id
, &info
))
784 return info
.type
== chromeos::User::POLICY
;
787 void WallpaperManager::OnPolicySet(const std::string
& policy
,
788 const std::string
& user_id
) {
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
) {
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
) {
810 wallpaper_loader_
->Start(
813 base::Bind(&WallpaperManager::SetPolicyControlledWallpaper
,
814 weak_factory_
.GetWeakPtr(),
819 WallpaperManager::WallpaperResolution
820 WallpaperManager::GetAppropriateResolution() {
821 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
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
);
835 NOTREACHED() << "Unknown user.";
838 SetCustomWallpaper(user_id
,
839 user
->username_hash(),
840 "policy-controlled.jpeg",
841 ash::WALLPAPER_LAYOUT_CENTER_CROPPED
,
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())
861 // Don't allow custom wallpapers while policy is in effect.
862 if (type
!= User::POLICY
&& IsPolicyControlled(user_id
))
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
);
876 !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id
);
878 WallpaperInfo wallpaper_info
= {
879 wallpaper_path
.value(),
882 // Date field is not used.
883 base::Time::Now().LocalMidnight()
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(
897 base::Bind(&WallpaperManager::SaveCustomWallpaper
,
898 base::Unretained(this),
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
= {
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())
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
942 if (!ash::Shell::HasInstance())
945 WallpaperResolution resolution
= GetAppropriateResolution();
946 const bool use_small
= (resolution
== WALLPAPER_RESOLUTION_SMALL
);
948 const base::FilePath
* file
= NULL
;
950 if (UserManager::Get()->IsLoggedInAsGuest()) {
952 use_small
? &guest_small_wallpaper_file_
: &guest_large_wallpaper_file_
;
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
;
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_
);
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
);
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
;
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
,
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())
1029 // There is no visible background in kiosk mode.
1030 if (UserManager::Get()->IsLoggedInAsKioskApp())
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();
1041 if (!UserManager::Get()->IsKnownUser(user_id
))
1044 last_selected_user_
= user_id
;
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
);
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
)
1070 current_wallpaper_path_
= wallpaper_path
;
1071 loaded_wallpapers_
++;
1073 GetPendingWallpaper(user_id
, delayed
)
1074 ->ResetSetCustomWallpaper(info
, wallpaper_path
);
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();
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())
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());
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
);
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() {
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
;
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.
1160 for (int cached
= 0;
1161 it
!= users
.end() && cached
< kMaxWallpapersToCache
;
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())
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(
1182 base::Bind(&WallpaperManager::GetCustomWallpaperInternal
,
1183 base::Unretained(this),
1187 false /* do not update wallpaper */,
1188 base::Passed(MovableOnDestroyCallbackHolder())));
1191 LoadWallpaper(user_id
,
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(
1238 base::Bind(&DeleteWallpaperInList
, file_to_remove
),
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())
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
);
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
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
)
1303 if (update_wallpaper
)
1304 current_wallpaper_path_
= wallpaper_path
;
1306 loaded_wallpapers_
++;
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
);
1318 user_id
, info
, update_wallpaper
, wallpaper_path
, on_finish
.Pass());
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.
1340 const base::DictionaryValue
* info_dict
;
1341 if (!g_browser_process
->local_state()->
1342 GetDictionary(prefs::kUsersWallpaperInfo
)->
1343 GetDictionaryWithoutPathExpansion(user_id
, &info_dict
)) {
1347 // Use temporary variables to keep |info| untouched in the error case.
1349 if (!info_dict
->GetString(kNewWallpaperFileNodeName
, &file
))
1352 if (!info_dict
->GetInteger(kNewWallpaperLayoutNodeName
, &layout
))
1355 if (!info_dict
->GetInteger(kNewWallpaperTypeNodeName
, &type
))
1357 std::string date_string
;
1358 if (!info_dict
->GetString(kNewWallpaperDateNodeName
, &date_string
))
1361 if (!base::StringToInt64(date_string
, &date_val
))
1365 info
->layout
= static_cast<ash::WallpaperLayout
>(layout
);
1366 info
->type
= static_cast<User::WallpaperType
>(type
);
1367 info
->date
= base::Time::FromInternalValue(date_val
);
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(
1384 base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess
,
1385 base::Unretained(this),
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
) {
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(
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.
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
,
1452 base::Bind(&WallpaperManager::DoSetDefaultWallpaper
,
1453 base::Unretained(this),
1455 base::Passed(on_finish
.Pass())));
1457 BrowserThread::PostTask(BrowserThread::UI
,
1459 base::Bind(&WallpaperManager::StartLoad
,
1460 base::Unretained(this),
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
,
1486 base::Time::Now().LocalMidnight()
1488 SetUserWallpaperInfo(user_id
, info
, true);
1490 if (update_wallpaper
)
1491 DoSetDefaultWallpaper(user_id
, on_finish
.Pass());
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
,
1527 ash::WALLPAPER_LAYOUT_STRETCH
,
1531 DeleteAllExcept(original_path
);
1533 ResizeAndSaveWallpaper(*image
,
1534 small_wallpaper_path
,
1536 kSmallWallpaperMaxWidth
,
1537 kSmallWallpaperMaxHeight
,
1539 DeleteAllExcept(small_wallpaper_path
);
1540 ResizeAndSaveWallpaper(*image
,
1541 large_wallpaper_path
,
1543 kLargeWallpaperMaxWidth
,
1544 kLargeWallpaperMaxHeight
,
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(),
1564 base::Bind(&WallpaperManager::OnWallpaperDecoded
,
1565 base::Unretained(this),
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
);
1588 delay
= std::accumulate(last_load_times_
.begin(),
1589 last_load_times_
.end(),
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))
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(),
1627 base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperDecoded
,
1628 weak_factory_
.GetWeakPtr(),
1630 base::Passed(rescaled_files
.Pass())));
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.";
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(),
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
,
1688 gfx::ImageSkia
* small_wallpaper_image
,
1689 gfx::ImageSkia
* large_wallpaper_image
) {
1690 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
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());
1720 LOG(WARNING
) << "Failed to save resized customized default wallpaper";
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
,
1736 if (!pending_inactive_
) {
1737 loading_
.push_back(new WallpaperManager::PendingWallpaper(
1738 (delayed
? GetWallpaperLoadDelay()
1739 : base::TimeDelta::FromMilliseconds(0)),
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();
1752 if (i
->get() == pending
) {
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() << "'";
1775 std::string downloaded_file_name
= downloaded_file
.BaseName().value();
1776 scoped_ptr
<CustomizedWallpaperRescaledFiles
> rescaled_files(
1777 new CustomizedWallpaperRescaledFiles(
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(),
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(
1833 base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded
,
1834 weak_factory_
.GetWeakPtr(),
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());
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