Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: ash/common/wm/workspace/workspace_layout_manager_unittest.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/common/wm/workspace/workspace_layout_manager.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "ash/common/session/session_state_delegate.h"
11 #include "ash/common/shelf/shelf_constants.h"
12 #include "ash/common/shelf/shelf_layout_manager.h"
13 #include "ash/common/shelf/wm_shelf.h"
14 #include "ash/common/shell_observer.h"
15 #include "ash/common/test/ash_test.h"
16 #include "ash/common/test/test_session_state_delegate.h"
17 #include "ash/common/wm/fullscreen_window_finder.h"
18 #include "ash/common/wm/maximize_mode/workspace_backdrop_delegate.h"
19 #include "ash/common/wm/window_state.h"
20 #include "ash/common/wm/wm_event.h"
21 #include "ash/common/wm/wm_screen_util.h"
22 #include "ash/common/wm/workspace/workspace_window_resizer.h"
23 #include "ash/common/wm_shell.h"
24 #include "ash/common/wm_window.h"
25 #include "ash/public/cpp/shell_window_ids.h"
26 #include "ash/root_window_controller.h"
27 #include "ash/wm/window_state_aura.h"
28 #include "base/command_line.h"
29 #include "base/run_loop.h"
30 #include "ui/aura/env.h"
31 #include "ui/base/ui_base_switches.h"
32 #include "ui/base/ui_base_types.h"
33 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
34 #include "ui/display/display.h"
35 #include "ui/display/screen.h"
36 #include "ui/gfx/geometry/insets.h"
37 #include "ui/views/widget/widget.h"
38 #include "ui/views/widget/widget_delegate.h"
39
40 namespace ash {
41 namespace {
42
43 class MaximizeDelegateView : public views::WidgetDelegateView {
44 public:
45 explicit MaximizeDelegateView(const gfx::Rect& initial_bounds)
46 : initial_bounds_(initial_bounds) {}
47 ~MaximizeDelegateView() override {}
48
49 bool GetSavedWindowPlacement(const views::Widget* widget,
50 gfx::Rect* bounds,
51 ui::WindowShowState* show_state) const override {
52 *bounds = initial_bounds_;
53 *show_state = ui::SHOW_STATE_MAXIMIZED;
54 return true;
55 }
56
57 private:
58 const gfx::Rect initial_bounds_;
59
60 DISALLOW_COPY_AND_ASSIGN(MaximizeDelegateView);
61 };
62
63 class TestShellObserver : public ShellObserver {
64 public:
65 TestShellObserver() : call_count_(0), is_fullscreen_(false) {
66 WmShell::Get()->AddShellObserver(this);
67 }
68
69 ~TestShellObserver() override { WmShell::Get()->RemoveShellObserver(this); }
70
71 void OnFullscreenStateChanged(bool is_fullscreen,
72 WmWindow* root_window) override {
73 call_count_++;
74 is_fullscreen_ = is_fullscreen;
75 }
76
77 int call_count() const { return call_count_; }
78
79 bool is_fullscreen() const { return is_fullscreen_; }
80
81 private:
82 int call_count_;
83 bool is_fullscreen_;
84
85 DISALLOW_COPY_AND_ASSIGN(TestShellObserver);
86 };
87
88 } // namespace
89
90 using WorkspaceLayoutManagerTest = AshTest;
91
92 // Verifies that a window containing a restore coordinate will be restored to
93 // to the size prior to minimize, keeping the restore rectangle in tact (if
94 // there is one).
95 TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) {
96 std::unique_ptr<WindowOwner> window_owner(
97 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
98 WmWindow* window = window_owner->window();
99 gfx::Rect bounds(10, 15, 25, 35);
100 window->SetBounds(bounds);
101
102 wm::WindowState* window_state = window->GetWindowState();
103
104 // This will not be used for un-minimizing window.
105 window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100));
106 window_state->Minimize();
107 window_state->Restore();
108 EXPECT_EQ("0,0 100x100", window_state->GetRestoreBoundsInScreen().ToString());
109 EXPECT_EQ("10,15 25x35", window->GetBounds().ToString());
110
111 UpdateDisplay("400x300,500x400");
112 window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100), GetSecondaryDisplay());
113 EXPECT_EQ(WmShell::Get()->GetAllRootWindows()[1], window->GetRootWindow());
114 window_state->Minimize();
115 // This will not be used for un-minimizing window.
116 window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100));
117 window_state->Restore();
118 EXPECT_EQ("600,0 100x100", window->GetBoundsInScreen().ToString());
119
120 // Make sure the unminimized window moves inside the display when
121 // 2nd display is disconnected.
122 window_state->Minimize();
123 UpdateDisplay("400x300");
124 window_state->Restore();
125 EXPECT_EQ(WmShell::Get()->GetPrimaryRootWindow(), window->GetRootWindow());
126 EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects(
127 window->GetBounds()));
128 }
129
130 TEST_F(WorkspaceLayoutManagerTest, KeepMinimumVisibilityInDisplays) {
131 UpdateDisplay("300x400,400x500");
132 WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows();
133
134 if (!SetSecondaryDisplayPlacement(display::DisplayPlacement::TOP, 0))
135 return;
136
137 EXPECT_EQ("0,-500 400x500", root_windows[1]->GetBoundsInScreen().ToString());
138
139 std::unique_ptr<WindowOwner> window1_owner(
140 CreateTestWindow(gfx::Rect(10, -400, 200, 200)));
141 EXPECT_EQ("10,-400 200x200",
142 window1_owner->window()->GetBoundsInScreen().ToString());
143
144 // Make sure the caption is visible.
145 std::unique_ptr<WindowOwner> window2_owner(
146 CreateTestWindow(gfx::Rect(10, -600, 200, 200)));
147 EXPECT_EQ("10,-500 200x200",
148 window2_owner->window()->GetBoundsInScreen().ToString());
149 }
150
151 TEST_F(WorkspaceLayoutManagerTest, NoMinimumVisibilityForPopupWindows) {
152 UpdateDisplay("300x400");
153
154 // Create a popup window out of display boundaries and make sure it is not
155 // moved to have minimum visibility.
156 std::unique_ptr<WindowOwner> window_owner(
157 CreateTestWindow(gfx::Rect(400, 100, 50, 50), ui::wm::WINDOW_TYPE_POPUP));
158 EXPECT_EQ("400,100 50x50",
159 window_owner->window()->GetBoundsInScreen().ToString());
160 }
161
162 TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) {
163 std::unique_ptr<WindowOwner> window_owner(
164 CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
165 WmWindow* window = window_owner->window();
166 wm::WindowState* window_state = window->GetWindowState();
167
168 // Maximized -> Normal transition.
169 window_state->Maximize();
170 window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40));
171 window_state->Restore();
172 EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects(
173 window->GetBounds()));
174 // Y bounds should not be negative.
175 EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString());
176
177 // Minimized -> Normal transition.
178 window->SetBounds(gfx::Rect(-100, -100, 30, 40));
179 window_state->Minimize();
180 EXPECT_FALSE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects(
181 window->GetBounds()));
182 EXPECT_EQ("-100,-100 30x40", window->GetBounds().ToString());
183 window->Show();
184 EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects(
185 window->GetBounds()));
186 // Y bounds should not be negative.
187 EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString());
188
189 // Fullscreen -> Normal transition.
190 window->SetBounds(gfx::Rect(0, 0, 30, 40)); // reset bounds.
191 ASSERT_EQ("0,0 30x40", window->GetBounds().ToString());
192 window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
193 EXPECT_EQ(window->GetBounds(), window->GetRootWindow()->GetBounds());
194 window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40));
195 window_state->Restore();
196 EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects(
197 window->GetBounds()));
198 // Y bounds should not be negative.
199 EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString());
200 }
201
202 TEST_F(WorkspaceLayoutManagerTest, MaximizeInDisplayToBeRestored) {
203 UpdateDisplay("300x400,400x500");
204
205 WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows();
206
207 std::unique_ptr<WindowOwner> window_owner(
208 CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
209 WmWindow* window = window_owner->window();
210 EXPECT_EQ(root_windows[0], window->GetRootWindow());
211
212 wm::WindowState* window_state = window->GetWindowState();
213 window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40));
214 // Maximize the window in 2nd display as the restore bounds
215 // is inside 2nd display.
216 window_state->Maximize();
217 EXPECT_EQ(root_windows[1], window->GetRootWindow());
218 EXPECT_EQ(
219 gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(),
220 window->GetBoundsInScreen().ToString());
221
222 window_state->Restore();
223 EXPECT_EQ(root_windows[1], window->GetRootWindow());
224 EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString());
225
226 // If the restore bounds intersects with the current display,
227 // don't move.
228 window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40));
229 window_state->Maximize();
230 EXPECT_EQ(root_windows[1], window->GetRootWindow());
231 EXPECT_EQ(
232 gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(),
233 window->GetBoundsInScreen().ToString());
234
235 window_state->Restore();
236 EXPECT_EQ(root_windows[1], window->GetRootWindow());
237 EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString());
238
239 // Restoring widget state.
240 std::unique_ptr<views::Widget> w1(new views::Widget);
241 views::Widget::InitParams params;
242 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
243 params.delegate = new MaximizeDelegateView(gfx::Rect(400, 0, 30, 40));
244 ConfigureWidgetInitParamsForDisplay(root_windows[0], &params);
245 w1->Init(params);
246 EXPECT_EQ(root_windows[0],
247 WmWindow::Get(w1->GetNativeWindow())->GetRootWindow());
248 w1->Show();
249 EXPECT_TRUE(w1->IsMaximized());
250 EXPECT_EQ(root_windows[1],
251 WmWindow::Get(w1->GetNativeWindow())->GetRootWindow());
252 EXPECT_EQ(
253 gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(),
254 w1->GetWindowBoundsInScreen().ToString());
255 w1->Restore();
256 EXPECT_EQ(root_windows[1],
257 WmWindow::Get(w1->GetNativeWindow())->GetRootWindow());
258 EXPECT_EQ("400,0 30x40", w1->GetWindowBoundsInScreen().ToString());
259 }
260
261 TEST_F(WorkspaceLayoutManagerTest, FullscreenInDisplayToBeRestored) {
262 UpdateDisplay("300x400,400x500");
263
264 WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows();
265
266 std::unique_ptr<WindowOwner> window_owner(
267 CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
268 WmWindow* window = window_owner->window();
269 EXPECT_EQ(root_windows[0], window->GetRootWindow());
270
271 wm::WindowState* window_state = window->GetWindowState();
272 window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40));
273 // Maximize the window in 2nd display as the restore bounds
274 // is inside 2nd display.
275 window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
276 EXPECT_EQ(root_windows[1], window->GetRootWindow());
277 EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString());
278
279 window_state->Restore();
280 EXPECT_EQ(root_windows[1], window->GetRootWindow());
281 EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString());
282
283 // If the restore bounds intersects with the current display,
284 // don't move.
285 window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40));
286 window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
287 EXPECT_EQ(root_windows[1], window->GetRootWindow());
288 EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString());
289
290 window_state->Restore();
291 EXPECT_EQ(root_windows[1], window->GetRootWindow());
292 EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString());
293 }
294
295 // aura::WindowObserver implementation used by
296 // DontClobberRestoreBoundsWindowObserver. This code mirrors what
297 // BrowserFrameAsh does. In particular when this code sees the window was
298 // maximized it changes the bounds of a secondary window. The secondary window
299 // mirrors the status window.
300 class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver {
301 public:
302 DontClobberRestoreBoundsWindowObserver() : window_(nullptr) {}
303
304 void set_window(WmWindow* window) { window_ = window; }
305
306 // aura::WindowObserver:
307 void OnWindowPropertyChanged(aura::Window* window,
308 const void* key,
309 intptr_t old) override {
310 if (!window_)
311 return;
312
313 if (wm::GetWindowState(window)->IsMaximized()) {
314 WmWindow* w = window_;
315 window_ = nullptr;
316
317 gfx::Rect shelf_bounds(AshTest::GetPrimaryShelf()->GetIdealBounds());
318 const gfx::Rect& window_bounds(w->GetBounds());
319 w->SetBounds(gfx::Rect(window_bounds.x(), shelf_bounds.y() - 1,
320 window_bounds.width(), window_bounds.height()));
321 }
322 }
323
324 private:
325 WmWindow* window_;
326
327 DISALLOW_COPY_AND_ASSIGN(DontClobberRestoreBoundsWindowObserver);
328 };
329
330 // Creates a window, maximized the window and from within the maximized
331 // notification sets the bounds of a window to overlap the shelf. Verifies this
332 // doesn't effect the restore bounds.
333 TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) {
334 DontClobberRestoreBoundsWindowObserver window_observer;
335 WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL,
336 ui::LAYER_TEXTURED));
337 WmWindow* window = window_owner.window();
338 window->SetBounds(gfx::Rect(10, 20, 30, 40));
339 // NOTE: for this test to exercise the failure the observer needs to be added
340 // before the parent set. This mimics what BrowserFrameAsh does.
341 window->aura_window()->AddObserver(&window_observer);
342 ParentWindowInPrimaryRootWindow(window);
343 window->Show();
344
345 wm::WindowState* window_state = window->GetWindowState();
346 window_state->Activate();
347
348 std::unique_ptr<WindowOwner> window2_owner(
349 CreateTestWindow(gfx::Rect(12, 20, 30, 40)));
350 WmWindow* window2 = window2_owner->window();
351 AddTransientChild(window, window2);
352 window2->Show();
353
354 window_observer.set_window(window2);
355 window_state->Maximize();
356 EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInScreen().ToString());
357 window->aura_window()->RemoveObserver(&window_observer);
358 }
359
360 // Verifies when a window is maximized all descendant windows have a size.
361 TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) {
362 std::unique_ptr<WindowOwner> window_owner(
363 CreateTestWindow(gfx::Rect(10, 20, 30, 40)));
364 WmWindow* window = window_owner->window();
365 window->Show();
366 wm::WindowState* window_state = window->GetWindowState();
367 window_state->Activate();
368 std::unique_ptr<WindowOwner> child_window_owner(
369 CreateChildWindow(window, gfx::Rect(5, 6, 7, 8)));
370 WmWindow* child_window = child_window_owner->window();
371 window_state->Maximize();
372 EXPECT_EQ("5,6 7x8", child_window->GetBounds().ToString());
373 }
374
375 // Verifies a window created with maximized state has the maximized
376 // bounds.
377 TEST_F(WorkspaceLayoutManagerTest, MaximizeWithEmptySize) {
378 WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL,
379 ui::LAYER_TEXTURED));
380 WmWindow* window = window_owner.window();
381 window->GetWindowState()->Maximize();
382 WmWindow* default_container =
383 WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer(
384 kShellWindowId_DefaultContainer);
385 default_container->AddChild(window);
386 window->Show();
387 gfx::Rect work_area(
388 display::Screen::GetScreen()->GetPrimaryDisplay().work_area());
389 EXPECT_EQ(work_area.ToString(), window->GetBoundsInScreen().ToString());
390 }
391
392 TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) {
393 // TODO: fix. This test verifies that when a window is added the bounds are
394 // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes
395 // from NativeWidgetAura), which means this test now fails for aura-mus.
396 if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS)
397 return;
398
399 // Normal window bounds shouldn't be changed.
400 gfx::Rect window_bounds(100, 100, 200, 200);
401 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds));
402 WmWindow* window = window_owner->window();
403 EXPECT_EQ(window_bounds, window->GetBounds());
404
405 // If the window is out of the workspace, it would be moved on screen.
406 gfx::Rect root_window_bounds =
407 WmShell::Get()->GetPrimaryRootWindow()->GetBounds();
408 window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height());
409 ASSERT_FALSE(window_bounds.Intersects(root_window_bounds));
410 std::unique_ptr<WindowOwner> out_window_owner(
411 CreateTestWindow(window_bounds));
412 WmWindow* out_window = out_window_owner->window();
413 EXPECT_EQ(window_bounds.size(), out_window->GetBounds().size());
414 gfx::Rect bounds = out_window->GetBounds();
415 bounds.Intersect(root_window_bounds);
416
417 // 30% of the window edge must be visible.
418 EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29);
419 EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29);
420
421 WmWindow* parent = out_window->GetParent();
422 parent->RemoveChild(out_window);
423 out_window->SetBounds(gfx::Rect(-200, -200, 200, 200));
424 // UserHasChangedWindowPositionOrSize flag shouldn't turn off this behavior.
425 window->GetWindowState()->set_bounds_changed_by_user(true);
426 parent->AddChild(out_window);
427 EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29);
428 EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29);
429
430 // Make sure we always make more than 1/3 of the window edge visible even
431 // if the initial bounds intersects with display.
432 window_bounds.SetRect(-150, -150, 200, 200);
433 bounds = window_bounds;
434 bounds.Intersect(root_window_bounds);
435
436 // Make sure that the initial bounds' visible area is less than 26%
437 // so that the auto adjustment logic kicks in.
438 ASSERT_LT(bounds.width(), out_window->GetBounds().width() * 0.26);
439 ASSERT_LT(bounds.height(), out_window->GetBounds().height() * 0.26);
440 ASSERT_TRUE(window_bounds.Intersects(root_window_bounds));
441
442 std::unique_ptr<WindowOwner> partially_out_window_owner(
443 CreateTestWindow(window_bounds));
444 WmWindow* partially_out_window = partially_out_window_owner->window();
445 EXPECT_EQ(window_bounds.size(), partially_out_window->GetBounds().size());
446 bounds = partially_out_window->GetBounds();
447 bounds.Intersect(root_window_bounds);
448 EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29);
449 EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29);
450
451 // Make sure the window whose 30% width/height is bigger than display
452 // will be placed correctly.
453 window_bounds.SetRect(-1900, -1900, 3000, 3000);
454 std::unique_ptr<WindowOwner> window_bigger_than_display_owner(
455 CreateTestWindow(window_bounds));
456 WmWindow* window_bigger_than_display =
457 window_bigger_than_display_owner->window();
458 EXPECT_GE(root_window_bounds.width(),
459 window_bigger_than_display->GetBounds().width());
460 EXPECT_GE(root_window_bounds.height(),
461 window_bigger_than_display->GetBounds().height());
462
463 bounds = window_bigger_than_display->GetBounds();
464 bounds.Intersect(root_window_bounds);
465 EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29);
466 EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29);
467 }
468
469 // Verifies the size of a window is enforced to be smaller than the work area.
470 TEST_F(WorkspaceLayoutManagerTest, SizeToWorkArea) {
471 // Normal window bounds shouldn't be changed.
472 gfx::Size work_area(
473 display::Screen::GetScreen()->GetPrimaryDisplay().work_area().size());
474 const gfx::Rect window_bounds(100, 101, work_area.width() + 1,
475 work_area.height() + 2);
476 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds));
477 WmWindow* window = window_owner->window();
478 // TODO: fix. This test verifies that when a window is added the bounds are
479 // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes
480 // from NativeWidgetAura), which means this test now fails for aura-mus.
481 if (aura::Env::GetInstance()->mode() != aura::Env::Mode::MUS) {
482 EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(),
483 window->GetBounds().ToString());
484 }
485
486 // Directly setting the bounds triggers a slightly different code path. Verify
487 // that too.
488 window->SetBounds(window_bounds);
489 EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(),
490 window->GetBounds().ToString());
491 }
492
493 TEST_F(WorkspaceLayoutManagerTest, NotifyFullscreenChanges) {
494 TestShellObserver observer;
495 std::unique_ptr<WindowOwner> window1_owner(
496 CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
497 WmWindow* window1 = window1_owner->window();
498 std::unique_ptr<WindowOwner> window2_owner(
499 CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
500 WmWindow* window2 = window2_owner->window();
501 wm::WindowState* window_state1 = window1->GetWindowState();
502 wm::WindowState* window_state2 = window2->GetWindowState();
503 window_state2->Activate();
504
505 const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
506 window_state2->OnWMEvent(&toggle_fullscreen_event);
507 EXPECT_EQ(1, observer.call_count());
508 EXPECT_TRUE(observer.is_fullscreen());
509
510 // When window1 moves to the front the fullscreen state should change.
511 window_state1->Activate();
512 EXPECT_EQ(2, observer.call_count());
513 EXPECT_FALSE(observer.is_fullscreen());
514
515 // It should change back if window2 becomes active again.
516 window_state2->Activate();
517 EXPECT_EQ(3, observer.call_count());
518 EXPECT_TRUE(observer.is_fullscreen());
519
520 window_state2->OnWMEvent(&toggle_fullscreen_event);
521 EXPECT_EQ(4, observer.call_count());
522 EXPECT_FALSE(observer.is_fullscreen());
523
524 window_state2->OnWMEvent(&toggle_fullscreen_event);
525 EXPECT_EQ(5, observer.call_count());
526 EXPECT_TRUE(observer.is_fullscreen());
527
528 // Closing the window should change the fullscreen state.
529 window2_owner.reset();
530 EXPECT_EQ(6, observer.call_count());
531 EXPECT_FALSE(observer.is_fullscreen());
532 }
533
534 // For crbug.com/673803, snapped window may not adjust snapped bounds on work
535 // area changed properly if window's layer is doing animation. We should use
536 // GetTargetBounds to check if snapped bounds need to be changed.
537 TEST_F(WorkspaceLayoutManagerTest,
538 SnappedWindowMayNotAdjustBoundsOnWorkAreaChanged) {
539 UpdateDisplay("300x400");
540 std::unique_ptr<WindowOwner> window_owner(
541 CreateTestWindow(gfx::Rect(10, 20, 100, 200)));
542 WmWindow* window = window_owner->window();
543 wm::WindowState* window_state = window->GetWindowState();
544 gfx::Insets insets(0, 0, 50, 0);
545 WmShell::Get()->SetDisplayWorkAreaInsets(window, insets);
546 const wm::WMEvent snap_left(wm::WM_EVENT_SNAP_LEFT);
547 window_state->OnWMEvent(&snap_left);
548 EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
549 const gfx::Rect kWorkAreaBounds =
550 display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
551 gfx::Rect expected_bounds =
552 gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(),
553 kWorkAreaBounds.width() / 2, kWorkAreaBounds.height());
554 EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
555
556 ui::ScopedAnimationDurationScaleMode test_duration_mode(
557 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
558 // The following two SetDisplayWorkAreaInsets calls simulate the case of
559 // crbug.com/673803 that work area first becomes fullscreen and then returns
560 // to the original state.
561 WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(0, 0, 0, 0));
562 ui::LayerAnimator* animator = window->GetLayer()->GetAnimator();
563 EXPECT_TRUE(animator->is_animating());
564 WmShell::Get()->SetDisplayWorkAreaInsets(window, insets);
565 animator->StopAnimating();
566 EXPECT_FALSE(animator->is_animating());
567 EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
568 }
569
570 // Do not adjust window bounds to ensure minimum visibility for transient
571 // windows (crbug.com/624806).
572 TEST_F(WorkspaceLayoutManagerTest,
573 DoNotAdjustTransientWindowBoundsToEnsureMinimumVisibility) {
574 UpdateDisplay("300x400");
575 WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL,
576 ui::LAYER_TEXTURED));
577 WmWindow* window = window_owner.window();
578 window->SetBounds(gfx::Rect(10, 0, 100, 200));
579 ParentWindowInPrimaryRootWindow(window);
580 window->Show();
581
582 std::unique_ptr<WindowOwner> window2_owner(
583 CreateTestWindow(gfx::Rect(10, 0, 40, 20)));
584 WmWindow* window2 = window2_owner->window();
585 AddTransientChild(window, window2);
586 window2->Show();
587
588 gfx::Rect expected_bounds = window2->GetBounds();
589 WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(50, 0, 0, 0));
590 EXPECT_EQ(expected_bounds.ToString(), window2->GetBounds().ToString());
591 }
592
593 // Following "Solo" tests were originally written for BaseLayoutManager.
594 using WorkspaceLayoutManagerSoloTest = AshTest;
595
596 // Tests normal->maximize->normal.
597 TEST_F(WorkspaceLayoutManagerSoloTest, Maximize) {
598 gfx::Rect bounds(100, 100, 200, 200);
599 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds));
600 WmWindow* window = window_owner->window();
601 window->SetShowState(ui::SHOW_STATE_MAXIMIZED);
602 // Maximized window fills the work area, not the whole display.
603 EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(),
604 window->GetBounds().ToString());
605 window->SetShowState(ui::SHOW_STATE_NORMAL);
606 EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString());
607 }
608
609 // Tests normal->minimize->normal.
610 TEST_F(WorkspaceLayoutManagerSoloTest, Minimize) {
611 gfx::Rect bounds(100, 100, 200, 200);
612 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds));
613 WmWindow* window = window_owner->window();
614 window->SetShowState(ui::SHOW_STATE_MINIMIZED);
615 EXPECT_FALSE(window->IsVisible());
616 EXPECT_TRUE(window->GetWindowState()->IsMinimized());
617 EXPECT_EQ(bounds, window->GetBounds());
618 window->SetShowState(ui::SHOW_STATE_NORMAL);
619 EXPECT_TRUE(window->IsVisible());
620 EXPECT_FALSE(window->GetWindowState()->IsMinimized());
621 EXPECT_EQ(bounds, window->GetBounds());
622 }
623
624 // A aura::WindowObserver which sets the focus when the window becomes visible.
625 class FocusDuringUnminimizeWindowObserver : public aura::WindowObserver {
626 public:
627 FocusDuringUnminimizeWindowObserver()
628 : window_(nullptr), show_state_(ui::SHOW_STATE_END) {}
629 ~FocusDuringUnminimizeWindowObserver() override { SetWindow(nullptr); }
630
631 void SetWindow(WmWindow* window) {
632 if (window_)
633 window_->aura_window()->RemoveObserver(this);
634 window_ = window;
635 if (window_)
636 window_->aura_window()->AddObserver(this);
637 }
638
639 // aura::WindowObserver:
640 void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
641 if (window_) {
642 if (visible)
643 window_->SetFocused();
644 show_state_ = window_->GetShowState();
645 }
646 }
647
648 ui::WindowShowState GetShowStateAndReset() {
649 ui::WindowShowState ret = show_state_;
650 show_state_ = ui::SHOW_STATE_END;
651 return ret;
652 }
653
654 private:
655 WmWindow* window_;
656 ui::WindowShowState show_state_;
657
658 DISALLOW_COPY_AND_ASSIGN(FocusDuringUnminimizeWindowObserver);
659 };
660
661 // Make sure that the window's show state is correct in
662 // WindowObserver::OnWindowTargetVisibilityChanged(), and setting focus in this
663 // callback doesn't cause DCHECK error. See crbug.com/168383.
664 TEST_F(WorkspaceLayoutManagerSoloTest, FocusDuringUnminimize) {
665 FocusDuringUnminimizeWindowObserver observer;
666 std::unique_ptr<WindowOwner> window_owner(
667 CreateTestWindow(gfx::Rect(100, 100, 100, 100)));
668 WmWindow* window = window_owner->window();
669 observer.SetWindow(window);
670 window->SetShowState(ui::SHOW_STATE_MINIMIZED);
671 EXPECT_FALSE(window->IsVisible());
672 EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, observer.GetShowStateAndReset());
673 window->Show();
674 EXPECT_TRUE(window->IsVisible());
675 EXPECT_EQ(ui::SHOW_STATE_NORMAL, observer.GetShowStateAndReset());
676 observer.SetWindow(nullptr);
677 }
678
679 // Tests maximized window size during root window resize.
680 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeRootWindowResize) {
681 gfx::Rect bounds(100, 100, 200, 200);
682 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds));
683 WmWindow* window = window_owner->window();
684 window->SetShowState(ui::SHOW_STATE_MAXIMIZED);
685 gfx::Rect initial_work_area_bounds =
686 wm::GetMaximizedWindowBoundsInParent(window);
687 EXPECT_EQ(initial_work_area_bounds.ToString(),
688 window->GetBounds().ToString());
689 // Enlarge the root window. We should still match the work area size.
690 UpdateDisplay("900x700");
691 EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(),
692 window->GetBounds().ToString());
693 EXPECT_NE(initial_work_area_bounds.ToString(),
694 wm::GetMaximizedWindowBoundsInParent(window).ToString());
695 }
696
697 // Tests normal->fullscreen->normal.
698 TEST_F(WorkspaceLayoutManagerSoloTest, Fullscreen) {
699 gfx::Rect bounds(100, 100, 200, 200);
700 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds));
701 WmWindow* window = window_owner->window();
702 window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
703 // Fullscreen window fills the whole display.
704 EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(),
705 window->GetBounds().ToString());
706 window->SetShowState(ui::SHOW_STATE_NORMAL);
707 EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString());
708 }
709
710 // Tests that fullscreen window causes always_on_top windows to stack below.
711 TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenSuspendsAlwaysOnTop) {
712 gfx::Rect bounds(100, 100, 200, 200);
713 std::unique_ptr<WindowOwner> fullscreen_window_owner(
714 CreateTestWindow(bounds));
715 WmWindow* fullscreen_window = fullscreen_window_owner->window();
716 std::unique_ptr<WindowOwner> always_on_top_window1_owner(
717 CreateTestWindow(bounds));
718 WmWindow* always_on_top_window1 = always_on_top_window1_owner->window();
719 std::unique_ptr<WindowOwner> always_on_top_window2_owner(
720 CreateTestWindow(bounds));
721 WmWindow* always_on_top_window2 = always_on_top_window2_owner->window();
722 always_on_top_window1->SetAlwaysOnTop(true);
723 always_on_top_window2->SetAlwaysOnTop(true);
724 // Making a window fullscreen temporarily suspends always on top state.
725 fullscreen_window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
726 EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop());
727 EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop());
728 EXPECT_NE(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window));
729
730 // Adding a new always-on-top window is not affected by fullscreen.
731 std::unique_ptr<WindowOwner> always_on_top_window3_owner(
732 CreateTestWindow(bounds));
733 WmWindow* always_on_top_window3 = always_on_top_window3_owner->window();
734 always_on_top_window3->SetAlwaysOnTop(true);
735 EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop());
736
737 // Making fullscreen window normal restores always on top windows.
738 fullscreen_window->SetShowState(ui::SHOW_STATE_NORMAL);
739 EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop());
740 EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop());
741 EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop());
742 EXPECT_EQ(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window));
743 }
744
745 // Similary, pinned window causes always_on_top_ windows to stack below.
746 TEST_F(WorkspaceLayoutManagerSoloTest, PinnedSuspendsAlwaysOnTop) {
747 // TODO: mash doesn't support pinning yet http://crbug.com/622486.
748 if (WmShell::Get()->IsRunningInMash())
749 return;
750
751 gfx::Rect bounds(100, 100, 200, 200);
752 std::unique_ptr<WindowOwner> pinned_window_owner(CreateTestWindow(bounds));
753 WmWindow* pinned_window = pinned_window_owner->window();
754 std::unique_ptr<WindowOwner> always_on_top_window1_owner(
755 CreateTestWindow(bounds));
756 WmWindow* always_on_top_window1 = always_on_top_window1_owner->window();
757 std::unique_ptr<WindowOwner> always_on_top_window2_owner(
758 CreateTestWindow(bounds));
759 WmWindow* always_on_top_window2 = always_on_top_window2_owner->window();
760 always_on_top_window1->SetAlwaysOnTop(true);
761 always_on_top_window2->SetAlwaysOnTop(true);
762
763 // Making a window pinned temporarily suspends always on top state.
764 const bool trusted = false;
765 pinned_window->SetPinned(trusted);
766 EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop());
767 EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop());
768
769 // Adding a new always-on-top window also is affected by pinned mode.
770 std::unique_ptr<WindowOwner> always_on_top_window3_owner(
771 CreateTestWindow(bounds));
772 WmWindow* always_on_top_window3 = always_on_top_window3_owner->window();
773 always_on_top_window3->SetAlwaysOnTop(true);
774 EXPECT_FALSE(always_on_top_window3->IsAlwaysOnTop());
775
776 // Making pinned window normal restores always on top windows.
777 pinned_window->GetWindowState()->Restore();
778 EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop());
779 EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop());
780 EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop());
781 }
782
783 // Tests fullscreen window size during root window resize.
784 TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenRootWindowResize) {
785 gfx::Rect bounds(100, 100, 200, 200);
786 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds));
787 WmWindow* window = window_owner->window();
788 // Fullscreen window fills the whole display.
789 window->SetShowState(ui::SHOW_STATE_FULLSCREEN);
790 EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(),
791 window->GetBounds().ToString());
792 // Enlarge the root window. We should still match the display size.
793 UpdateDisplay("800x600");
794 EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(),
795 window->GetBounds().ToString());
796 }
797
798 // Tests that when the screen gets smaller the windows aren't bigger than
799 // the screen.
800 TEST_F(WorkspaceLayoutManagerSoloTest, RootWindowResizeShrinksWindows) {
801 std::unique_ptr<WindowOwner> window_owner(
802 CreateTestWindow(gfx::Rect(10, 20, 500, 400)));
803 WmWindow* window = window_owner->window();
804 gfx::Rect work_area = window->GetDisplayNearestWindow().work_area();
805 // Invariant: Window is smaller than work area.
806 EXPECT_LE(window->GetBounds().width(), work_area.width());
807 EXPECT_LE(window->GetBounds().height(), work_area.height());
808
809 // Make the root window narrower than our window.
810 UpdateDisplay("300x400");
811 work_area = window->GetDisplayNearestWindow().work_area();
812 EXPECT_LE(window->GetBounds().width(), work_area.width());
813 EXPECT_LE(window->GetBounds().height(), work_area.height());
814
815 // Make the root window shorter than our window.
816 UpdateDisplay("300x200");
817 work_area = window->GetDisplayNearestWindow().work_area();
818 EXPECT_LE(window->GetBounds().width(), work_area.width());
819 EXPECT_LE(window->GetBounds().height(), work_area.height());
820
821 // Enlarging the root window does not change the window bounds.
822 gfx::Rect old_bounds = window->GetBounds();
823 UpdateDisplay("800x600");
824 EXPECT_EQ(old_bounds.width(), window->GetBounds().width());
825 EXPECT_EQ(old_bounds.height(), window->GetBounds().height());
826 }
827
828 // Verifies maximizing sets the restore bounds, and restoring
829 // restores the bounds.
830 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeSetsRestoreBounds) {
831 const gfx::Rect initial_bounds(10, 20, 30, 40);
832 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(initial_bounds));
833 WmWindow* window = window_owner->window();
834 EXPECT_EQ(initial_bounds, window->GetBounds());
835 wm::WindowState* window_state = window->GetWindowState();
836
837 // Maximize it, which will keep the previous restore bounds.
838 window->SetShowState(ui::SHOW_STATE_MAXIMIZED);
839 EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInParent().ToString());
840
841 // Restore it, which should restore bounds and reset restore bounds.
842 window->SetShowState(ui::SHOW_STATE_NORMAL);
843 EXPECT_EQ("10,20 30x40", window->GetBounds().ToString());
844 EXPECT_FALSE(window_state->HasRestoreBounds());
845 }
846
847 // Verifies maximizing keeps the restore bounds if set.
848 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeResetsRestoreBounds) {
849 std::unique_ptr<WindowOwner> window_owner(
850 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
851 WmWindow* window = window_owner->window();
852 wm::WindowState* window_state = window->GetWindowState();
853 window_state->SetRestoreBoundsInParent(gfx::Rect(10, 11, 12, 13));
854
855 // Maximize it, which will keep the previous restore bounds.
856 window->SetShowState(ui::SHOW_STATE_MAXIMIZED);
857 EXPECT_EQ("10,11 12x13", window_state->GetRestoreBoundsInParent().ToString());
858 }
859
860 // Verifies that the restore bounds do not get reset when restoring to a
861 // maximzied state from a minimized state.
862 TEST_F(WorkspaceLayoutManagerSoloTest,
863 BoundsAfterRestoringToMaximizeFromMinimize) {
864 std::unique_ptr<WindowOwner> window_owner(
865 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
866 WmWindow* window = window_owner->window();
867 gfx::Rect bounds(10, 15, 25, 35);
868 window->SetBounds(bounds);
869
870 wm::WindowState* window_state = window->GetWindowState();
871 // Maximize it, which should reset restore bounds.
872 window_state->Maximize();
873 EXPECT_EQ(bounds.ToString(),
874 window_state->GetRestoreBoundsInParent().ToString());
875 // Minimize the window. The restore bounds should not change.
876 window_state->Minimize();
877 EXPECT_EQ(bounds.ToString(),
878 window_state->GetRestoreBoundsInParent().ToString());
879
880 // Show the window again. The window should be maximized, and the restore
881 // bounds should not change.
882 window->Show();
883 EXPECT_EQ(bounds.ToString(),
884 window_state->GetRestoreBoundsInParent().ToString());
885 EXPECT_TRUE(window_state->IsMaximized());
886
887 window_state->Restore();
888 EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString());
889 }
890
891 // Verify if the window is not resized during screen lock. See: crbug.com/173127
892 TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) {
893 test::TestSessionStateDelegate::SetCanLockScreen(true);
894 std::unique_ptr<WindowOwner> window_owner(
895 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
896 WmWindow* window = window_owner->window();
897 // window with AlwaysOnTop will be managed by BaseLayoutManager.
898 window->SetAlwaysOnTop(true);
899 window->Show();
900
901 WmShelf* shelf = GetPrimaryShelf();
902 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
903
904 window->SetBounds(wm::GetMaximizedWindowBoundsInParent(window));
905 gfx::Rect window_bounds = window->GetBounds();
906 EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(),
907 window_bounds.ToString());
908
909 // The window size should not get touched while we are in lock screen.
910 WmShell::Get()->GetSessionStateDelegate()->LockScreen();
911 ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager();
912 shelf_layout_manager->UpdateVisibilityState();
913 EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString());
914
915 // Coming out of the lock screen the window size should still remain.
916 WmShell::Get()->GetSessionStateDelegate()->UnlockScreen();
917 shelf_layout_manager->UpdateVisibilityState();
918 EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(),
919 window_bounds.ToString());
920 EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString());
921 }
922
923 // Following tests are written to test the backdrop functionality.
924
925 namespace {
926
927 WorkspaceLayoutManager* GetWorkspaceLayoutManager(WmWindow* container) {
928 return static_cast<WorkspaceLayoutManager*>(container->GetLayoutManager());
929 }
930
931 class WorkspaceLayoutManagerBackdropTest : public AshTest {
932 public:
933 WorkspaceLayoutManagerBackdropTest() : default_container_(nullptr) {}
934 ~WorkspaceLayoutManagerBackdropTest() override {}
935
936 void SetUp() override {
937 AshTest::SetUp();
938 UpdateDisplay("800x600");
939 default_container_ =
940 WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer(
941 kShellWindowId_DefaultContainer);
942 }
943
944 // Turn the top window back drop on / off.
945 void ShowTopWindowBackdrop(bool show) {
946 std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> backdrop;
947 if (show)
948 backdrop.reset(new WorkspaceBackdropDelegate(default_container_));
949 GetWorkspaceLayoutManager(default_container_)
950 ->SetMaximizeBackdropDelegate(std::move(backdrop));
951 // Closing and / or opening can be a delayed operation.
952 base::RunLoop().RunUntilIdle();
953 }
954
955 // Return the default container.
956 WmWindow* default_container() { return default_container_; }
957
958 // Return the order of windows (top most first) as they are in the default
959 // container. If the window is visible it will be a big letter, otherwise a
960 // small one. The backdrop will be an X and unknown windows will be shown as
961 // '!'.
962 std::string GetWindowOrderAsString(WmWindow* backdrop,
963 WmWindow* wa,
964 WmWindow* wb,
965 WmWindow* wc) {
966 std::string result;
967 WmWindow::Windows children = default_container()->GetChildren();
968 for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) {
969 if (!result.empty())
970 result += ",";
971 if (children[i] == wa)
972 result += children[i]->IsVisible() ? "A" : "a";
973 else if (children[i] == wb)
974 result += children[i]->IsVisible() ? "B" : "b";
975 else if (children[i] == wc)
976 result += children[i]->IsVisible() ? "C" : "c";
977 else if (children[i] == backdrop)
978 result += children[i]->IsVisible() ? "X" : "x";
979 else
980 result += "!";
981 }
982 return result;
983 }
984
985 private:
986 // The default container.
987 WmWindow* default_container_;
988
989 DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerBackdropTest);
990 };
991
992 } // namespace
993
994 // Check that creating the BackDrop without destroying it does not lead into
995 // a crash.
996 TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) {
997 ShowTopWindowBackdrop(true);
998 }
999
1000 // Verify basic assumptions about the backdrop.
1001 TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) {
1002 // Create a backdrop and see that there is one window (the backdrop) and
1003 // that the size is the same as the default container as well as that it is
1004 // not visible.
1005 ShowTopWindowBackdrop(true);
1006 ASSERT_EQ(1U, default_container()->GetChildren().size());
1007 EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible());
1008
1009 {
1010 // Add a window and make sure that the backdrop is the second child.
1011 std::unique_ptr<WindowOwner> window_owner(
1012 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
1013 WmWindow* window = window_owner->window();
1014 window->Show();
1015 ASSERT_EQ(2U, default_container()->GetChildren().size());
1016 EXPECT_TRUE(default_container()->GetChildren()[0]->IsVisible());
1017 EXPECT_TRUE(default_container()->GetChildren()[1]->IsVisible());
1018 EXPECT_EQ(window, default_container()->GetChildren()[1]);
1019 EXPECT_EQ(default_container()->GetBounds().ToString(),
1020 default_container()->GetChildren()[0]->GetBounds().ToString());
1021 }
1022
1023 // With the window gone the backdrop should be invisible again.
1024 ASSERT_EQ(1U, default_container()->GetChildren().size());
1025 EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible());
1026
1027 // Destroying the Backdrop should empty the container.
1028 ShowTopWindowBackdrop(false);
1029 ASSERT_EQ(0U, default_container()->GetChildren().size());
1030 }
1031
1032 // Verify that the backdrop gets properly created and placed.
1033 TEST_F(WorkspaceLayoutManagerBackdropTest, VerifyBackdropAndItsStacking) {
1034 std::unique_ptr<WindowOwner> window1_owner(
1035 CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
1036 WmWindow* window1 = window1_owner->window();
1037 window1->Show();
1038
1039 // Get the default container and check that only a single window is in there.
1040 ASSERT_EQ(1U, default_container()->GetChildren().size());
1041 EXPECT_EQ(window1, default_container()->GetChildren()[0]);
1042 EXPECT_EQ("A", GetWindowOrderAsString(nullptr, window1, nullptr, nullptr));
1043
1044 // Create 2 more windows and check that they are also in the container.
1045 std::unique_ptr<WindowOwner> window2_owner(
1046 CreateTestWindow(gfx::Rect(10, 2, 3, 4)));
1047 WmWindow* window2 = window2_owner->window();
1048 std::unique_ptr<WindowOwner> window3_owner(
1049 CreateTestWindow(gfx::Rect(20, 2, 3, 4)));
1050 WmWindow* window3 = window3_owner->window();
1051 window2->Show();
1052 window3->Show();
1053
1054 WmWindow* backdrop = nullptr;
1055 EXPECT_EQ("C,B,A",
1056 GetWindowOrderAsString(backdrop, window1, window2, window3));
1057
1058 // Turn on the backdrop mode and check that the window shows up where it
1059 // should be (second highest number).
1060 ShowTopWindowBackdrop(true);
1061 backdrop = default_container()->GetChildren()[2];
1062 EXPECT_EQ("C,X,B,A",
1063 GetWindowOrderAsString(backdrop, window1, window2, window3));
1064
1065 // Switch the order of windows and check that it still remains in that
1066 // location.
1067 default_container()->StackChildAtTop(window2);
1068 EXPECT_EQ("B,X,C,A",
1069 GetWindowOrderAsString(backdrop, window1, window2, window3));
1070
1071 // Make the top window invisible and check.
1072 window2->Hide();
1073 EXPECT_EQ("b,C,X,A",
1074 GetWindowOrderAsString(backdrop, window1, window2, window3));
1075 // Then delete window after window and see that everything is in order.
1076 window1_owner.reset();
1077 EXPECT_EQ("b,C,X",
1078 GetWindowOrderAsString(backdrop, window1, window2, window3));
1079 window3_owner.reset();
1080 EXPECT_EQ("b,x", GetWindowOrderAsString(backdrop, window1, window2, window3));
1081 ShowTopWindowBackdrop(false);
1082 EXPECT_EQ("b", GetWindowOrderAsString(nullptr, window1, window2, window3));
1083 }
1084
1085 // Tests that when hidding the shelf, that the backdrop resizes to fill the
1086 // entire workspace area.
1087 TEST_F(WorkspaceLayoutManagerBackdropTest, ShelfVisibilityChangesBounds) {
1088 WmShelf* shelf = GetPrimaryShelf();
1089 ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager();
1090 ShowTopWindowBackdrop(true);
1091 RunAllPendingInMessageLoop();
1092
1093 ASSERT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
1094 gfx::Rect initial_bounds = default_container()->GetChildren()[0]->GetBounds();
1095 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1096 shelf_layout_manager->UpdateVisibilityState();
1097
1098 // When the shelf is re-shown WorkspaceLayoutManager shrinks all children
1099 // including the backdrop.
1100 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
1101 shelf_layout_manager->UpdateVisibilityState();
1102 gfx::Rect reduced_bounds = default_container()->GetChildren()[0]->GetBounds();
1103 EXPECT_LT(reduced_bounds.height(), initial_bounds.height());
1104
1105 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1106 shelf_layout_manager->UpdateVisibilityState();
1107
1108 EXPECT_GT(default_container()->GetChildren()[0]->GetBounds().height(),
1109 reduced_bounds.height());
1110 }
1111
1112 class WorkspaceLayoutManagerKeyboardTest : public AshTest {
1113 public:
1114 WorkspaceLayoutManagerKeyboardTest() : layout_manager_(nullptr) {}
1115 ~WorkspaceLayoutManagerKeyboardTest() override {}
1116
1117 void SetUp() override {
1118 AshTest::SetUp();
1119 UpdateDisplay("800x600");
1120 WmWindow* default_container =
1121 WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer(
1122 kShellWindowId_DefaultContainer);
1123 layout_manager_ = GetWorkspaceLayoutManager(default_container);
1124 }
1125
1126 void ShowKeyboard() {
1127 layout_manager_->OnKeyboardBoundsChanging(keyboard_bounds_);
1128 restore_work_area_insets_ =
1129 display::Screen::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets();
1130 WmShell::Get()->SetDisplayWorkAreaInsets(
1131 WmShell::Get()->GetPrimaryRootWindow(),
1132 gfx::Insets(0, 0, keyboard_bounds_.height(), 0));
1133 }
1134
1135 void HideKeyboard() {
1136 WmShell::Get()->SetDisplayWorkAreaInsets(
1137 WmShell::Get()->GetPrimaryRootWindow(), restore_work_area_insets_);
1138 layout_manager_->OnKeyboardBoundsChanging(gfx::Rect());
1139 }
1140
1141 // Initializes the keyboard bounds using the bottom half of the work area.
1142 void InitKeyboardBounds() {
1143 gfx::Rect work_area(
1144 display::Screen::GetScreen()->GetPrimaryDisplay().work_area());
1145 keyboard_bounds_.SetRect(work_area.x(),
1146 work_area.y() + work_area.height() / 2,
1147 work_area.width(), work_area.height() / 2);
1148 }
1149
1150 void EnableNewVKMode() {
1151 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1152 if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior))
1153 command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior);
1154 }
1155
1156 const gfx::Rect& keyboard_bounds() const { return keyboard_bounds_; }
1157
1158 private:
1159 gfx::Insets restore_work_area_insets_;
1160 gfx::Rect keyboard_bounds_;
1161 WorkspaceLayoutManager* layout_manager_;
1162
1163 DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerKeyboardTest);
1164 };
1165
1166 // Tests that when a child window gains focus the top level window containing it
1167 // is resized to fit the remaining workspace area.
1168 TEST_F(WorkspaceLayoutManagerKeyboardTest, ChildWindowFocused) {
1169 InitKeyboardBounds();
1170
1171 gfx::Rect work_area(
1172 display::Screen::GetScreen()->GetPrimaryDisplay().work_area());
1173
1174 std::unique_ptr<WindowOwner> parent_window_owner(
1175 CreateToplevelTestWindow(work_area));
1176 WmWindow* parent_window = parent_window_owner->window();
1177 std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(work_area));
1178 WmWindow* window = window_owner->window();
1179 parent_window->AddChild(window);
1180
1181 window->Activate();
1182
1183 int available_height =
1184 display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() -
1185 keyboard_bounds().height();
1186
1187 gfx::Rect initial_window_bounds(50, 50, 100, 500);
1188 parent_window->SetBounds(initial_window_bounds);
1189 EXPECT_EQ(initial_window_bounds.ToString(),
1190 parent_window->GetBounds().ToString());
1191 ShowKeyboard();
1192 EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(),
1193 parent_window->GetBounds().ToString());
1194 HideKeyboard();
1195 EXPECT_EQ(initial_window_bounds.ToString(),
1196 parent_window->GetBounds().ToString());
1197 }
1198
1199 TEST_F(WorkspaceLayoutManagerKeyboardTest, AdjustWindowForA11yKeyboard) {
1200 InitKeyboardBounds();
1201 gfx::Rect work_area(
1202 display::Screen::GetScreen()->GetPrimaryDisplay().work_area());
1203
1204 std::unique_ptr<WindowOwner> window_owner(
1205 CreateToplevelTestWindow(work_area));
1206 WmWindow* window = window_owner->window();
1207 // The additional SetBounds() is needed as the aura-mus case uses Widget,
1208 // which alters the supplied bounds.
1209 window->SetBounds(work_area);
1210
1211 int available_height =
1212 display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() -
1213 keyboard_bounds().height();
1214
1215 window->Activate();
1216
1217 EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString());
1218 ShowKeyboard();
1219 EXPECT_EQ(gfx::Rect(work_area.origin(),
1220 gfx::Size(work_area.width(), available_height))
1221 .ToString(),
1222 window->GetBounds().ToString());
1223 HideKeyboard();
1224 EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString());
1225
1226 gfx::Rect small_window_bound(50, 50, 100, 500);
1227 window->SetBounds(small_window_bound);
1228 EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString());
1229 ShowKeyboard();
1230 EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(),
1231 window->GetBounds().ToString());
1232 HideKeyboard();
1233 EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString());
1234
1235 gfx::Rect occluded_window_bounds(
1236 50, keyboard_bounds().y() + keyboard_bounds().height() / 2, 50,
1237 keyboard_bounds().height() / 2);
1238 window->SetBounds(occluded_window_bounds);
1239 EXPECT_EQ(occluded_window_bounds.ToString(),
1240 occluded_window_bounds.ToString());
1241 ShowKeyboard();
1242 EXPECT_EQ(
1243 gfx::Rect(50, keyboard_bounds().y() - keyboard_bounds().height() / 2,
1244 occluded_window_bounds.width(), occluded_window_bounds.height())
1245 .ToString(),
1246 window->GetBounds().ToString());
1247 HideKeyboard();
1248 EXPECT_EQ(occluded_window_bounds.ToString(), window->GetBounds().ToString());
1249 }
1250
1251 TEST_F(WorkspaceLayoutManagerKeyboardTest, IgnoreKeyboardBoundsChange) {
1252 InitKeyboardBounds();
1253
1254 std::unique_ptr<WindowOwner> window_owner(
1255 CreateTestWindow(keyboard_bounds()));
1256 WmWindow* window = window_owner->window();
1257 // The additional SetBounds() is needed as the aura-mus case uses Widget,
1258 // which alters the supplied bounds.
1259 window->SetBounds(keyboard_bounds());
1260 window->GetWindowState()->set_ignore_keyboard_bounds_change(true);
1261 window->Activate();
1262
1263 EXPECT_EQ(keyboard_bounds(), window->GetBounds());
1264 ShowKeyboard();
1265 EXPECT_EQ(keyboard_bounds(), window->GetBounds());
1266 }
1267
1268 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h ('k') | ash/common/wm/workspace/workspace_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698