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   }
     73   virtual ~DesktopBackgroundControllerTest() {}
     74 
     75   virtual void SetUp() OVERRIDE {
     76     test::AshTestBase::SetUp();
     77     // Ash shell initialization creates wallpaper. Reset it so we can manually
     78     // control wallpaper creation and animation in our tests.
     79     RootWindowController* root_window_controller =
     80         Shell::GetPrimaryRootWindowController();
     81     root_window_controller->SetWallpaperController(NULL);
     82     root_window_controller->SetAnimatingWallpaperController(NULL);
     83     controller_ = Shell::GetInstance()->desktop_background_controller();
     84     wallpaper_delegate_ = static_cast<test::TestUserWallpaperDelegate*>(
     85         Shell::GetInstance()->user_wallpaper_delegate());
     86     controller_->set_wallpaper_reload_delay_for_test(0);
     87   }
     88 
     89  protected:
     90   // A color that can be passed to CreateImage(). Specifically chosen to not
     91   // conflict with any of the default wallpaper colors.
     92   static const SkColor kCustomWallpaperColor = SK_ColorMAGENTA;
     93 
     94   // Creates an image of size |size|.
     95   gfx::ImageSkia CreateImage(int width, int height, SkColor color) {
     96     SkBitmap bitmap;
     97     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
     98     bitmap.allocPixels();
     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 normal_duration_mode(
    154       ui::ScopedAnimationDurationScaleMode::NORMAL_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 normal_duration_mode(
    186       ui::ScopedAnimationDurationScaleMode::NORMAL_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 normal_duration_mode(
    234       ui::ScopedAnimationDurationScaleMode::NORMAL_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::BrowserThread::GetBlockingPool()->FlushForTesting();
    295   content::RunAllPendingInMessageLoop();
    296   gfx::ImageSkia resized_image = controller_->GetWallpaper();
    297   EXPECT_FALSE(image.BackedBySameObjectAs(resized_image));
    298   EXPECT_EQ(gfx::Size(320, 200).ToString(), resized_image.size().ToString());
    299 
    300   // Load the original wallpaper again and check that we're still using the
    301   // previously-resized image instead of doing another resize
    302   // (http://crbug.com/321402).
    303   controller_->SetWallpaperImage(image, WALLPAPER_LAYOUT_STRETCH);
    304   content::BrowserThread::GetBlockingPool()->FlushForTesting();
    305   content::RunAllPendingInMessageLoop();
    306   EXPECT_TRUE(resized_image.BackedBySameObjectAs(controller_->GetWallpaper()));
    307 }
    308 
    309 TEST_F(DesktopBackgroundControllerTest, GetMaxDisplaySize) {
    310   // Device scale factor shouldn't affect the native size.
    311   UpdateDisplay("1000x300*2");
    312   EXPECT_EQ(
    313       "1000x300",
    314       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    315 
    316   // Rotated display should return the rotated size.
    317   UpdateDisplay("1000x300*2/r");
    318   EXPECT_EQ(
    319       "300x1000",
    320       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    321 
    322   // UI Scaling shouldn't affect the native size.
    323   UpdateDisplay("1000x300*2 (at) 1.5");
    324   EXPECT_EQ(
    325       "1000x300",
    326       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    327 
    328   if (!SupportsMultipleDisplays())
    329     return;
    330 
    331   // First display has maximum size.
    332   UpdateDisplay("400x300,100x100");
    333   EXPECT_EQ(
    334       "400x300",
    335       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    336 
    337   // Second display has maximum size.
    338   UpdateDisplay("400x300,500x600");
    339   EXPECT_EQ(
    340       "500x600",
    341       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    342 
    343   // Maximum width and height belongs to different displays.
    344   UpdateDisplay("400x300,100x500");
    345   EXPECT_EQ(
    346       "400x500",
    347       DesktopBackgroundController::GetMaxDisplaySizeInNative().ToString());
    348 }
    349 
    350 
    351 }  // namespace ash
    352