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