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