Home | History | Annotate | Download | only in desktop_background
      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 "ash/desktop_background/desktop_background_controller.h"
      6 
      7 #include <cmath>
      8 #include <cstdlib>
      9 
     10 #include "ash/ash_switches.h"
     11 #include "ash/desktop_background/desktop_background_widget_controller.h"
     12 #include "ash/root_window_controller.h"
     13 #include "ash/shell.h"
     14 #include "ash/shell_window_ids.h"
     15 #include "ash/test/ash_test_base.h"
     16 #include "ash/test/display_manager_test_api.h"
     17 #include "ash/test/test_user_wallpaper_delegate.h"
     18 #include "base/message_loop/message_loop.h"
     19 #include "base/threading/sequenced_worker_pool.h"
     20 #include "content/public/browser/browser_thread.h"
     21 #include "content/public/test/test_browser_thread.h"
     22 #include "content/public/test/test_utils.h"
     23 #include "third_party/skia/include/core/SkBitmap.h"
     24 #include "third_party/skia/include/core/SkColor.h"
     25 #include "ui/aura/window_event_dispatcher.h"
     26 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
     27 #include "ui/compositor/test/layer_animator_test_controller.h"
     28 
     29 using aura::RootWindow;
     30 using aura::Window;
     31 
     32 namespace ash {
     33 namespace {
     34 
     35 // Containers IDs used for tests.
     36 const int kDesktopBackgroundId = ash::kShellWindowId_DesktopBackgroundContainer;
     37 const int kLockScreenBackgroundId =
     38     ash::kShellWindowId_LockScreenBackgroundContainer;
     39 
     40 // Returns number of child windows in a shell window container.
     41 int ChildCountForContainer(int container_id) {
     42   Window* root = ash::Shell::GetPrimaryRootWindow();
     43   Window* container = root->GetChildById(container_id);
     44   return static_cast<int>(container->children().size());
     45 }
     46 
     47 // Steps a widget's layer animation until it is completed. Animations must be
     48 // enabled.
     49 void RunAnimationForWidget(views::Widget* widget) {
     50   // Animations must be enabled for stepping to work.
     51   ASSERT_NE(ui::ScopedAnimationDurationScaleMode::duration_scale_mode(),
     52             ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
     53 
     54   ui::Layer* layer = widget->GetNativeView()->layer();
     55   ui::LayerAnimatorTestController controller(layer->GetAnimator());
     56   // Multiple steps are required to complete complex animations.
     57   // TODO(vollick): This should not be necessary. crbug.com/154017
     58   while (controller.animator()->is_animating()) {
     59     controller.StartThreadedAnimationsIfNeeded();
     60     base::TimeTicks step_time = controller.animator()->last_step_time();
     61     layer->GetAnimator()->Step(step_time +
     62                                base::TimeDelta::FromMilliseconds(1000));
     63   }
     64 }
     65 
     66 }  // namespace
     67 
     68 class DesktopBackgroundControllerTest : public test::AshTestBase {
     69  public:
     70   DesktopBackgroundControllerTest()
     71       : controller_(NULL),
     72         wallpaper_delegate_(NULL) {
     73   }
     74   virtual ~DesktopBackgroundControllerTest() {}
     75 
     76   virtual void SetUp() OVERRIDE {
     77     test::AshTestBase::SetUp();
     78     // Ash shell initialization creates wallpaper. Reset it so we can manually
     79     // control wallpaper creation and animation in our tests.
     80     RootWindowController* root_window_controller =
     81         Shell::GetPrimaryRootWindowController();
     82     root_window_controller->SetWallpaperController(NULL);
     83     root_window_controller->SetAnimatingWallpaperController(NULL);
     84     controller_ = Shell::GetInstance()->desktop_background_controller();
     85     wallpaper_delegate_ = static_cast<test::TestUserWallpaperDelegate*>(
     86         Shell::GetInstance()->user_wallpaper_delegate());
     87     controller_->set_wallpaper_reload_delay_for_test(0);
     88   }
     89 
     90  protected:
     91   // A color that can be passed to CreateImage(). Specifically chosen to not
     92   // conflict with any of the default wallpaper colors.
     93   static const SkColor kCustomWallpaperColor = SK_ColorMAGENTA;
     94 
     95   // Creates an image of size |size|.
     96   gfx::ImageSkia CreateImage(int width, int height, SkColor color) {
     97     SkBitmap bitmap;
     98     bitmap.allocN32Pixels(width, height);
     99     bitmap.eraseColor(color);
    100     gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
    101     return image;
    102   }
    103 
    104   // Runs kAnimatingDesktopController's animation to completion.
    105   // TODO(bshe): Don't require tests to run animations; it's slow.
    106   void RunDesktopControllerAnimation() {
    107     DesktopBackgroundWidgetController* controller =
    108         Shell::GetPrimaryRootWindowController()
    109             ->animating_wallpaper_controller()
    110             ->GetController(false);
    111     EXPECT_TRUE(!!controller);
    112     ASSERT_NO_FATAL_FAILURE(RunAnimationForWidget(controller->widget()));
    113   }
    114 
    115   DesktopBackgroundController* controller_;  // Not owned.
    116 
    117   test::TestUserWallpaperDelegate* wallpaper_delegate_;
    118 
    119  private:
    120   DISALLOW_COPY_AND_ASSIGN(DesktopBackgroundControllerTest);
    121 };
    122 
    123 TEST_F(DesktopBackgroundControllerTest, BasicReparenting) {
    124   DesktopBackgroundController* controller =
    125       Shell::GetInstance()->desktop_background_controller();
    126   controller->CreateEmptyWallpaper();
    127 
    128   // Wallpaper view/window exists in the desktop background container and
    129   // nothing is in the lock screen background container.
    130   EXPECT_EQ(1, ChildCountForContainer(kDesktopBackgroundId));
    131   EXPECT_EQ(0, ChildCountForContainer(kLockScreenBackgroundId));
    132 
    133   // Moving background to lock container should succeed the first time but
    134   // subsequent calls should do nothing.
    135   EXPECT_TRUE(controller->MoveDesktopToLockedContainer());
    136   EXPECT_FALSE(controller->MoveDesktopToLockedContainer());
    137 
    138   // One window is moved from desktop to lock container.
    139   EXPECT_EQ(0, ChildCountForContainer(kDesktopBackgroundId));
    140   EXPECT_EQ(1, ChildCountForContainer(kLockScreenBackgroundId));
    141 
    142   // Moving background to desktop container should succeed the first time.
    143   EXPECT_TRUE(controller->MoveDesktopToUnlockedContainer());
    144   EXPECT_FALSE(controller->MoveDesktopToUnlockedContainer());
    145 
    146   // One window is moved from lock to desktop container.
    147   EXPECT_EQ(1, ChildCountForContainer(kDesktopBackgroundId));
    148   EXPECT_EQ(0, ChildCountForContainer(kLockScreenBackgroundId));
    149 }
    150 
    151 TEST_F(DesktopBackgroundControllerTest, ControllerOwnership) {
    152   // We cannot short-circuit animations for this test.
    153   ui::ScopedAnimationDurationScaleMode test_duration_mode(
    154       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
    155 
    156   // Create wallpaper and background view.
    157   DesktopBackgroundController* controller =
    158       Shell::GetInstance()->desktop_background_controller();
    159   controller->CreateEmptyWallpaper();
    160 
    161   // The new wallpaper is ready to start animating. kAnimatingDesktopController
    162   // holds the widget controller instance. kDesktopController will get it later.
    163   RootWindowController* root_window_controller =
    164       Shell::GetPrimaryRootWindowController();
    165   EXPECT_TRUE(root_window_controller->animating_wallpaper_controller()->
    166               GetController(false));
    167 
    168   // kDesktopController will receive the widget controller when the animation
    169   // is done.
    170   EXPECT_FALSE(root_window_controller->wallpaper_controller());
    171 
    172   // Force the widget's layer animation to play to completion.
    173   RunDesktopControllerAnimation();
    174 
    175   // Ownership has moved from kAnimatingDesktopController to kDesktopController.
    176   EXPECT_FALSE(root_window_controller->animating_wallpaper_controller()->
    177                GetController(false));
    178   EXPECT_TRUE(root_window_controller->wallpaper_controller());
    179 }
    180 
    181 // Test for crbug.com/149043 "Unlock screen, no launcher appears". Ensure we
    182 // move all desktop views if there are more than one.
    183 TEST_F(DesktopBackgroundControllerTest, BackgroundMovementDuringUnlock) {
    184   // We cannot short-circuit animations for this test.
    185   ui::ScopedAnimationDurationScaleMode test_duration_mode(
    186       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
    187 
    188   // Reset wallpaper state, see ControllerOwnership above.
    189   DesktopBackgroundController* controller =
    190       Shell::GetInstance()->desktop_background_controller();
    191   controller->CreateEmptyWallpaper();
    192 
    193   // Run wallpaper show animation to completion.
    194   RunDesktopControllerAnimation();
    195 
    196   // User locks the screen, which moves the background forward.
    197   controller->MoveDesktopToLockedContainer();
    198 
    199   // Suspend/resume cycle causes wallpaper to refresh, loading a new desktop
    200   // background that will animate in on top of the old one.
    201   controller->CreateEmptyWallpaper();
    202 
    203   // In this state we have two desktop background views stored in different
    204   // properties. Both are in the lock screen background container.
    205   RootWindowController* root_window_controller =
    206       Shell::GetPrimaryRootWindowController();
    207   EXPECT_TRUE(root_window_controller->animating_wallpaper_controller()->
    208               GetController(false));
    209   EXPECT_TRUE(root_window_controller->wallpaper_controller());
    210   EXPECT_EQ(0, ChildCountForContainer(kDesktopBackgroundId));
    211   EXPECT_EQ(2, ChildCountForContainer(kLockScreenBackgroundId));
    212 
    213   // Before the wallpaper's animation completes, user unlocks the screen, which
    214   // moves the desktop to the back.
    215   controller->MoveDesktopToUnlockedContainer();
    216 
    217   // Ensure both desktop backgrounds have moved.
    218   EXPECT_EQ(2, ChildCountForContainer(kDesktopBackgroundId));
    219   EXPECT_EQ(0, ChildCountForContainer(kLockScreenBackgroundId));
    220 
    221   // Finish the new desktop background animation.
    222   RunDesktopControllerAnimation();
    223 
    224   // Now there is one desktop background, in the back.
    225   EXPECT_EQ(1, ChildCountForContainer(kDesktopBackgroundId));
    226   EXPECT_EQ(0, ChildCountForContainer(kLockScreenBackgroundId));
    227 }
    228 
    229 // Test for crbug.com/156542. Animating wallpaper should immediately finish
    230 // animation and replace current wallpaper before next animation starts.
    231 TEST_F(DesktopBackgroundControllerTest, ChangeWallpaperQuick) {
    232   // We cannot short-circuit animations for this test.
    233   ui::ScopedAnimationDurationScaleMode test_duration_mode(
    234       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
    235 
    236   // Reset wallpaper state, see ControllerOwnership above.
    237   DesktopBackgroundController* controller =
    238       Shell::GetInstance()->desktop_background_controller();
    239   controller->CreateEmptyWallpaper();
    240 
    241   // Run wallpaper show animation to completion.
    242   RunDesktopControllerAnimation();
    243 
    244   // Change to a new wallpaper.
    245   controller->CreateEmptyWallpaper();
    246 
    247   RootWindowController* root_window_controller =
    248       Shell::GetPrimaryRootWindowController();
    249   DesktopBackgroundWidgetController* animating_controller =
    250       root_window_controller->animating_wallpaper_controller()->GetController(
    251           false);
    252   EXPECT_TRUE(animating_controller);
    253   EXPECT_TRUE(root_window_controller->wallpaper_controller());
    254 
    255   // Change to another wallpaper before animation finished.
    256   controller->CreateEmptyWallpaper();
    257 
    258   // The animating controller should immediately move to desktop controller.
    259   EXPECT_EQ(animating_controller,
    260             root_window_controller->wallpaper_controller());
    261 
    262   // Cache the new animating controller.
    263   animating_controller = root_window_controller->
    264       animating_wallpaper_controller()->GetController(false);
    265 
    266   // Run wallpaper show animation to completion.
    267   ASSERT_NO_FATAL_FAILURE(
    268       RunAnimationForWidget(
    269           root_window_controller->animating_wallpaper_controller()->
    270               GetController(false)->widget()));
    271 
    272   EXPECT_TRUE(root_window_controller->wallpaper_controller());
    273   EXPECT_FALSE(root_window_controller->animating_wallpaper_controller()->
    274                GetController(false));
    275   // The desktop controller should be the last created animating controller.
    276   EXPECT_EQ(animating_controller,
    277             root_window_controller->wallpaper_controller());
    278 }
    279 
    280 TEST_F(DesktopBackgroundControllerTest, ResizeCustomWallpaper) {
    281   if (!SupportsMultipleDisplays())
    282     return;
    283 
    284   test::DisplayManagerTestApi display_manager_test_api(
    285       Shell::GetInstance()->display_manager());
    286   display_manager_test_api.UpdateDisplay("320x200");
    287 
    288   gfx::ImageSkia image = CreateImage(640, 480, kCustomWallpaperColor);
    289 
    290   // Set the image as custom wallpaper, wait for the resize to finish, and check
    291   // that the resized image is the expected size.
    292   controller_->SetWallpaperImage(image, WALLPAPER_LAYOUT_STRETCH);
    293   EXPECT_TRUE(image.BackedBySameObjectAs(controller_->GetWallpaper()));
    294   content::RunAllBlockingPoolTasksUntilIdle();
    295   gfx::ImageSkia resized_image = controller_->GetWallpaper();
    296   EXPECT_FALSE(image.BackedBySameObjectAs(resized_image));
    297   EXPECT_EQ(gfx::Size(320, 200).ToString(), resized_image.size().ToString());
    298 
    299   // Load the original wallpaper again and check that we're still using the
    300   // previously-resized image instead of doing another resize
    301   // (http://crbug.com/321402).
    302   controller_->SetWallpaperImage(image, WALLPAPER_LAYOUT_STRETCH);
    303   content::RunAllBlockingPoolTasksUntilIdle();
    304   EXPECT_TRUE(resized_image.BackedBySameObjectAs(controller_->GetWallpaper()));
    305 }
    306 
    307 TEST_F(DesktopBackgroundControllerTest, GetMaxDisplaySize) {
    308   // Device scale factor shouldn't affect the native size.
    309   UpdateDisplay("1000x300*2");
    310   EXPECT_EQ(
    311       "1000x300",
    312       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    313 
    314   // Rotated display should return the rotated size.
    315   UpdateDisplay("1000x300*2/r");
    316   EXPECT_EQ(
    317       "300x1000",
    318       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    319 
    320   // UI Scaling shouldn't affect the native size.
    321   UpdateDisplay("1000x300*2 (at) 1.5");
    322   EXPECT_EQ(
    323       "1000x300",
    324       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    325 
    326   if (!SupportsMultipleDisplays())
    327     return;
    328 
    329   // First display has maximum size.
    330   UpdateDisplay("400x300,100x100");
    331   EXPECT_EQ(
    332       "400x300",
    333       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    334 
    335   // Second display has maximum size.
    336   UpdateDisplay("400x300,500x600");
    337   EXPECT_EQ(
    338       "500x600",
    339       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    340 
    341   // Maximum width and height belongs to different displays.
    342   UpdateDisplay("400x300,100x500");
    343   EXPECT_EQ(
    344       "400x500",
    345       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    346 }
    347 
    348 
    349 }  // namespace ash
    350