Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: chrome/browser/chromeos/login/wallpaper_manager.cc

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

Powered by Google App Engine
This is Rietveld 408576698