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.
5 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
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/files/file_path.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/path_service.h"
18 #include "base/prefs/scoped_user_pref_update.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "chrome/browser/chromeos/login/user.h"
23 #include "chrome/browser/chromeos/login/user_manager.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "chrome/test/base/testing_browser_process.h"
28 #include "chromeos/chromeos_switches.h"
29 #include "chromeos/dbus/cryptohome_client.h"
30 #include "content/public/test/test_utils.h"
31 #include "ui/aura/env.h"
32 #include "ui/base/resource/resource_bundle.h"
40 const int kLargeWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_LARGE;
41 const int kSmallWallpaperResourceId = IDR_AURA_WALLPAPER_DEFAULT_SMALL;
43 int kLargeWallpaperWidth = 256;
44 int kLargeWallpaperHeight = ash::kLargeWallpaperMaxHeight;
45 int kSmallWallpaperWidth = 256;
46 int kSmallWallpaperHeight = ash::kSmallWallpaperMaxHeight;
48 const char kTestUser1[] = "test@domain.com";
49 const char kTestUser1Hash[] = "test@domain.com-hash";
53 class WallpaperManagerBrowserTest : public InProcessBrowserTest,
54 public DesktopBackgroundControllerObserver {
56 WallpaperManagerBrowserTest () : controller_(NULL),
60 virtual ~WallpaperManagerBrowserTest () {}
62 virtual void SetUpOnMainThread() OVERRIDE {
63 controller_ = ash::Shell::GetInstance()->desktop_background_controller();
64 controller_->AddObserver(this);
65 local_state_ = g_browser_process->local_state();
66 UpdateDisplay("800x600");
69 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
70 command_line->AppendSwitch(switches::kLoginManager);
71 command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
74 virtual void CleanUpOnMainThread() OVERRIDE {
75 controller_->RemoveObserver(this);
79 // Update the display configuration as given in |display_specs|.
80 // See ash::test::DisplayManagerTestApi::UpdateDisplay for more
82 void UpdateDisplay(const std::string& display_specs) {
83 ash::test::DisplayManagerTestApi display_manager_test_api(
84 ash::Shell::GetInstance()->display_manager());
85 display_manager_test_api.UpdateDisplay(display_specs);
88 void WaitAsyncWallpaperLoadStarted() {
89 base::MessageLoop::current()->RunUntilIdle();
92 void WaitAsyncWallpaperLoadFinished() {
93 base::MessageLoop::current()->RunUntilIdle();
94 while (WallpaperManager::Get()->loading_.size()) {
95 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
96 base::MessageLoop::current()->RunUntilIdle();
100 virtual void OnWallpaperDataChanged() OVERRIDE {
101 base::MessageLoop::current()->Quit();
105 // Return custom wallpaper path. Create directory if not exist.
106 base::FilePath GetCustomWallpaperPath(const char* sub_dir,
107 const std::string& username_hash,
108 const std::string& id) {
109 base::FilePath wallpaper_path =
110 WallpaperManager::Get()->GetCustomWallpaperPath(sub_dir,
113 if (!base::DirectoryExists(wallpaper_path.DirName()))
114 base::CreateDirectory(wallpaper_path.DirName());
116 return wallpaper_path;
119 // Logs in |username|.
120 void LogIn(const std::string& username, const std::string& username_hash) {
121 UserManager::Get()->UserLoggedIn(username, username_hash, false);
122 WaitAsyncWallpaperLoadStarted();
125 // Saves bitmap |resource_id| to disk.
126 void SaveUserWallpaperData(const base::FilePath& wallpaper_path,
128 scoped_refptr<base::RefCountedStaticMemory> image_data(
129 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
130 resource_id, ui::SCALE_FACTOR_100P));
131 int written = file_util::WriteFile(
133 reinterpret_cast<const char*>(image_data->front()),
135 EXPECT_EQ(static_cast<int>(image_data->size()), written);
138 int LoadedWallpapers() {
139 return WallpaperManager::Get()->loaded_wallpapers();
142 DesktopBackgroundController* controller_;
143 PrefService* local_state_;
146 DISALLOW_COPY_AND_ASSIGN(WallpaperManagerBrowserTest);
149 // Tests that the appropriate custom wallpaper (large vs. small) is loaded
150 // depending on the desktop resolution.
151 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
152 LoadCustomLargeWallpaperForLargeExternalScreen) {
153 WallpaperManager* wallpaper_manager = WallpaperManager::Get();
154 LogIn(kTestUser1, kTestUser1Hash);
155 std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
156 base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
157 kSmallWallpaperSubDir,
160 base::FilePath large_wallpaper_path = GetCustomWallpaperPath(
161 kLargeWallpaperSubDir,
165 // Saves the small/large resolution wallpapers to small/large custom
167 SaveUserWallpaperData(small_wallpaper_path,
168 kSmallWallpaperResourceId);
169 SaveUserWallpaperData(large_wallpaper_path,
170 kLargeWallpaperResourceId);
172 std::string relative_path = base::FilePath(kTestUser1Hash).Append(id).value();
173 // Saves wallpaper info to local state for user |kTestUser1|.
174 WallpaperInfo info = {
176 WALLPAPER_LAYOUT_CENTER_CROPPED,
178 base::Time::Now().LocalMidnight()
180 wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true);
182 // Set the wallpaper for |kTestUser1|.
183 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
184 WaitAsyncWallpaperLoadFinished();
185 gfx::ImageSkia wallpaper = controller_->GetWallpaper();
187 // Display is initialized to 800x600. The small resolution custom wallpaper is
189 EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width());
190 EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height());
192 // Hook up another 800x600 display. This shouldn't trigger a reload.
193 UpdateDisplay("800x600,800x600");
194 content::RunAllPendingInMessageLoop();
195 // The small resolution custom wallpaper is expected.
196 EXPECT_EQ(kSmallWallpaperWidth, wallpaper.width());
197 EXPECT_EQ(kSmallWallpaperHeight, wallpaper.height());
199 // Detach the secondary display.
200 UpdateDisplay("800x600");
201 // Hook up a 2000x2000 display. The large resolution custom wallpaper should
203 UpdateDisplay("800x600,2000x2000");
204 WaitAsyncWallpaperLoadFinished();
205 wallpaper = controller_->GetWallpaper();
207 // The large resolution custom wallpaper is expected.
208 EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width());
209 EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height());
211 // Detach the secondary display.
212 UpdateDisplay("800x600");
213 // Hook up the 2000x2000 display again. The large resolution default wallpaper
214 // should persist. Test for crbug/165788.
215 UpdateDisplay("800x600,2000x2000");
216 WaitAsyncWallpaperLoadFinished();
217 wallpaper = controller_->GetWallpaper();
219 // The large resolution custom wallpaper is expected.
220 EXPECT_EQ(kLargeWallpaperWidth, wallpaper.width());
221 EXPECT_EQ(kLargeWallpaperHeight, wallpaper.height());
224 // If chrome tries to reload the same wallpaper twice, the latter request should
225 // be prevented. Otherwise, there are some strange animation issues as
226 // described in crbug.com/158383.
227 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
228 PreventReloadingSameWallpaper) {
229 WallpaperManager* wallpaper_manager = WallpaperManager::Get();
230 // New user log in, a default wallpaper is loaded.
231 LogIn(kTestUser1, kTestUser1Hash);
232 EXPECT_EQ(1, LoadedWallpapers());
233 // Loads the same wallpaper before the initial one finished. It should be
235 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
236 WaitAsyncWallpaperLoadFinished();
237 EXPECT_EQ(1, LoadedWallpapers());
238 // Loads the same wallpaper after the initial one finished. It should be
240 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
241 WaitAsyncWallpaperLoadFinished();
242 EXPECT_EQ(1, LoadedWallpapers());
243 wallpaper_manager->ClearWallpaperCache();
245 // Change wallpaper to a custom wallpaper.
246 std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
247 base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
248 kSmallWallpaperSubDir,
251 SaveUserWallpaperData(small_wallpaper_path,
252 kSmallWallpaperResourceId);
254 std::string relative_path = base::FilePath(kTestUser1Hash).Append(id).value();
255 // Saves wallpaper info to local state for user |kTestUser1|.
256 WallpaperInfo info = {
258 WALLPAPER_LAYOUT_CENTER_CROPPED,
260 base::Time::Now().LocalMidnight()
262 wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true);
264 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
265 WaitAsyncWallpaperLoadStarted();
266 EXPECT_EQ(2, LoadedWallpapers());
267 // Loads the same wallpaper before the initial one finished. It should be
269 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
270 WaitAsyncWallpaperLoadStarted();
271 EXPECT_EQ(2, LoadedWallpapers());
272 wallpaper_manager->SetUserWallpaperNow(kTestUser1);
273 WaitAsyncWallpaperLoadFinished();
274 EXPECT_EQ(2, LoadedWallpapers());
277 // Some users have old user profiles which may have legacy wallpapers. And these
278 // lagacy wallpapers should migrate to new wallpaper picker version seamlessly.
279 // This tests make sure we compatible with migrated old wallpapers.
281 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
282 PRE_UseMigratedWallpaperInfo) {
283 // New user log in, a default wallpaper is loaded.
284 LogIn(kTestUser1, kTestUser1Hash);
285 // Old wallpaper migration code doesn't exist in codebase anymore. Modify user
286 // wallpaper info directly to simulate the wallpaper migration. See
287 // crosbug.com/38429 for details about why we modify wallpaper info this way.
288 WallpaperInfo info = {
290 WALLPAPER_LAYOUT_CENTER_CROPPED,
292 base::Time::Now().LocalMidnight()
294 base::FilePath user_data_dir;
295 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
296 SaveUserWallpaperData(user_data_dir.Append("123"),
297 kLargeWallpaperResourceId);
298 WallpaperManager::Get()->SetUserWallpaperInfo(kTestUser1, info, true);
301 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
302 UseMigratedWallpaperInfo) {
303 LogIn(kTestUser1, kTestUser1Hash);
304 WaitAsyncWallpaperLoadFinished();
305 // This test should finish normally. If timeout, it is probably because
306 // migrated wallpaper is somehow not loaded. Bad things can happen if
307 // wallpaper is not loaded at login screen. One example is: crosbug.com/38429.
310 // Some users have old user profiles which may never get a chance to migrate.
311 // This tests make sure we compatible with these profiles.
312 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
313 PRE_UsePreMigrationWallpaperInfo) {
314 // New user log in, a default wallpaper is loaded.
315 LogIn(kTestUser1, kTestUser1Hash);
316 // Old wallpaper migration code doesn't exist in codebase anymore. So if
317 // user's profile is not migrated, it is the same as no wallpaper info. To
318 // simulate this, we remove user's wallpaper info here.
319 WallpaperManager::Get()->RemoveUserWallpaperInfo(kTestUser1);
322 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
323 UsePreMigrationWallpaperInfo) {
324 LogIn(kTestUser1, kTestUser1Hash);
325 WaitAsyncWallpaperLoadFinished();
326 // This test should finish normally. If timeout, it is probably because chrome
327 // can not handle pre migrated user profile (M21 profile or older).
330 // Test for http://crbug.com/265689. When hooked up a large external monitor,
331 // the default large resolution wallpaper should load.
332 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
333 HotPlugInScreenAtGAIALoginScreen) {
334 UpdateDisplay("800x600");
335 // Set initial wallpaper to the default wallpaper.
336 WallpaperManager::Get()->SetDefaultWallpaperNow();
337 WaitAsyncWallpaperLoadFinished();
339 // Hook up a 2000x2000 display. The large resolution custom wallpaper should
341 UpdateDisplay("800x600,2000x2000");
342 WaitAsyncWallpaperLoadFinished();
345 class WallpaperManagerBrowserTestNoAnimation
346 : public WallpaperManagerBrowserTest {
348 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
349 command_line->AppendSwitch(switches::kLoginManager);
350 command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
351 command_line->AppendSwitch(chromeos::switches::kDisableLoginAnimations);
352 command_line->AppendSwitch(chromeos::switches::kDisableBootAnimation);
356 // Same test as WallpaperManagerBrowserTest.UseMigratedWallpaperInfo. But
357 // disabled boot and login animation.
358 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
359 PRE_UseMigratedWallpaperInfo) {
360 // New user log in, a default wallpaper is loaded.
361 LogIn(kTestUser1, kTestUser1Hash);
362 // Old wallpaper migration code doesn't exist in codebase anymore. Modify user
363 // wallpaper info directly to simulate the wallpaper migration. See
364 // crosbug.com/38429 for details about why we modify wallpaper info this way.
365 WallpaperInfo info = {
367 WALLPAPER_LAYOUT_CENTER_CROPPED,
369 base::Time::Now().LocalMidnight()
371 base::FilePath user_data_dir;
372 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
373 SaveUserWallpaperData(user_data_dir.Append("123"),
374 kLargeWallpaperResourceId);
375 WallpaperManager::Get()->SetUserWallpaperInfo(kTestUser1, info, true);
378 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
379 UseMigratedWallpaperInfo) {
380 LogIn(kTestUser1, kTestUser1Hash);
381 WaitAsyncWallpaperLoadFinished();
382 // This test should finish normally. If timeout, it is probably because
383 // migrated wallpaper is somehow not loaded. Bad things can happen if
384 // wallpaper is not loaded at login screen. One example is: crosbug.com/38429.
387 // Same test as WallpaperManagerBrowserTest.UsePreMigrationWallpaperInfo. But
388 // disabled boot and login animation.
389 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
390 PRE_UsePreMigrationWallpaperInfo) {
391 // New user log in, a default wallpaper is loaded.
392 LogIn(kTestUser1, kTestUser1Hash);
393 WaitAsyncWallpaperLoadFinished();
394 // Old wallpaper migration code doesn't exist in codebase anymore. So if
395 // user's profile is not migrated, it is the same as no wallpaper info. To
396 // simulate this, we remove user's wallpaper info here.
397 WallpaperManager::Get()->RemoveUserWallpaperInfo(kTestUser1);
400 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
401 UsePreMigrationWallpaperInfo) {
402 LogIn(kTestUser1, kTestUser1Hash);
403 WaitAsyncWallpaperLoadFinished();
404 // This test should finish normally. If timeout, it is probably because chrome
405 // can not handle pre migrated user profile (M21 profile or older).
408 class WallpaperManagerBrowserTestCrashRestore
409 : public WallpaperManagerBrowserTest {
411 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
412 command_line->AppendSwitch(chromeos::switches::kDisableLoginAnimations);
413 command_line->AppendSwitch(chromeos::switches::kDisableBootAnimation);
414 command_line->AppendSwitch(::switches::kMultiProfiles);
415 command_line->AppendSwitchASCII(switches::kLoginUser, kTestUser1);
416 command_line->AppendSwitchASCII(switches::kLoginProfile,
417 CryptohomeClient::GetStubSanitizedUsername(kTestUser1));
421 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
422 PRE_RestoreWallpaper) {
423 LogIn(kTestUser1, kTestUser1Hash);
424 WaitAsyncWallpaperLoadFinished();
427 // Test for crbug.com/270278. It simulates a browser crash and verifies if user
428 // wallpaper is loaded.
429 IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
431 EXPECT_EQ(1, LoadedWallpapers());
434 } // namespace chromeos