1 // Copyright 2014 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 "components/wallpaper/wallpaper_manager_base.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/path_service.h"
16 #include "base/prefs/pref_registry_simple.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/prefs/scoped_user_pref_update.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/sys_info.h"
23 #include "base/threading/worker_pool.h"
24 #include "base/time/time.h"
25 #include "base/values.h"
26 #include "chromeos/chromeos_switches.h"
27 #include "chromeos/cryptohome/async_method_caller.h"
28 #include "chromeos/dbus/dbus_thread_manager.h"
29 #include "chromeos/login/user_names.h"
30 #include "components/user_manager/user.h"
31 #include "components/user_manager/user_image/user_image.h"
32 #include "components/user_manager/user_manager.h"
33 #include "components/user_manager/user_type.h"
34 #include "components/wallpaper/wallpaper_layout.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "third_party/skia/include/core/SkColor.h"
37 #include "ui/gfx/codec/jpeg_codec.h"
38 #include "ui/gfx/geometry/safe_integer_conversions.h"
39 #include "ui/gfx/image/image_skia_operations.h"
40 #include "ui/gfx/skia_util.h"
42 using content::BrowserThread
;
48 // Default quality for encoding wallpaper.
49 const int kDefaultEncodingQuality
= 90;
51 // Maximum number of wallpapers cached by CacheUsersWallpapers().
52 const int kMaxWallpapersToCache
= 3;
54 // Maximum number of entries in WallpaperManagerBase::last_load_times_ .
55 const size_t kLastLoadsStatsMsMaxSize
= 4;
57 // Minimum delay between wallpaper loads, milliseconds.
58 const unsigned kLoadMinDelayMs
= 50;
60 // Default wallpaper load delay, milliseconds.
61 const unsigned kLoadDefaultDelayMs
= 200;
63 // Maximum wallpaper load delay, milliseconds.
64 const unsigned kLoadMaxDelayMs
= 2000;
66 // When no wallpaper image is specified, the screen is filled with a solid
68 const SkColor kDefaultWallpaperColor
= SK_ColorGRAY
;
70 // The path ids for directories.
71 int dir_user_data_path_id
= -1; // chrome::DIR_USER_DATA
72 int dir_chromeos_wallpapers_path_id
= -1; // chrome::DIR_CHROMEOS_WALLPAPERS
73 int dir_chromeos_custom_wallpapers_path_id
=
74 -1; // chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS
76 bool MoveCustomWallpaperDirectory(const char* sub_dir
,
77 const std::string
& user_id
,
78 const std::string
& user_id_hash
) {
79 base::FilePath base_path
=
80 WallpaperManagerBase::GetCustomWallpaperDir(sub_dir
);
81 base::FilePath to_path
= base_path
.Append(user_id_hash
);
82 base::FilePath from_path
= base_path
.Append(user_id
);
83 if (base::PathExists(from_path
))
84 return base::Move(from_path
, to_path
);
88 // Deletes a list of wallpaper files in |file_list|.
89 void DeleteWallpaperInList(const std::vector
<base::FilePath
>& file_list
) {
90 for (std::vector
<base::FilePath
>::const_iterator it
= file_list
.begin();
91 it
!= file_list
.end(); ++it
) {
92 base::FilePath path
= *it
;
93 // Some users may still have legacy wallpapers with png extension. We need
94 // to delete these wallpapers too.
95 if (!base::DeleteFile(path
, true) &&
96 !base::DeleteFile(path
.AddExtension(".png"), false)) {
97 LOG(ERROR
) << "Failed to remove user wallpaper at " << path
.value();
102 // Creates all new custom wallpaper directories for |user_id_hash| if not exist.
104 void EnsureCustomWallpaperDirectories(const std::string
& user_id_hash
) {
106 dir
= WallpaperManagerBase::GetCustomWallpaperDir(kSmallWallpaperSubDir
);
107 dir
= dir
.Append(user_id_hash
);
108 if (!base::PathExists(dir
))
109 base::CreateDirectory(dir
);
110 dir
= WallpaperManagerBase::GetCustomWallpaperDir(kLargeWallpaperSubDir
);
111 dir
= dir
.Append(user_id_hash
);
112 if (!base::PathExists(dir
))
113 base::CreateDirectory(dir
);
114 dir
= WallpaperManagerBase::GetCustomWallpaperDir(kOriginalWallpaperSubDir
);
115 dir
= dir
.Append(user_id_hash
);
116 if (!base::PathExists(dir
))
117 base::CreateDirectory(dir
);
118 dir
= WallpaperManagerBase::GetCustomWallpaperDir(kThumbnailWallpaperSubDir
);
119 dir
= dir
.Append(user_id_hash
);
120 if (!base::PathExists(dir
))
121 base::CreateDirectory(dir
);
124 // Saves wallpaper image raw |data| to |path| (absolute path) in file system.
125 // Returns true on success.
126 bool SaveWallpaperInternal(const base::FilePath
& path
,
129 int written_bytes
= base::WriteFile(path
, data
, size
);
130 return written_bytes
== size
;
135 MovableOnDestroyCallback::MovableOnDestroyCallback(
136 const base::Closure
& callback
)
137 : callback_(callback
) {
140 MovableOnDestroyCallback::~MovableOnDestroyCallback() {
141 if (!callback_
.is_null())
145 WallpaperInfo::WallpaperInfo()
146 : layout(WALLPAPER_LAYOUT_CENTER
),
147 type(user_manager::User::WALLPAPER_TYPE_COUNT
) {
150 WallpaperInfo::WallpaperInfo(const std::string
& in_location
,
151 WallpaperLayout in_layout
,
152 user_manager::User::WallpaperType in_type
,
153 const base::Time
& in_date
)
154 : location(in_location
),
160 WallpaperInfo::~WallpaperInfo() {
163 const char kWallpaperSequenceTokenName
[] = "wallpaper-sequence";
165 const char kSmallWallpaperSuffix
[] = "_small";
166 const char kLargeWallpaperSuffix
[] = "_large";
168 const char kSmallWallpaperSubDir
[] = "small";
169 const char kLargeWallpaperSubDir
[] = "large";
170 const char kOriginalWallpaperSubDir
[] = "original";
171 const char kThumbnailWallpaperSubDir
[] = "thumb";
173 const int kSmallWallpaperMaxWidth
= 1366;
174 const int kSmallWallpaperMaxHeight
= 800;
175 const int kLargeWallpaperMaxWidth
= 2560;
176 const int kLargeWallpaperMaxHeight
= 1700;
177 const int kWallpaperThumbnailWidth
= 108;
178 const int kWallpaperThumbnailHeight
= 68;
180 const char kUsersWallpaperInfo
[] = "user_wallpaper_info";
182 const char kUserWallpapers
[] = "UserWallpapers";
183 const char kUserWallpapersProperties
[] = "UserWallpapersProperties";
185 const base::FilePath
&
186 WallpaperManagerBase::CustomizedWallpaperRescaledFiles::path_downloaded()
188 return path_downloaded_
;
191 const base::FilePath
&
192 WallpaperManagerBase::CustomizedWallpaperRescaledFiles::path_rescaled_small()
194 return path_rescaled_small_
;
197 const base::FilePath
&
198 WallpaperManagerBase::CustomizedWallpaperRescaledFiles::path_rescaled_large()
200 return path_rescaled_large_
;
203 bool WallpaperManagerBase::CustomizedWallpaperRescaledFiles::downloaded_exists()
205 return downloaded_exists_
;
208 bool WallpaperManagerBase::CustomizedWallpaperRescaledFiles::
209 rescaled_small_exists() const {
210 return rescaled_small_exists_
;
213 bool WallpaperManagerBase::CustomizedWallpaperRescaledFiles::
214 rescaled_large_exists() const {
215 return rescaled_large_exists_
;
218 WallpaperManagerBase::CustomizedWallpaperRescaledFiles::
219 CustomizedWallpaperRescaledFiles(const base::FilePath
& path_downloaded
,
220 const base::FilePath
& path_rescaled_small
,
221 const base::FilePath
& path_rescaled_large
)
222 : path_downloaded_(path_downloaded
),
223 path_rescaled_small_(path_rescaled_small
),
224 path_rescaled_large_(path_rescaled_large
),
225 downloaded_exists_(false),
226 rescaled_small_exists_(false),
227 rescaled_large_exists_(false) {
231 WallpaperManagerBase::CustomizedWallpaperRescaledFiles::CreateCheckerClosure() {
232 return base::Bind(&WallpaperManagerBase::CustomizedWallpaperRescaledFiles::
233 CheckCustomizedWallpaperFilesExist
,
234 base::Unretained(this));
237 void WallpaperManagerBase::CustomizedWallpaperRescaledFiles::
238 CheckCustomizedWallpaperFilesExist() {
239 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
240 downloaded_exists_
= base::PathExists(path_downloaded_
);
241 rescaled_small_exists_
= base::PathExists(path_rescaled_small_
);
242 rescaled_large_exists_
= base::PathExists(path_rescaled_large_
);
245 bool WallpaperManagerBase::CustomizedWallpaperRescaledFiles::AllSizesExist()
247 return rescaled_small_exists_
&& rescaled_large_exists_
;
250 // WallpaperManagerBase, public:
252 // TestApi. For testing purpose
253 WallpaperManagerBase::TestApi::TestApi(WallpaperManagerBase
* wallpaper_manager
)
254 : wallpaper_manager_(wallpaper_manager
) {
257 WallpaperManagerBase::TestApi::~TestApi() {
260 base::FilePath
WallpaperManagerBase::TestApi::current_wallpaper_path() {
261 return wallpaper_manager_
->current_wallpaper_path_
;
264 bool WallpaperManagerBase::TestApi::GetWallpaperFromCache(
265 const std::string
& user_id
,
266 gfx::ImageSkia
* image
) {
267 return wallpaper_manager_
->GetWallpaperFromCache(user_id
, image
);
270 void WallpaperManagerBase::TestApi::SetWallpaperCache(
271 const std::string
& user_id
,
272 const gfx::ImageSkia
& image
) {
273 DCHECK(!image
.isNull());
274 wallpaper_manager_
->wallpaper_cache_
[user_id
] = image
;
277 void WallpaperManagerBase::TestApi::ClearDisposableWallpaperCache() {
278 wallpaper_manager_
->ClearDisposableWallpaperCache();
282 void WallpaperManagerBase::SetPathIds(
283 int dir_user_data_enum
,
284 int dir_chromeos_wallpapers_enum
,
285 int dir_chromeos_custom_wallpapers_enum
) {
286 dir_user_data_path_id
= dir_user_data_enum
;
287 dir_chromeos_wallpapers_path_id
= dir_chromeos_wallpapers_enum
;
288 dir_chromeos_custom_wallpapers_path_id
= dir_chromeos_custom_wallpapers_enum
;
292 base::FilePath
WallpaperManagerBase::GetCustomWallpaperDir(
293 const char* sub_dir
) {
294 base::FilePath custom_wallpaper_dir
;
295 DCHECK(dir_chromeos_custom_wallpapers_path_id
!= -1);
296 CHECK(PathService::Get(dir_chromeos_custom_wallpapers_path_id
,
297 &custom_wallpaper_dir
));
298 return custom_wallpaper_dir
.Append(sub_dir
);
302 void WallpaperManagerBase::RegisterPrefs(PrefRegistrySimple
* registry
) {
303 registry
->RegisterDictionaryPref(kUsersWallpaperInfo
);
304 registry
->RegisterDictionaryPref(kUserWallpapers
);
305 registry
->RegisterDictionaryPref(kUserWallpapersProperties
);
308 void WallpaperManagerBase::EnsureLoggedInUserWallpaperLoaded() {
310 if (GetLoggedInUserWallpaperInfo(&info
)) {
311 UMA_HISTOGRAM_ENUMERATION("Ash.Wallpaper.Type", info
.type
,
312 user_manager::User::WALLPAPER_TYPE_COUNT
);
313 if (info
== current_user_wallpaper_info_
)
317 user_manager::UserManager::Get()->GetLoggedInUser()->email());
320 void WallpaperManagerBase::ClearDisposableWallpaperCache() {
321 // Cancel callback for previous cache requests.
322 weak_factory_
.InvalidateWeakPtrs();
323 // Keep the wallpaper of logged in users in cache at multi-profile mode.
324 std::set
<std::string
> logged_in_users_names
;
325 const user_manager::UserList
& logged_users
=
326 user_manager::UserManager::Get()->GetLoggedInUsers();
327 for (user_manager::UserList::const_iterator it
= logged_users
.begin();
328 it
!= logged_users
.end(); ++it
) {
329 logged_in_users_names
.insert((*it
)->email());
332 CustomWallpaperMap logged_in_users_cache
;
333 for (CustomWallpaperMap::iterator it
= wallpaper_cache_
.begin();
334 it
!= wallpaper_cache_
.end(); ++it
) {
335 if (logged_in_users_names
.find(it
->first
) != logged_in_users_names
.end()) {
336 logged_in_users_cache
.insert(*it
);
339 wallpaper_cache_
= logged_in_users_cache
;
342 bool WallpaperManagerBase::GetLoggedInUserWallpaperInfo(WallpaperInfo
* info
) {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
345 if (user_manager::UserManager::Get()->IsLoggedInAsStub()) {
346 info
->location
= current_user_wallpaper_info_
.location
= "";
347 info
->layout
= current_user_wallpaper_info_
.layout
=
348 WALLPAPER_LAYOUT_CENTER_CROPPED
;
349 info
->type
= current_user_wallpaper_info_
.type
=
350 user_manager::User::DEFAULT
;
351 info
->date
= current_user_wallpaper_info_
.date
=
352 base::Time::Now().LocalMidnight();
356 return GetUserWallpaperInfo(
357 user_manager::UserManager::Get()->GetLoggedInUser()->email(), info
);
361 bool WallpaperManagerBase::ResizeImage(
362 const gfx::ImageSkia
& image
,
363 WallpaperLayout layout
,
365 int preferred_height
,
366 scoped_refptr
<base::RefCountedBytes
>* output
,
367 gfx::ImageSkia
* output_skia
) {
368 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
369 int width
= image
.width();
370 int height
= image
.height();
373 *output
= new base::RefCountedBytes();
375 if (layout
== WALLPAPER_LAYOUT_CENTER_CROPPED
) {
376 // Do not resize custom wallpaper if it is smaller than preferred size.
377 if (!(width
> preferred_width
&& height
> preferred_height
))
380 double horizontal_ratio
= static_cast<double>(preferred_width
) / width
;
381 double vertical_ratio
= static_cast<double>(preferred_height
) / height
;
382 if (vertical_ratio
> horizontal_ratio
) {
384 gfx::ToRoundedInt(static_cast<double>(width
) * vertical_ratio
);
385 resized_height
= preferred_height
;
387 resized_width
= preferred_width
;
389 gfx::ToRoundedInt(static_cast<double>(height
) * horizontal_ratio
);
391 } else if (layout
== WALLPAPER_LAYOUT_STRETCH
) {
392 resized_width
= preferred_width
;
393 resized_height
= preferred_height
;
395 resized_width
= width
;
396 resized_height
= height
;
399 gfx::ImageSkia resized_image
= gfx::ImageSkiaOperations::CreateResizedImage(
400 image
, skia::ImageOperations::RESIZE_LANCZOS3
,
401 gfx::Size(resized_width
, resized_height
));
403 SkBitmap bitmap
= *(resized_image
.bitmap());
404 SkAutoLockPixels
lock_input(bitmap
);
405 gfx::JPEGCodec::Encode(
406 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
407 gfx::JPEGCodec::FORMAT_SkBitmap
, bitmap
.width(), bitmap
.height(),
408 bitmap
.width() * bitmap
.bytesPerPixel(), kDefaultEncodingQuality
,
412 resized_image
.MakeThreadSafe();
413 *output_skia
= resized_image
;
420 bool WallpaperManagerBase::ResizeAndSaveWallpaper(const gfx::ImageSkia
& image
,
421 const base::FilePath
& path
,
422 WallpaperLayout layout
,
424 int preferred_height
,
425 gfx::ImageSkia
* output_skia
) {
426 if (layout
== WALLPAPER_LAYOUT_CENTER
) {
427 // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
428 if (base::PathExists(path
))
429 base::DeleteFile(path
, false);
432 scoped_refptr
<base::RefCountedBytes
> data
;
433 if (ResizeImage(image
, layout
, preferred_width
, preferred_height
, &data
,
435 return SaveWallpaperInternal(
436 path
, reinterpret_cast<const char*>(data
->front()), data
->size());
441 bool WallpaperManagerBase::IsPolicyControlled(
442 const std::string
& user_id
) const {
444 if (!GetUserWallpaperInfo(user_id
, &info
))
446 return info
.type
== user_manager::User::POLICY
;
449 void WallpaperManagerBase::OnPolicySet(const std::string
& policy
,
450 const std::string
& user_id
) {
452 GetUserWallpaperInfo(user_id
, &info
);
453 info
.type
= user_manager::User::POLICY
;
454 SetUserWallpaperInfo(user_id
, info
, true /* is_persistent */);
457 void WallpaperManagerBase::OnPolicyCleared(const std::string
& policy
,
458 const std::string
& user_id
) {
460 GetUserWallpaperInfo(user_id
, &info
);
461 info
.type
= user_manager::User::DEFAULT
;
462 SetUserWallpaperInfo(user_id
, info
, true /* is_persistent */);
463 SetDefaultWallpaperNow(user_id
);
467 base::FilePath
WallpaperManagerBase::GetCustomWallpaperPath(
469 const std::string
& user_id_hash
,
470 const std::string
& file
) {
471 base::FilePath custom_wallpaper_path
= GetCustomWallpaperDir(sub_dir
);
472 return custom_wallpaper_path
.Append(user_id_hash
).Append(file
);
475 WallpaperManagerBase::WallpaperManagerBase()
476 : loaded_wallpapers_(0),
477 command_line_for_testing_(NULL
),
478 should_cache_wallpaper_(false),
479 weak_factory_(this) {
480 SetDefaultWallpaperPathsFromCommandLine(
481 base::CommandLine::ForCurrentProcess());
482 sequence_token_
= BrowserThread::GetBlockingPool()->GetNamedSequenceToken(
483 kWallpaperSequenceTokenName
);
485 BrowserThread::GetBlockingPool()
486 ->GetSequencedTaskRunnerWithShutdownBehavior(
487 sequence_token_
, base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
);
490 WallpaperManagerBase::~WallpaperManagerBase() {
491 // TODO(bshe): Lifetime of WallpaperManagerBase needs more consideration.
492 // http://crbug.com/171694
493 weak_factory_
.InvalidateWeakPtrs();
496 void WallpaperManagerBase::SetPolicyControlledWallpaper(
497 const std::string
& user_id
,
498 const user_manager::UserImage
& user_image
) {
499 const user_manager::User
* user
=
500 user_manager::UserManager::Get()->FindUser(user_id
);
502 NOTREACHED() << "Unknown user.";
506 if (user
->username_hash().empty()) {
507 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
509 base::Bind(&WallpaperManagerBase::SetCustomWallpaperOnSanitizedUsername
,
510 weak_factory_
.GetWeakPtr(), user_id
, user_image
.image(),
511 true /* update wallpaper */));
513 SetCustomWallpaper(user_id
, user
->username_hash(), "policy-controlled.jpeg",
514 WALLPAPER_LAYOUT_CENTER_CROPPED
,
515 user_manager::User::POLICY
, user_image
.image(),
516 true /* update wallpaper */);
520 void WallpaperManagerBase::SetCustomWallpaperOnSanitizedUsername(
521 const std::string
& user_id
,
522 const gfx::ImageSkia
& image
,
523 bool update_wallpaper
,
524 bool cryptohome_success
,
525 const std::string
& user_id_hash
) {
526 if (!cryptohome_success
)
528 SetCustomWallpaper(user_id
, user_id_hash
, "policy-controlled.jpeg",
529 WALLPAPER_LAYOUT_CENTER_CROPPED
,
530 user_manager::User::POLICY
, image
, update_wallpaper
);
534 void WallpaperManagerBase::SaveCustomWallpaper(
535 const std::string
& user_id_hash
,
536 const base::FilePath
& original_path
,
537 WallpaperLayout layout
,
538 scoped_ptr
<gfx::ImageSkia
> image
) {
540 GetCustomWallpaperDir(kOriginalWallpaperSubDir
).Append(user_id_hash
),
541 true /* recursive */);
543 GetCustomWallpaperDir(kSmallWallpaperSubDir
).Append(user_id_hash
),
544 true /* recursive */);
546 GetCustomWallpaperDir(kLargeWallpaperSubDir
).Append(user_id_hash
),
547 true /* recursive */);
548 EnsureCustomWallpaperDirectories(user_id_hash
);
549 std::string file_name
= original_path
.BaseName().value();
550 base::FilePath small_wallpaper_path
=
551 GetCustomWallpaperPath(kSmallWallpaperSubDir
, user_id_hash
, file_name
);
552 base::FilePath large_wallpaper_path
=
553 GetCustomWallpaperPath(kLargeWallpaperSubDir
, user_id_hash
, file_name
);
555 // Re-encode orginal file to jpeg format and saves the result in case that
556 // resized wallpaper is not generated (i.e. chrome shutdown before resized
557 // wallpaper is saved).
558 ResizeAndSaveWallpaper(*image
, original_path
, WALLPAPER_LAYOUT_STRETCH
,
559 image
->width(), image
->height(), NULL
);
560 ResizeAndSaveWallpaper(*image
, small_wallpaper_path
, layout
,
561 kSmallWallpaperMaxWidth
, kSmallWallpaperMaxHeight
,
563 ResizeAndSaveWallpaper(*image
, large_wallpaper_path
, layout
,
564 kLargeWallpaperMaxWidth
, kLargeWallpaperMaxHeight
,
569 void WallpaperManagerBase::MoveCustomWallpapersOnWorker(
570 const std::string
& user_id
,
571 const std::string
& user_id_hash
,
572 base::WeakPtr
<WallpaperManagerBase
> weak_ptr
) {
573 if (MoveCustomWallpaperDirectory(kOriginalWallpaperSubDir
, user_id
,
575 // Consider success if the original wallpaper is moved to the new directory.
576 // Original wallpaper is the fallback if the correct resolution wallpaper
578 BrowserThread::PostTask(
579 BrowserThread::UI
, FROM_HERE
,
580 base::Bind(&WallpaperManagerBase::MoveCustomWallpapersSuccess
, weak_ptr
,
581 user_id
, user_id_hash
));
583 MoveCustomWallpaperDirectory(kLargeWallpaperSubDir
, user_id
, user_id_hash
);
584 MoveCustomWallpaperDirectory(kSmallWallpaperSubDir
, user_id
, user_id_hash
);
585 MoveCustomWallpaperDirectory(kThumbnailWallpaperSubDir
, user_id
,
590 void WallpaperManagerBase::GetCustomWallpaperInternal(
591 const std::string
& user_id
,
592 const WallpaperInfo
& info
,
593 const base::FilePath
& wallpaper_path
,
594 bool update_wallpaper
,
595 MovableOnDestroyCallbackHolder on_finish
,
596 base::WeakPtr
<WallpaperManagerBase
> weak_ptr
) {
597 base::FilePath valid_path
= wallpaper_path
;
598 if (!base::PathExists(wallpaper_path
)) {
599 // Falls back on original file if the correct resolution file does not
600 // exist. This may happen when the original custom wallpaper is small or
601 // browser shutdown before resized wallpaper saved.
602 valid_path
= GetCustomWallpaperDir(kOriginalWallpaperSubDir
);
603 valid_path
= valid_path
.Append(info
.location
);
606 if (!base::PathExists(valid_path
)) {
607 // Falls back to custom wallpaper that uses email as part of its file path.
608 // Note that email is used instead of user_id_hash here.
609 valid_path
= GetCustomWallpaperPath(kOriginalWallpaperSubDir
, user_id
,
613 if (!base::PathExists(valid_path
)) {
614 LOG(ERROR
) << "Failed to load previously selected custom wallpaper. "
615 << "Fallback to default wallpaper";
616 BrowserThread::PostTask(
617 BrowserThread::UI
, FROM_HERE
,
618 base::Bind(&WallpaperManagerBase::DoSetDefaultWallpaper
, weak_ptr
,
619 user_id
, base::Passed(on_finish
.Pass())));
621 BrowserThread::PostTask(
622 BrowserThread::UI
, FROM_HERE
,
623 base::Bind(&WallpaperManagerBase::StartLoad
, weak_ptr
, user_id
, info
,
624 update_wallpaper
, valid_path
,
625 base::Passed(on_finish
.Pass())));
629 void WallpaperManagerBase::InitInitialUserWallpaper(const std::string
& user_id
,
630 bool is_persistent
) {
631 current_user_wallpaper_info_
.location
= "";
632 current_user_wallpaper_info_
.layout
= WALLPAPER_LAYOUT_CENTER_CROPPED
;
633 current_user_wallpaper_info_
.type
= user_manager::User::DEFAULT
;
634 current_user_wallpaper_info_
.date
= base::Time::Now().LocalMidnight();
636 WallpaperInfo info
= current_user_wallpaper_info_
;
637 SetUserWallpaperInfo(user_id
, info
, is_persistent
);
640 void WallpaperManagerBase::SetUserWallpaperDelayed(const std::string
& user_id
) {
641 ScheduleSetUserWallpaper(user_id
, true);
644 void WallpaperManagerBase::SetUserWallpaperNow(const std::string
& user_id
) {
645 ScheduleSetUserWallpaper(user_id
, false);
648 void WallpaperManagerBase::UpdateWallpaper(bool clear_cache
) {
649 FOR_EACH_OBSERVER(Observer
, observers_
, OnUpdateWallpaperForTesting());
651 wallpaper_cache_
.clear();
652 current_wallpaper_path_
.clear();
653 // For GAIA login flow, the last_selected_user_ may not be set before user
654 // login. If UpdateWallpaper is called at GAIA login screen, no wallpaper will
655 // be set. It could result a black screen on external monitors.
656 // See http://crbug.com/265689 for detail.
657 if (last_selected_user_
.empty()) {
658 SetDefaultWallpaperNow(chromeos::login::kSignInUser
);
661 SetUserWallpaperNow(last_selected_user_
);
664 void WallpaperManagerBase::AddObserver(
665 WallpaperManagerBase::Observer
* observer
) {
666 observers_
.AddObserver(observer
);
669 void WallpaperManagerBase::RemoveObserver(
670 WallpaperManagerBase::Observer
* observer
) {
671 observers_
.RemoveObserver(observer
);
674 void WallpaperManagerBase::NotifyAnimationFinished() {
675 FOR_EACH_OBSERVER(Observer
, observers_
,
676 OnWallpaperAnimationFinished(last_selected_user_
));
679 // WallpaperManager, protected: -----------------------------------------------
681 bool WallpaperManagerBase::GetWallpaperFromCache(const std::string
& user_id
,
682 gfx::ImageSkia
* image
) {
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
684 CustomWallpaperMap::const_iterator it
= wallpaper_cache_
.find(user_id
);
685 if (it
!= wallpaper_cache_
.end()) {
686 *image
= (*it
).second
;
692 int WallpaperManagerBase::loaded_wallpapers() const {
693 return loaded_wallpapers_
;
696 void WallpaperManagerBase::CacheUsersWallpapers() {
697 // TODO(dpolukhin): crbug.com/408734.
698 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
699 user_manager::UserList users
= user_manager::UserManager::Get()->GetUsers();
701 if (!users
.empty()) {
702 user_manager::UserList::const_iterator it
= users
.begin();
703 // Skip the wallpaper of first user in the list. It should have been cached.
705 for (int cached
= 0; it
!= users
.end() && cached
< kMaxWallpapersToCache
;
707 std::string user_id
= (*it
)->email();
708 CacheUserWallpaper(user_id
);
713 void WallpaperManagerBase::CacheUserWallpaper(const std::string
& user_id
) {
714 if (wallpaper_cache_
.find(user_id
) != wallpaper_cache_
.end())
717 if (GetUserWallpaperInfo(user_id
, &info
)) {
718 if (info
.location
.empty())
721 base::FilePath wallpaper_dir
;
722 base::FilePath wallpaper_path
;
723 if (info
.type
== user_manager::User::CUSTOMIZED
||
724 info
.type
== user_manager::User::POLICY
) {
725 const char* sub_dir
= GetCustomWallpaperSubdirForCurrentResolution();
726 base::FilePath wallpaper_path
= GetCustomWallpaperDir(sub_dir
);
727 wallpaper_path
= wallpaper_path
.Append(info
.location
);
728 task_runner_
->PostTask(
730 base::Bind(&WallpaperManagerBase::GetCustomWallpaperInternal
, user_id
,
731 info
, wallpaper_path
, false /* do not update wallpaper */,
732 base::Passed(MovableOnDestroyCallbackHolder()),
733 weak_factory_
.GetWeakPtr()));
736 LoadWallpaper(user_id
, info
, false /* do not update wallpaper */,
737 MovableOnDestroyCallbackHolder().Pass());
741 void WallpaperManagerBase::DeleteUserWallpapers(
742 const std::string
& user_id
,
743 const std::string
& path_to_file
) {
744 std::vector
<base::FilePath
> file_to_remove
;
745 // Remove small user wallpaper.
746 base::FilePath wallpaper_path
= GetCustomWallpaperDir(kSmallWallpaperSubDir
);
747 // Remove old directory if exists
748 file_to_remove
.push_back(wallpaper_path
.Append(user_id
));
749 wallpaper_path
= wallpaper_path
.Append(path_to_file
).DirName();
750 file_to_remove
.push_back(wallpaper_path
);
752 // Remove large user wallpaper.
753 wallpaper_path
= GetCustomWallpaperDir(kLargeWallpaperSubDir
);
754 file_to_remove
.push_back(wallpaper_path
.Append(user_id
));
755 wallpaper_path
= wallpaper_path
.Append(path_to_file
);
756 file_to_remove
.push_back(wallpaper_path
);
758 // Remove user wallpaper thumbnail.
759 wallpaper_path
= GetCustomWallpaperDir(kThumbnailWallpaperSubDir
);
760 file_to_remove
.push_back(wallpaper_path
.Append(user_id
));
761 wallpaper_path
= wallpaper_path
.Append(path_to_file
);
762 file_to_remove
.push_back(wallpaper_path
);
764 // Remove original user wallpaper.
765 wallpaper_path
= GetCustomWallpaperDir(kOriginalWallpaperSubDir
);
766 file_to_remove
.push_back(wallpaper_path
.Append(user_id
));
767 wallpaper_path
= wallpaper_path
.Append(path_to_file
);
768 file_to_remove
.push_back(wallpaper_path
);
770 base::WorkerPool::PostTask(
771 FROM_HERE
, base::Bind(&DeleteWallpaperInList
, file_to_remove
), false);
774 void WallpaperManagerBase::SetCommandLineForTesting(
775 base::CommandLine
* command_line
) {
776 command_line_for_testing_
= command_line
;
777 SetDefaultWallpaperPathsFromCommandLine(command_line
);
780 base::CommandLine
* WallpaperManagerBase::GetCommandLine() {
781 base::CommandLine
* command_line
=
782 command_line_for_testing_
? command_line_for_testing_
783 : base::CommandLine::ForCurrentProcess();
787 void WallpaperManagerBase::LoadWallpaper(
788 const std::string
& user_id
,
789 const WallpaperInfo
& info
,
790 bool update_wallpaper
,
791 MovableOnDestroyCallbackHolder on_finish
) {
792 base::FilePath wallpaper_dir
;
793 base::FilePath wallpaper_path
;
795 // Do a sanity check that file path information is not empty.
796 if (info
.type
== user_manager::User::ONLINE
||
797 info
.type
== user_manager::User::DEFAULT
) {
798 if (info
.location
.empty()) {
799 if (base::SysInfo::IsRunningOnChromeOS()) {
800 NOTREACHED() << "User wallpaper info appears to be broken: " << user_id
;
802 // Filename might be empty on debug configurations when stub users
803 // were created directly in Local State (for testing). Ignore such
804 // errors i.e. allowsuch type of debug configurations on the desktop.
805 LOG(WARNING
) << "User wallpaper info is empty: " << user_id
;
807 // |on_finish| callback will get called on destruction.
813 if (info
.type
== user_manager::User::ONLINE
) {
814 std::string file_name
= GURL(info
.location
).ExtractFileName();
815 WallpaperResolution resolution
= GetAppropriateResolution();
816 // Only solid color wallpapers have stretch layout and they have only one
818 if (info
.layout
!= WALLPAPER_LAYOUT_STRETCH
&&
819 resolution
== WALLPAPER_RESOLUTION_SMALL
) {
820 file_name
= base::FilePath(file_name
)
821 .InsertBeforeExtension(kSmallWallpaperSuffix
)
824 DCHECK(dir_chromeos_wallpapers_path_id
!= -1);
825 CHECK(PathService::Get(dir_chromeos_wallpapers_path_id
,
827 wallpaper_path
= wallpaper_dir
.Append(file_name
);
828 if (current_wallpaper_path_
== wallpaper_path
)
831 if (update_wallpaper
)
832 current_wallpaper_path_
= wallpaper_path
;
834 loaded_wallpapers_
++;
835 StartLoad(user_id
, info
, update_wallpaper
, wallpaper_path
,
837 } else if (info
.type
== user_manager::User::DEFAULT
) {
838 // Default wallpapers are migrated from M21 user profiles. A code refactor
839 // overlooked that case and caused these wallpapers not being loaded at all.
840 // On some slow devices, it caused login webui not visible after upgrade to
841 // M26 from M21. See crosbug.com/38429 for details.
842 base::FilePath user_data_dir
;
843 DCHECK(dir_user_data_path_id
!= -1);
844 PathService::Get(dir_user_data_path_id
, &user_data_dir
);
845 wallpaper_path
= user_data_dir
.Append(info
.location
);
846 StartLoad(user_id
, info
, update_wallpaper
, wallpaper_path
,
849 // In unexpected cases, revert to default wallpaper to fail safely. See
850 // crosbug.com/38429.
851 LOG(ERROR
) << "Wallpaper reverts to default unexpected.";
852 DoSetDefaultWallpaper(user_id
, on_finish
.Pass());
856 void WallpaperManagerBase::MoveCustomWallpapersSuccess(
857 const std::string
& user_id
,
858 const std::string
& user_id_hash
) {
860 GetUserWallpaperInfo(user_id
, &info
);
861 if (info
.type
== user_manager::User::CUSTOMIZED
) {
862 // New file field should include user id hash in addition to file name.
863 // This is needed because at login screen, user id hash is not available.
864 info
.location
= base::FilePath(user_id_hash
).Append(info
.location
).value();
866 !user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral(
868 SetUserWallpaperInfo(user_id
, info
, is_persistent
);
872 void WallpaperManagerBase::MoveLoggedInUserCustomWallpaper() {
873 const user_manager::User
* logged_in_user
=
874 user_manager::UserManager::Get()->GetLoggedInUser();
875 if (logged_in_user
) {
876 task_runner_
->PostTask(
878 base::Bind(&WallpaperManagerBase::MoveCustomWallpapersOnWorker
,
879 logged_in_user
->email(), logged_in_user
->username_hash(),
880 weak_factory_
.GetWeakPtr()));
884 void WallpaperManagerBase::SaveLastLoadTime(const base::TimeDelta elapsed
) {
885 while (last_load_times_
.size() >= kLastLoadsStatsMsMaxSize
)
886 last_load_times_
.pop_front();
888 if (elapsed
> base::TimeDelta::FromMicroseconds(0)) {
889 last_load_times_
.push_back(elapsed
);
890 last_load_finished_at_
= base::Time::Now();
894 base::TimeDelta
WallpaperManagerBase::GetWallpaperLoadDelay() const {
895 base::TimeDelta delay
;
897 if (last_load_times_
.size() == 0) {
898 delay
= base::TimeDelta::FromMilliseconds(kLoadDefaultDelayMs
);
900 delay
= std::accumulate(last_load_times_
.begin(), last_load_times_
.end(),
901 base::TimeDelta(), std::plus
<base::TimeDelta
>()) /
902 last_load_times_
.size();
905 if (delay
< base::TimeDelta::FromMilliseconds(kLoadMinDelayMs
))
906 delay
= base::TimeDelta::FromMilliseconds(kLoadMinDelayMs
);
907 else if (delay
> base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs
))
908 delay
= base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs
);
910 // If we had ever loaded wallpaper, adjust wait delay by time since last load.
911 if (!last_load_finished_at_
.is_null()) {
912 const base::TimeDelta interval
= base::Time::Now() - last_load_finished_at_
;
913 if (interval
> delay
)
914 delay
= base::TimeDelta::FromMilliseconds(0);
915 else if (interval
> base::TimeDelta::FromMilliseconds(0))
921 void WallpaperManagerBase::OnCustomizedDefaultWallpaperDecoded(
922 const GURL
& wallpaper_url
,
923 scoped_ptr
<CustomizedWallpaperRescaledFiles
> rescaled_files
,
924 const user_manager::UserImage
& wallpaper
) {
925 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
927 // If decoded wallpaper is empty, we have probably failed to decode the file.
928 if (wallpaper
.image().isNull()) {
929 LOG(WARNING
) << "Failed to decode customized wallpaper.";
933 wallpaper
.image().EnsureRepsForSupportedScales();
934 scoped_ptr
<gfx::ImageSkia
> deep_copy(wallpaper
.image().DeepCopy());
936 scoped_ptr
<bool> success(new bool(false));
937 scoped_ptr
<gfx::ImageSkia
> small_wallpaper_image(new gfx::ImageSkia
);
938 scoped_ptr
<gfx::ImageSkia
> large_wallpaper_image(new gfx::ImageSkia
);
940 // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
941 base::Closure resize_closure
= base::Bind(
942 &WallpaperManagerBase::ResizeCustomizedDefaultWallpaper
,
943 base::Passed(&deep_copy
), wallpaper
.raw_image(),
944 base::Unretained(rescaled_files
.get()), base::Unretained(success
.get()),
945 base::Unretained(small_wallpaper_image
.get()),
946 base::Unretained(large_wallpaper_image
.get()));
947 base::Closure on_resized_closure
= base::Bind(
948 &WallpaperManagerBase::OnCustomizedDefaultWallpaperResized
,
949 weak_factory_
.GetWeakPtr(), wallpaper_url
,
950 base::Passed(rescaled_files
.Pass()), base::Passed(success
.Pass()),
951 base::Passed(small_wallpaper_image
.Pass()),
952 base::Passed(large_wallpaper_image
.Pass()));
954 if (!task_runner_
->PostTaskAndReply(FROM_HERE
, resize_closure
,
955 on_resized_closure
)) {
956 LOG(WARNING
) << "Failed to start Customized Wallpaper resize.";
960 void WallpaperManagerBase::ResizeCustomizedDefaultWallpaper(
961 scoped_ptr
<gfx::ImageSkia
> image
,
962 const user_manager::UserImage::RawImage
& raw_image
,
963 const CustomizedWallpaperRescaledFiles
* rescaled_files
,
965 gfx::ImageSkia
* small_wallpaper_image
,
966 gfx::ImageSkia
* large_wallpaper_image
) {
969 *success
&= ResizeAndSaveWallpaper(
970 *image
, rescaled_files
->path_rescaled_small(), WALLPAPER_LAYOUT_STRETCH
,
971 kSmallWallpaperMaxWidth
, kSmallWallpaperMaxHeight
, small_wallpaper_image
);
973 *success
&= ResizeAndSaveWallpaper(
974 *image
, rescaled_files
->path_rescaled_large(), WALLPAPER_LAYOUT_STRETCH
,
975 kLargeWallpaperMaxWidth
, kLargeWallpaperMaxHeight
, large_wallpaper_image
);
978 void WallpaperManagerBase::SetCustomizedDefaultWallpaper(
979 const GURL
& wallpaper_url
,
980 const base::FilePath
& downloaded_file
,
981 const base::FilePath
& resized_directory
) {
982 // Should fail if this ever happens in tests.
983 DCHECK(wallpaper_url
.is_valid());
984 if (!wallpaper_url
.is_valid()) {
985 if (!wallpaper_url
.is_empty()) {
986 LOG(WARNING
) << "Invalid Customized Wallpaper URL '"
987 << wallpaper_url
.spec() << "'";
991 std::string downloaded_file_name
= downloaded_file
.BaseName().value();
992 scoped_ptr
<CustomizedWallpaperRescaledFiles
> rescaled_files(
993 new CustomizedWallpaperRescaledFiles(
994 downloaded_file
, resized_directory
.Append(downloaded_file_name
+
995 kSmallWallpaperSuffix
),
996 resized_directory
.Append(downloaded_file_name
+
997 kLargeWallpaperSuffix
)));
999 base::Closure check_file_exists
= rescaled_files
->CreateCheckerClosure();
1000 base::Closure on_checked_closure
=
1001 base::Bind(&WallpaperManagerBase::SetCustomizedDefaultWallpaperAfterCheck
,
1002 weak_factory_
.GetWeakPtr(), wallpaper_url
, downloaded_file
,
1003 base::Passed(rescaled_files
.Pass()));
1004 if (!BrowserThread::PostBlockingPoolTaskAndReply(FROM_HERE
, check_file_exists
,
1005 on_checked_closure
)) {
1006 LOG(WARNING
) << "Failed to start check CheckCustomizedWallpaperFilesExist.";
1010 void WallpaperManagerBase::SetDefaultWallpaperPathsFromCommandLine(
1011 base::CommandLine
* command_line
) {
1012 default_small_wallpaper_file_
= command_line
->GetSwitchValuePath(
1013 chromeos::switches::kDefaultWallpaperSmall
);
1014 default_large_wallpaper_file_
= command_line
->GetSwitchValuePath(
1015 chromeos::switches::kDefaultWallpaperLarge
);
1016 guest_small_wallpaper_file_
= command_line
->GetSwitchValuePath(
1017 chromeos::switches::kGuestWallpaperSmall
);
1018 guest_large_wallpaper_file_
= command_line
->GetSwitchValuePath(
1019 chromeos::switches::kGuestWallpaperLarge
);
1020 child_small_wallpaper_file_
= command_line
->GetSwitchValuePath(
1021 chromeos::switches::kChildWallpaperSmall
);
1022 child_large_wallpaper_file_
= command_line
->GetSwitchValuePath(
1023 chromeos::switches::kChildWallpaperLarge
);
1024 default_wallpaper_image_
.reset();
1028 WallpaperManagerBase::GetCustomWallpaperSubdirForCurrentResolution() {
1029 WallpaperResolution resolution
= GetAppropriateResolution();
1030 return resolution
== WALLPAPER_RESOLUTION_SMALL
? kSmallWallpaperSubDir
1031 : kLargeWallpaperSubDir
;
1034 void WallpaperManagerBase::CreateSolidDefaultWallpaper() {
1035 loaded_wallpapers_
++;
1037 bitmap
.allocN32Pixels(1, 1);
1038 bitmap
.eraseColor(kDefaultWallpaperColor
);
1039 const gfx::ImageSkia image
= gfx::ImageSkia::CreateFrom1xBitmap(bitmap
);
1040 default_wallpaper_image_
.reset(new user_manager::UserImage(image
));
1043 } // namespace wallpaper