1 // Copyright (c) 2012 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 "ash/ash_resources/grit/ash_resources.h" 8 #include "ash/desktop_background/desktop_background_controller.h" 9 #include "ash/desktop_background/desktop_background_controller_observer.h" 10 #include "ash/display/display_manager.h" 11 #include "ash/shell.h" 12 #include "ash/test/display_manager_test_api.h" 13 #include "base/command_line.h" 14 #include "base/file_util.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/strings/string_number_conversions.h" 17 #include "base/time/time.h" 18 #include "base/values.h" 19 #include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h" 20 #include "chrome/browser/chromeos/login/user.h" 21 #include "chrome/browser/chromeos/login/user_manager.h" 22 #include "chrome/browser/prefs/scoped_user_pref_update.h" 23 #include "chrome/common/chrome_switches.h" 24 #include "chrome/test/base/testing_browser_process.h" 25 #include "chromeos/chromeos_switches.h" 26 #include "ui/aura/env.h" 27 #include "ui/base/resource/resource_bundle.h" 28 29 using namespace ash; 30 31 namespace chromeos { 32 33 namespace { 34 35 const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_LARGE; 36 const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_SMALL; 37 38 int kLargeWallpaperWidth = 256; 39 int kLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight; 40 int kSmallWallpaperWidth = 256; 41 int kSmallWallpaperHeight = ash::kSmallWallpaperMaxHeight; 42 43 const char kTestUser1[] = "test (at) domain.com"; 44 45 } // namespace 46 47 class WallpaperManagerBrowserTest : public CrosInProcessBrowserTest, 48 public DesktopBackgroundControllerObserver { 49 public: 50 WallpaperManagerBrowserTest () : controller_(NULL), 51 local_state_(NULL) { 52 } 53 54 virtual ~WallpaperManagerBrowserTest () {} 55 56 virtual void SetUpOnMainThread() OVERRIDE { 57 controller_ = ash::Shell::GetInstance()->desktop_background_controller(); 58 controller_->AddObserver(this); 59 local_state_ = g_browser_process->local_state(); 60 UpdateDisplay("800x600"); 61 } 62 63 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 64 command_line->AppendSwitch(switches::kLoginManager); 65 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); 66 } 67 68 virtual void CleanUpOnMainThread() OVERRIDE { 69 controller_->RemoveObserver(this); 70 controller_ = NULL; 71 } 72 73 // Update the display configuration as given in |display_specs|. 74 // See ash::test::DisplayManagerTestApi::UpdateDisplay for more 75 // details. 76 void UpdateDisplay(const std::string& display_specs) { 77 ash::test::DisplayManagerTestApi display_manager_test_api( 78 ash::Shell::GetInstance()->display_manager()); 79 display_manager_test_api.UpdateDisplay(display_specs); 80 } 81 82 void WaitAsyncWallpaperLoad() { 83 base::MessageLoop::current()->Run(); 84 } 85 86 virtual void OnWallpaperDataChanged() OVERRIDE { 87 base::MessageLoop::current()->Quit(); 88 } 89 90 protected: 91 // Return custom wallpaper path. Create directory if not exist. 92 base::FilePath GetCustomWallpaperPath(const char* sub_dir, 93 const std::string& email, 94 const std::string& id) { 95 base::FilePath wallpaper_path = 96 WallpaperManager::Get()->GetCustomWallpaperPath(sub_dir, email, id); 97 if (!base::DirectoryExists(wallpaper_path.DirName())) 98 file_util::CreateDirectory(wallpaper_path.DirName()); 99 100 return wallpaper_path; 101 } 102 103 // Logs in |username|. 104 void LogIn(const std::string& username) { 105 UserManager::Get()->UserLoggedIn(username, username, false); 106 } 107 108 // Saves bitmap |resource_id| to disk. 109 void SaveUserWallpaperData(const std::string& username, 110 const base::FilePath& wallpaper_path, 111 int resource_id) { 112 scoped_refptr<base::RefCountedStaticMemory> image_data( 113 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( 114 resource_id, ui::SCALE_FACTOR_100P)); 115 int written = file_util::WriteFile( 116 wallpaper_path, 117 reinterpret_cast<const char*>(image_data->front()), 118 image_data->size()); 119 EXPECT_EQ(static_cast<int>(image_data->size()), written); 120 } 121 122 int LoadedWallpapers() { 123 return WallpaperManager::Get()->loaded_wallpapers(); 124 } 125 126 DesktopBackgroundController* controller_; 127 PrefService* local_state_; 128 129 private: 130 DISALLOW_COPY_AND_ASSIGN(WallpaperManagerBrowserTest); 131 }; 132 133 // Tests that the appropriate custom wallpaper (large vs. small) is loaded 134 // depending on the desktop resolution. 135 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 136 LoadCustomLargeWallpaperForLargeExternalScreen) { 137 WallpaperManager* wallpaper_manager = WallpaperManager::Get(); 138 LogIn(kTestUser1); 139 // Wait for default wallpaper loaded. 140 WaitAsyncWallpaperLoad(); 141 std::string id = base::Int64ToString(base::Time::Now().ToInternalValue()); 142 base::FilePath small_wallpaper_path = GetCustomWallpaperPath( 143 kSmallWallpaperSubDir, 144 kTestUser1, 145 id); 146 base::FilePath large_wallpaper_path = GetCustomWallpaperPath( 147 kLargeWallpaperSubDir, 148 kTestUser1, 149 id); 150 151 // Saves the small/large resolution wallpapers to small/large custom 152 // wallpaper paths. 153 SaveUserWallpaperData(kTestUser1, 154 small_wallpaper_path, 155 kSmallWallpaperResourceId); 156 SaveUserWallpaperData(kTestUser1, 157 large_wallpaper_path, 158 kLargeWallpaperResourceId); 159 160 // Saves wallpaper info to local state for user |kTestUser1|. 161 WallpaperInfo info = { 162 id, 163 WALLPAPER_LAYOUT_CENTER_CROPPED, 164 User::CUSTOMIZED, 165 base::Time::Now().LocalMidnight() 166 }; 167 wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true); 168 169 // Set the wallpaper for |kTestUser1|. 170 wallpaper_manager->SetUserWallpaper(kTestUser1); 171 WaitAsyncWallpaperLoad(); 172 gfx::ImageSkia wallpaper = controller_->GetWallpaper(); 173 174 // Display is initialized to 800x600. The small resolution custom wallpaper is 175 // expected. 176 EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width()); 177 EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height()); 178 179 // Hook up another 800x600 display. 180 UpdateDisplay("800x600,800x600"); 181 WaitAsyncWallpaperLoad(); 182 // The small resolution custom wallpaper is expected. 183 EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width()); 184 EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height()); 185 186 // Detach the secondary display. 187 UpdateDisplay("800x600"); 188 // Hook up a 2000x2000 display. The large resolution custom wallpaper should 189 // be loaded. 190 UpdateDisplay("800x600,2000x2000"); 191 WaitAsyncWallpaperLoad(); 192 wallpaper = controller_->GetWallpaper(); 193 194 // The large resolution custom wallpaper is expected. 195 EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width()); 196 EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height()); 197 198 // Detach the secondary display. 199 UpdateDisplay("800x600"); 200 // Hook up the 2000x2000 display again. The large resolution default wallpaper 201 // should persist. Test for crbug/165788. 202 UpdateDisplay("800x600,2000x2000"); 203 WaitAsyncWallpaperLoad(); 204 wallpaper = controller_->GetWallpaper(); 205 206 // The large resolution custom wallpaper is expected. 207 EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width()); 208 EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height()); 209 } 210 211 // If chrome tries to reload the same wallpaper twice, the latter request should 212 // be prevented. Otherwise, there are some strange animation issues as 213 // described in crbug.com/158383. 214 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 215 PreventReloadingSameWallpaper) { 216 WallpaperManager* wallpaper_manager = WallpaperManager::Get(); 217 // New user log in, a default wallpaper is loaded. 218 LogIn(kTestUser1); 219 EXPECT_EQ(1, LoadedWallpapers()); 220 // Loads the same wallpaper before the initial one finished. It should be 221 // prevented. 222 wallpaper_manager->SetUserWallpaper(kTestUser1); 223 EXPECT_EQ(1, LoadedWallpapers()); 224 WaitAsyncWallpaperLoad(); 225 // Loads the same wallpaper after the initial one finished. It should be 226 // prevented. 227 wallpaper_manager->SetUserWallpaper(kTestUser1); 228 EXPECT_EQ(1, LoadedWallpapers()); 229 wallpaper_manager->ClearWallpaperCache(); 230 231 // Change wallpaper to a custom wallpaper. 232 std::string id = base::Int64ToString(base::Time::Now().ToInternalValue()); 233 base::FilePath small_wallpaper_path = GetCustomWallpaperPath( 234 kSmallWallpaperSubDir, 235 kTestUser1, 236 id); 237 SaveUserWallpaperData(kTestUser1, 238 small_wallpaper_path, 239 kSmallWallpaperResourceId); 240 241 // Saves wallpaper info to local state for user |kTestUser1|. 242 WallpaperInfo info = { 243 id, 244 WALLPAPER_LAYOUT_CENTER_CROPPED, 245 User::CUSTOMIZED, 246 base::Time::Now().LocalMidnight() 247 }; 248 wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true); 249 250 wallpaper_manager->SetUserWallpaper(kTestUser1); 251 EXPECT_EQ(2, LoadedWallpapers()); 252 // Loads the same wallpaper before the initial one finished. It should be 253 // prevented. 254 wallpaper_manager->SetUserWallpaper(kTestUser1); 255 EXPECT_EQ(2, LoadedWallpapers()); 256 WaitAsyncWallpaperLoad(); 257 wallpaper_manager->SetUserWallpaper(kTestUser1); 258 EXPECT_EQ(2, LoadedWallpapers()); 259 } 260 261 // Old custom wallpaper is stored in USER_DATA_DIR. New custom wallpapers will 262 // be stored in USER_CUSTOM_WALLPAPER_DIR. The migration is triggered when any 263 // of the user fall back to load custom wallpaper from old path. 264 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 265 MoveCustomWallpaper) { 266 WallpaperManager* wallpaper_manager = WallpaperManager::Get(); 267 LogIn(kTestUser1); 268 WaitAsyncWallpaperLoad(); 269 270 base::FilePath old_wallpaper_path = wallpaper_manager-> 271 GetOriginalWallpaperPathForUser(kTestUser1); 272 SaveUserWallpaperData(kTestUser1, 273 old_wallpaper_path, 274 kSmallWallpaperResourceId); 275 // Saves wallpaper info to local state for user |kTestUser1|. 276 WallpaperInfo info = { 277 "DUMMY", 278 WALLPAPER_LAYOUT_CENTER_CROPPED, 279 User::CUSTOMIZED, 280 base::Time::Now().LocalMidnight() 281 }; 282 wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true); 283 wallpaper_manager->SetUserWallpaper(kTestUser1); 284 WaitAsyncWallpaperLoad(); 285 EXPECT_EQ(2, LoadedWallpapers()); 286 wallpaper_manager->UpdateWallpaper(); 287 // Wait for wallpaper migration and refresh. Note: the migration is guarantee 288 // to finish before wallpaper refresh finish. This is guarantted by sequence 289 // worker pool we use. 290 WaitAsyncWallpaperLoad(); 291 EXPECT_EQ(3, LoadedWallpapers()); 292 base::FilePath new_wallpaper_path = GetCustomWallpaperPath( 293 kOriginalWallpaperSubDir, kTestUser1, "DUMMY"); 294 EXPECT_FALSE(base::PathExists(old_wallpaper_path)); 295 EXPECT_TRUE(base::PathExists(new_wallpaper_path)); 296 } 297 298 // Some users have old user profiles which may have legacy wallpapers. And these 299 // lagacy wallpapers should migrate to new wallpaper picker version seamlessly. 300 // This tests make sure we compatible with migrated old wallpapers. 301 // crosbug.com/38429 302 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 303 PRE_UseMigratedWallpaperInfo) { 304 // New user log in, a default wallpaper is loaded. 305 LogIn(kTestUser1); 306 WaitAsyncWallpaperLoad(); 307 // Old wallpaper migration code doesn't exist in codebase anymore. Modify user 308 // wallpaper info directly to simulate the wallpaper migration. See 309 // crosbug.com/38429 for details about why we modify wallpaper info this way. 310 WallpaperInfo info = { 311 "123", 312 WALLPAPER_LAYOUT_CENTER_CROPPED, 313 User::DEFAULT, 314 base::Time::Now().LocalMidnight() 315 }; 316 WallpaperManager::Get()->SetUserWallpaperInfo(kTestUser1, info, true); 317 } 318 319 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 320 UseMigratedWallpaperInfo) { 321 LogIn(kTestUser1); 322 WaitAsyncWallpaperLoad(); 323 // This test should finish normally. If timeout, it is probably because 324 // migrated wallpaper is somehow not loaded. Bad things can happen if 325 // wallpaper is not loaded at login screen. One example is: crosbug.com/38429. 326 } 327 328 // Some users have old user profiles which may never get a chance to migrate. 329 // This tests make sure we compatible with these profiles. 330 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 331 PRE_UsePreMigrationWallpaperInfo) { 332 // New user log in, a default wallpaper is loaded. 333 LogIn(kTestUser1); 334 WaitAsyncWallpaperLoad(); 335 // Old wallpaper migration code doesn't exist in codebase anymore. So if 336 // user's profile is not migrated, it is the same as no wallpaper info. To 337 // simulate this, we remove user's wallpaper info here. 338 WallpaperManager::Get()->RemoveUserWallpaperInfo(kTestUser1); 339 } 340 341 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 342 UsePreMigrationWallpaperInfo) { 343 LogIn(kTestUser1); 344 WaitAsyncWallpaperLoad(); 345 // This test should finish normally. If timeout, it is probably because chrome 346 // can not handle pre migrated user profile (M21 profile or older). 347 } 348 349 // Test for http://crbug.com/265689. When hooked up a large external monitor, 350 // the default large resolution wallpaper should load. 351 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, 352 HotPlugInScreenAtGAIALoginScreen) { 353 UpdateDisplay("800x600"); 354 // Set initial wallpaper to the default wallpaper. 355 WallpaperManager::Get()->SetDefaultWallpaper(); 356 WaitAsyncWallpaperLoad(); 357 358 // Hook up a 2000x2000 display. The large resolution custom wallpaper should 359 // be loaded. 360 UpdateDisplay("800x600,2000x2000"); 361 WaitAsyncWallpaperLoad(); 362 } 363 364 class WallpaperManagerBrowserTestNoAnimation 365 : public WallpaperManagerBrowserTest { 366 public: 367 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 368 command_line->AppendSwitch(switches::kLoginManager); 369 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); 370 command_line->AppendSwitch(chromeos::switches::kDisableLoginAnimations); 371 command_line->AppendSwitch(chromeos::switches::kDisableBootAnimation); 372 } 373 }; 374 375 // Same test as WallpaperManagerBrowserTest.UseMigratedWallpaperInfo. But 376 // disabled boot and login animation. 377 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation, 378 PRE_UseMigratedWallpaperInfo) { 379 // New user log in, a default wallpaper is loaded. 380 LogIn(kTestUser1); 381 WaitAsyncWallpaperLoad(); 382 // Old wallpaper migration code doesn't exist in codebase anymore. Modify user 383 // wallpaper info directly to simulate the wallpaper migration. See 384 // crosbug.com/38429 for details about why we modify wallpaper info this way. 385 WallpaperInfo info = { 386 "123", 387 WALLPAPER_LAYOUT_CENTER_CROPPED, 388 User::DEFAULT, 389 base::Time::Now().LocalMidnight() 390 }; 391 WallpaperManager::Get()->SetUserWallpaperInfo(kTestUser1, info, true); 392 } 393 394 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation, 395 UseMigratedWallpaperInfo) { 396 LogIn(kTestUser1); 397 WaitAsyncWallpaperLoad(); 398 // This test should finish normally. If timeout, it is probably because 399 // migrated wallpaper is somehow not loaded. Bad things can happen if 400 // wallpaper is not loaded at login screen. One example is: crosbug.com/38429. 401 } 402 403 // Same test as WallpaperManagerBrowserTest.UsePreMigrationWallpaperInfo. But 404 // disabled boot and login animation. 405 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation, 406 PRE_UsePreMigrationWallpaperInfo) { 407 // New user log in, a default wallpaper is loaded. 408 LogIn(kTestUser1); 409 WaitAsyncWallpaperLoad(); 410 // Old wallpaper migration code doesn't exist in codebase anymore. So if 411 // user's profile is not migrated, it is the same as no wallpaper info. To 412 // simulate this, we remove user's wallpaper info here. 413 WallpaperManager::Get()->RemoveUserWallpaperInfo(kTestUser1); 414 } 415 416 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation, 417 UsePreMigrationWallpaperInfo) { 418 LogIn(kTestUser1); 419 WaitAsyncWallpaperLoad(); 420 // This test should finish normally. If timeout, it is probably because chrome 421 // can not handle pre migrated user profile (M21 profile or older). 422 } 423 424 } // namespace chromeos 425