1 // Copyright 2014 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/root_window_controller.h" 6 #include "ash/screen_util.h" 7 #include "ash/shell.h" 8 #include "ash/shell_window_ids.h" 9 #include "ash/test/ash_test_base.h" 10 #include "ash/wm/window_state.h" 11 #include "base/basictypes.h" 12 #include "base/command_line.h" 13 #include "ui/aura/client/aura_constants.h" 14 #include "ui/aura/window.h" 15 #include "ui/gfx/screen.h" 16 #include "ui/keyboard/keyboard_controller.h" 17 #include "ui/keyboard/keyboard_controller_proxy.h" 18 #include "ui/keyboard/keyboard_switches.h" 19 #include "ui/keyboard/keyboard_util.h" 20 #include "ui/views/widget/widget.h" 21 #include "ui/views/widget/widget_delegate.h" 22 23 namespace ash { 24 namespace test { 25 26 namespace { 27 28 const int kVirtualKeyboardHeight = 100; 29 30 // A login implementation of WidgetDelegate. 31 class LoginTestWidgetDelegate : public views::WidgetDelegate { 32 public: 33 explicit LoginTestWidgetDelegate(views::Widget* widget) : widget_(widget) { 34 } 35 virtual ~LoginTestWidgetDelegate() {} 36 37 // Overridden from WidgetDelegate: 38 virtual void DeleteDelegate() OVERRIDE { 39 delete this; 40 } 41 virtual views::Widget* GetWidget() OVERRIDE { 42 return widget_; 43 } 44 virtual const views::Widget* GetWidget() const OVERRIDE { 45 return widget_; 46 } 47 virtual bool CanActivate() const OVERRIDE { 48 return true; 49 } 50 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { 51 return true; 52 } 53 54 private: 55 views::Widget* widget_; 56 57 DISALLOW_COPY_AND_ASSIGN(LoginTestWidgetDelegate); 58 }; 59 60 } // namespace 61 62 class LockLayoutManagerTest : public AshTestBase { 63 public: 64 virtual void SetUp() OVERRIDE { 65 // Allow a virtual keyboard (and initialize it per default). 66 CommandLine::ForCurrentProcess()->AppendSwitch( 67 keyboard::switches::kEnableVirtualKeyboard); 68 AshTestBase::SetUp(); 69 Shell::GetPrimaryRootWindowController()->ActivateKeyboard( 70 keyboard::KeyboardController::GetInstance()); 71 } 72 73 virtual void TearDown() OVERRIDE { 74 Shell::GetPrimaryRootWindowController()->DeactivateKeyboard( 75 keyboard::KeyboardController::GetInstance()); 76 AshTestBase::TearDown(); 77 } 78 79 aura::Window* CreateTestLoginWindow(views::Widget::InitParams params, 80 bool use_delegate) { 81 aura::Window* parent = Shell::GetPrimaryRootWindowController()-> 82 GetContainer(ash::kShellWindowId_LockScreenContainer); 83 params.parent = parent; 84 views::Widget* widget = new views::Widget; 85 if (use_delegate) 86 params.delegate = new LoginTestWidgetDelegate(widget); 87 widget->Init(params); 88 widget->Show(); 89 aura::Window* window = widget->GetNativeView(); 90 return window; 91 } 92 93 // Show or hide the keyboard. 94 void ShowKeyboard(bool show) { 95 keyboard::KeyboardController* keyboard = 96 keyboard::KeyboardController::GetInstance(); 97 ASSERT_TRUE(keyboard); 98 if (show == keyboard->keyboard_visible()) 99 return; 100 101 if (show) { 102 keyboard->ShowKeyboard(true); 103 if (keyboard->proxy()->GetKeyboardWindow()->bounds().height() == 0) { 104 keyboard->proxy()->GetKeyboardWindow()->SetBounds( 105 keyboard::KeyboardBoundsFromWindowBounds( 106 keyboard->GetContainerWindow()->bounds(), 107 kVirtualKeyboardHeight)); 108 } 109 } else { 110 keyboard->HideKeyboard(keyboard::KeyboardController::HIDE_REASON_MANUAL); 111 } 112 113 DCHECK_EQ(show, keyboard->keyboard_visible()); 114 } 115 }; 116 117 TEST_F(LockLayoutManagerTest, NorwmalWindowBoundsArePreserved) { 118 gfx::Rect screen_bounds = Shell::GetScreen()->GetPrimaryDisplay().bounds(); 119 120 views::Widget::InitParams widget_params( 121 views::Widget::InitParams::TYPE_WINDOW); 122 const gfx::Rect bounds = gfx::Rect(10, 10, 300, 300); 123 widget_params.bounds = bounds; 124 scoped_ptr<aura::Window> window( 125 CreateTestLoginWindow(widget_params, false /* use_delegate */)); 126 EXPECT_EQ(bounds.ToString(), window->GetBoundsInScreen().ToString()); 127 128 gfx::Rect work_area = 129 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window.get()); 130 window->SetBounds(work_area); 131 132 EXPECT_EQ(work_area.ToString(), window->GetBoundsInScreen().ToString()); 133 EXPECT_NE(screen_bounds.ToString(), window->GetBoundsInScreen().ToString()); 134 135 const gfx::Rect bounds2 = gfx::Rect(100, 100, 200, 200); 136 window->SetBounds(bounds2); 137 EXPECT_EQ(bounds2.ToString(), window->GetBoundsInScreen().ToString()); 138 } 139 140 TEST_F(LockLayoutManagerTest, MaximizedFullscreenWindowBoundsAreEqualToScreen) { 141 gfx::Rect screen_bounds = Shell::GetScreen()->GetPrimaryDisplay().bounds(); 142 143 views::Widget::InitParams widget_params( 144 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 145 widget_params.show_state = ui::SHOW_STATE_MAXIMIZED; 146 const gfx::Rect bounds = gfx::Rect(10, 10, 300, 300); 147 widget_params.bounds = bounds; 148 // Maximized TYPE_WINDOW_FRAMELESS windows needs a delegate defined otherwise 149 // it won't get initial SetBounds event. 150 scoped_ptr<aura::Window> maximized_window( 151 CreateTestLoginWindow(widget_params, true /* use_delegate */)); 152 153 widget_params.show_state = ui::SHOW_STATE_FULLSCREEN; 154 widget_params.delegate = NULL; 155 scoped_ptr<aura::Window> fullscreen_window( 156 CreateTestLoginWindow(widget_params, false /* use_delegate */)); 157 158 EXPECT_EQ(screen_bounds.ToString(), 159 maximized_window->GetBoundsInScreen().ToString()); 160 EXPECT_EQ(screen_bounds.ToString(), 161 fullscreen_window->GetBoundsInScreen().ToString()); 162 163 gfx::Rect work_area = 164 ScreenUtil::GetDisplayWorkAreaBoundsInParent(maximized_window.get()); 165 maximized_window->SetBounds(work_area); 166 167 EXPECT_NE(work_area.ToString(), 168 maximized_window->GetBoundsInScreen().ToString()); 169 EXPECT_EQ(screen_bounds.ToString(), 170 maximized_window->GetBoundsInScreen().ToString()); 171 172 work_area = 173 ScreenUtil::GetDisplayWorkAreaBoundsInParent(fullscreen_window.get()); 174 fullscreen_window->SetBounds(work_area); 175 EXPECT_NE(work_area.ToString(), 176 fullscreen_window->GetBoundsInScreen().ToString()); 177 EXPECT_EQ(screen_bounds.ToString(), 178 fullscreen_window->GetBoundsInScreen().ToString()); 179 180 const gfx::Rect bounds2 = gfx::Rect(100, 100, 200, 200); 181 maximized_window->SetBounds(bounds2); 182 fullscreen_window->SetBounds(bounds2); 183 EXPECT_EQ(screen_bounds.ToString(), 184 maximized_window->GetBoundsInScreen().ToString()); 185 EXPECT_EQ(screen_bounds.ToString(), 186 fullscreen_window->GetBoundsInScreen().ToString()); 187 } 188 189 TEST_F(LockLayoutManagerTest, KeyboardBounds) { 190 gfx::Rect screen_bounds = Shell::GetScreen()->GetPrimaryDisplay().bounds(); 191 192 views::Widget::InitParams widget_params( 193 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 194 widget_params.show_state = ui::SHOW_STATE_FULLSCREEN; 195 scoped_ptr<aura::Window> window( 196 CreateTestLoginWindow(widget_params, false /* use_delegate */)); 197 198 EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString()); 199 200 // When virtual keyboard overscroll is enabled keyboard bounds should not 201 // affect window bounds. 202 keyboard::SetKeyboardOverscrollOverride( 203 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED); 204 ShowKeyboard(true); 205 EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString()); 206 ShowKeyboard(false); 207 208 // When virtual keyboard overscroll is disabled keyboard bounds do 209 // affect window bounds. 210 keyboard::SetKeyboardOverscrollOverride( 211 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 212 ShowKeyboard(true); 213 keyboard::KeyboardController* keyboard = 214 keyboard::KeyboardController::GetInstance(); 215 gfx::Rect target_bounds(screen_bounds); 216 target_bounds.set_height(target_bounds.height() - 217 keyboard->proxy()->GetKeyboardWindow()->bounds().height()); 218 EXPECT_EQ(target_bounds.ToString(), window->GetBoundsInScreen().ToString()); 219 ShowKeyboard(false); 220 221 keyboard::SetKeyboardOverscrollOverride( 222 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); 223 } 224 225 TEST_F(LockLayoutManagerTest, MultipleMonitors) { 226 if (!SupportsMultipleDisplays()) 227 return; 228 229 UpdateDisplay("300x400,400x500"); 230 gfx::Rect screen_bounds = Shell::GetScreen()->GetPrimaryDisplay().bounds(); 231 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 232 233 views::Widget::InitParams widget_params( 234 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 235 widget_params.show_state = ui::SHOW_STATE_FULLSCREEN; 236 scoped_ptr<aura::Window> window( 237 CreateTestLoginWindow(widget_params, false /* use_delegate */)); 238 window->SetProperty(aura::client::kCanMaximizeKey, true); 239 240 EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString()); 241 242 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 243 244 wm::WindowState* window_state = wm::GetWindowState(window.get()); 245 window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40)); 246 247 // Maximize the window with as the restore bounds is inside 2nd display but 248 // lock container windows are always on primary display. 249 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); 250 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 251 EXPECT_EQ("0,0 300x400", window->GetBoundsInScreen().ToString()); 252 253 window_state->Restore(); 254 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 255 EXPECT_EQ("0,0 300x400", window->GetBoundsInScreen().ToString()); 256 257 window_state->SetRestoreBoundsInScreen(gfx::Rect(280, 0, 30, 40)); 258 window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); 259 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 260 EXPECT_EQ("0,0 300x400", window->GetBoundsInScreen().ToString()); 261 262 window_state->Restore(); 263 EXPECT_EQ(root_windows[0], window->GetRootWindow()); 264 EXPECT_EQ("0,0 300x400", window->GetBoundsInScreen().ToString()); 265 266 gfx::Rect work_area = 267 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window.get()); 268 window->SetBounds(work_area); 269 // Usually work_area takes Shelf into account but that doesn't affect 270 // LockScreen container windows. 271 EXPECT_NE(work_area.ToString(), window->GetBoundsInScreen().ToString()); 272 EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString()); 273 } 274 275 } // namespace test 276 } // namespace ash 277