| OLD | NEW |
| (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 | |
| OLD | NEW |