Home | History | Annotate | Download | only in login
      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