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/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
;
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|
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
);
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
)
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()) {
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
) {
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
,
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|
208 int FindPublicSession(const chromeos::UserList
& users
) {
211 for (UserList::const_iterator it
= users
.begin();
212 it
!= users
.end(); ++it
, ++i
) {
213 if ((*it
)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
) {
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
{
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_
; }
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) {
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
{
319 explicit MovableOnDestroyCallback(const base::Closure
& callback
)
320 : callback_(callback
) {
323 ~MovableOnDestroyCallback() {
324 if (!callback_
.is_null())
329 base::Closure callback_
;
332 WallpaperManager::PendingWallpaper::PendingWallpaper(
333 const base::TimeDelta delay
,
334 const std::string
& user_id
)
337 on_finish_(new MovableOnDestroyCallback(
338 base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet
,
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
;
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();
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(
400 base::Bind(&WallpaperManager::GetCustomWallpaperInternal
,
401 base::Unretained(manager
),
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());
410 // PendingWallpaper was created and never initialized?
412 // Error. Do not record time.
413 started_load_at_
= base::Time();
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
;
439 DCHECK(manager
->loading_
.size() > 0);
441 for (WallpaperManager::PendingList::iterator i
= manager
->loading_
.begin();
442 i
!= manager
->loading_
.end();
444 if (i
->get() == this) {
445 manager
->loading_
.erase(i
);
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();
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),
491 pending_inactive_(NULL
) {
492 SetDefaultWallpaperPathsFromCommandLine(
493 base::CommandLine::ForCurrentProcess());
495 chrome::NOTIFICATION_LOGIN_USER_CHANGED
,
496 content::NotificationService::AllSources());
498 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
,
499 content::NotificationService::AllSources());
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(
508 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
);
509 wallpaper_loader_
= new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC
,
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();
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
545 if (!ash::Shell::HasInstance())
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_
)
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();
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();
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(
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();
606 return GetUserWallpaperInfo(UserManager::Get()->GetLoggedInUser()->email(),
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.
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();
642 if (!user_manager
->IsUserLoggedIn()) {
643 if (!StartupUtils::IsDeviceRegistered())
644 SetDefaultWallpaperDelayed(UserManager::kSignInUser
);
646 InitializeRegisteredDeviceWallpaper();
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
));
657 case chrome::NOTIFICATION_LOGIN_USER_CHANGED
: {
658 ClearDisposableWallpaperCache();
659 BrowserThread::PostDelayedTask(
662 base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper
,
663 weak_factory_
.GetWeakPtr()),
664 base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds
));
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
));
675 should_cache_wallpaper_
= true;
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;
692 NOTREACHED() << "Unexpected notification " << type
;
696 void WallpaperManager::RemoveUserWallpaperInfo(const std::string
& user_id
) {
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
);
707 bool WallpaperManager::ResizeImage(const gfx::ImageSkia
& image
,
708 ash::WallpaperLayout layout
,
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();
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
))
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
) {
729 RoundPositive(static_cast<double>(width
) * vertical_ratio
);
730 resized_height
= preferred_height
;
732 resized_width
= preferred_width
;
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
;
740 resized_width
= width
;
741 resized_height
= height
;
744 gfx::ImageSkia resized_image
= gfx::ImageSkiaOperations::CreateResizedImage(
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
,
756 bitmap
.width() * bitmap
.bytesPerPixel(),
757 kDefaultEncodingQuality
,
761 resized_image
.MakeThreadSafe();
762 *output_skia
= resized_image
;
769 bool WallpaperManager::ResizeAndSaveWallpaper(const gfx::ImageSkia
& image
,
770 const base::FilePath
& path
,
771 ash::WallpaperLayout layout
,
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);
781 scoped_refptr
<base::RefCountedBytes
> data
;
782 if (ResizeImage(image
,
788 return SaveWallpaperInternal(
789 path
, reinterpret_cast<const char*>(data
->front()), data
->size());
794 bool WallpaperManager::IsPolicyControlled(const std::string
& user_id
) const {
795 chromeos::WallpaperInfo info
;
796 if (!GetUserWallpaperInfo(user_id
, &info
))
798 return info
.type
== chromeos::User::POLICY
;
801 void WallpaperManager::OnPolicySet(const std::string
& policy
,
802 const std::string
& user_id
) {
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
) {
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
) {
824 wallpaper_loader_
->Start(
827 base::Bind(&WallpaperManager::SetPolicyControlledWallpaper
,
828 weak_factory_
.GetWeakPtr(),
833 WallpaperManager::WallpaperResolution
834 WallpaperManager::GetAppropriateResolution() {
835 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
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() {
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()="
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");
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
);
869 NOTREACHED() << "Unknown user.";
872 SetCustomWallpaper(user_id
,
873 user
->username_hash(),
874 "policy-controlled.jpeg",
875 ash::WALLPAPER_LAYOUT_CENTER_CROPPED
,
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())
895 // Don't allow custom wallpapers while policy is in effect.
896 if (type
!= User::POLICY
&& IsPolicyControlled(user_id
))
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
);
910 !UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id
);
912 WallpaperInfo wallpaper_info
= {
913 wallpaper_path
.value(),
916 // Date field is not used.
917 base::Time::Now().LocalMidnight()
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(
931 base::Bind(&WallpaperManager::SaveCustomWallpaper
,
932 base::Unretained(this),
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
= {
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())
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
976 if (!ash::Shell::HasInstance())
979 WallpaperResolution resolution
= GetAppropriateResolution();
980 const bool use_small
= (resolution
== WALLPAPER_RESOLUTION_SMALL
);
982 const base::FilePath
* file
= NULL
;
984 if (UserManager::Get()->IsLoggedInAsGuest()) {
986 use_small
? &guest_small_wallpaper_file_
: &guest_large_wallpaper_file_
;
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
;
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_
);
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
);
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
;
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
,
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())
1063 // There is no visible background in kiosk mode.
1064 if (UserManager::Get()->IsLoggedInAsKioskApp())
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();
1075 if (!UserManager::Get()->IsKnownUser(user_id
))
1078 last_selected_user_
= user_id
;
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
);
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
)
1104 current_wallpaper_path_
= wallpaper_path
;
1105 loaded_wallpapers_
++;
1107 GetPendingWallpaper(user_id
, delayed
)
1108 ->ResetSetCustomWallpaper(info
, wallpaper_path
);
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();
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())
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());
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
);
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();
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() {
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
;
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.
1208 for (int cached
= 0;
1209 it
!= users
.end() && cached
< kMaxWallpapersToCache
;
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())
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(
1230 base::Bind(&WallpaperManager::GetCustomWallpaperInternal
,
1231 base::Unretained(this),
1235 false /* do not update wallpaper */,
1236 base::Passed(MovableOnDestroyCallbackHolder())));
1239 LoadWallpaper(user_id
,
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(
1286 base::Bind(&DeleteWallpaperInList
, file_to_remove
),
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())
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
);
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
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
)
1351 if (update_wallpaper
)
1352 current_wallpaper_path_
= wallpaper_path
;
1354 loaded_wallpapers_
++;
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
);
1366 user_id
, info
, update_wallpaper
, wallpaper_path
, on_finish
.Pass());
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.
1388 const base::DictionaryValue
* info_dict
;
1389 if (!g_browser_process
->local_state()->
1390 GetDictionary(prefs::kUsersWallpaperInfo
)->
1391 GetDictionaryWithoutPathExpansion(user_id
, &info_dict
)) {
1395 // Use temporary variables to keep |info| untouched in the error case.
1397 if (!info_dict
->GetString(kNewWallpaperFileNodeName
, &file
))
1400 if (!info_dict
->GetInteger(kNewWallpaperLayoutNodeName
, &layout
))
1403 if (!info_dict
->GetInteger(kNewWallpaperTypeNodeName
, &type
))
1405 std::string date_string
;
1406 if (!info_dict
->GetString(kNewWallpaperDateNodeName
, &date_string
))
1409 if (!base::StringToInt64(date_string
, &date_val
))
1413 info
->layout
= static_cast<ash::WallpaperLayout
>(layout
);
1414 info
->type
= static_cast<User::WallpaperType
>(type
);
1415 info
->date
= base::Time::FromInternalValue(date_val
);
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(
1432 base::Bind(&WallpaperManager::MoveCustomWallpapersSuccess
,
1433 base::Unretained(this),
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
) {
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(
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.
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
,
1500 base::Bind(&WallpaperManager::DoSetDefaultWallpaper
,
1501 base::Unretained(this),
1503 base::Passed(on_finish
.Pass())));
1505 BrowserThread::PostTask(BrowserThread::UI
,
1507 base::Bind(&WallpaperManager::StartLoad
,
1508 base::Unretained(this),
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
,
1534 base::Time::Now().LocalMidnight()
1536 SetUserWallpaperInfo(user_id
, info
, true);
1538 if (update_wallpaper
)
1539 DoSetDefaultWallpaper(user_id
, on_finish
.Pass());
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
,
1575 ash::WALLPAPER_LAYOUT_STRETCH
,
1579 DeleteAllExcept(original_path
);
1581 ResizeAndSaveWallpaper(*image
,
1582 small_wallpaper_path
,
1584 kSmallWallpaperMaxWidth
,
1585 kSmallWallpaperMaxHeight
,
1587 DeleteAllExcept(small_wallpaper_path
);
1588 ResizeAndSaveWallpaper(*image
,
1589 large_wallpaper_path
,
1591 kLargeWallpaperMaxWidth
,
1592 kLargeWallpaperMaxHeight
,
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(),
1612 base::Bind(&WallpaperManager::OnWallpaperDecoded
,
1613 base::Unretained(this),
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
);
1636 delay
= std::accumulate(last_load_times_
.begin(),
1637 last_load_times_
.end(),
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))
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(),
1675 base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperDecoded
,
1676 weak_factory_
.GetWeakPtr(),
1678 base::Passed(rescaled_files
.Pass())));
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.";
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(),
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
,
1736 gfx::ImageSkia
* small_wallpaper_image
,
1737 gfx::ImageSkia
* large_wallpaper_image
) {
1738 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
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());
1768 LOG(WARNING
) << "Failed to save resized customized default wallpaper";
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
,
1784 if (!pending_inactive_
) {
1785 loading_
.push_back(new WallpaperManager::PendingWallpaper(
1786 (delayed
? GetWallpaperLoadDelay()
1787 : base::TimeDelta::FromMilliseconds(0)),
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() << "'";
1807 std::string downloaded_file_name
= downloaded_file
.BaseName().value();
1808 scoped_ptr
<CustomizedWallpaperRescaledFiles
> rescaled_files(
1809 new CustomizedWallpaperRescaledFiles(
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(),
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(
1861 base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded
,
1862 weak_factory_
.GetWeakPtr(),
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());
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