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