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 "chrome/browser/ui/window_sizer/window_sizer_chromeos.h"
6
7 #include "ash/public/cpp/window_properties.h"
8 #include "ash/shell.h"
9 #include "base/memory/ptr_util.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/window_sizer/window_sizer_common_unittest.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/test/base/chrome_ash_test_base.h"
14 #include "chrome/test/base/test_browser_window_aura.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "content/public/test/render_view_test.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/test/test_windows.h"
21 #include "ui/aura/window_event_dispatcher.h"
22 #include "ui/display/display.h"
23 #include "ui/display/manager/display_manager.h"
24 #include "ui/display/screen.h"
25 #include "ui/display/test/display_manager_test_api.h"
26 #include "ui/wm/public/activation_client.h"
27
28 class WindowSizerChromeOSTest : public ChromeAshTestBase {
29 public:
30 WindowSizerChromeOSTest() = default;
31 WindowSizerChromeOSTest(const WindowSizerChromeOSTest&) = delete;
32 WindowSizerChromeOSTest& operator=(const WindowSizerChromeOSTest&) = delete;
33 ~WindowSizerChromeOSTest() override = default;
34
35 // The window sizing code only works when the window hasn't yet been created.
CreateWindowlessBrowser(Browser::CreateParams params)36 std::unique_ptr<Browser> CreateWindowlessBrowser(
37 Browser::CreateParams params) {
38 params.skip_window_init_for_testing = true;
39 return std::unique_ptr<Browser>(Browser::Create(params));
40 }
41
42 // Similar to WindowSizerTestUtil::GetWindowBounds() but takes an existing
43 // |display_id| instead of creating a TestScreen and new displays.
GetWindowBounds(const Browser * browser,const gfx::Rect & passed_in,int64_t display_id,gfx::Rect * out_bounds)44 void GetWindowBounds(const Browser* browser,
45 const gfx::Rect& passed_in,
46 int64_t display_id,
47 gfx::Rect* out_bounds) {
48 auto state_provider = std::make_unique<TestStateProvider>();
49 state_provider->SetPersistentState(gfx::Rect(), gfx::Rect(),
50 ui::SHOW_STATE_DEFAULT);
51 display::Screen::GetScreen()->SetDisplayForNewWindows(display_id);
52
53 ui::WindowShowState ignored;
54 WindowSizer::GetBrowserWindowBoundsAndShowState(
55 std::move(state_provider), passed_in, browser, out_bounds, &ignored);
56 }
57
58 // Returns browser window |out_bounds| and |out_show_state| for simulated
59 // persisted and last-active window bounds, work area, show state, etc.
GetBrowserWindowBoundsAndShowState(const gfx::Rect & bounds,const gfx::Rect & work_area,ui::WindowShowState show_state_persisted,ui::WindowShowState show_state_last,Source source,const Browser * browser,const gfx::Rect & passed_in,gfx::Rect * out_bounds,ui::WindowShowState * out_show_state)60 static void GetBrowserWindowBoundsAndShowState(
61 const gfx::Rect& bounds,
62 const gfx::Rect& work_area,
63 ui::WindowShowState show_state_persisted,
64 ui::WindowShowState show_state_last,
65 Source source,
66 const Browser* browser,
67 const gfx::Rect& passed_in,
68 gfx::Rect* out_bounds,
69 ui::WindowShowState* out_show_state) {
70 DCHECK(out_show_state);
71 auto provider = std::make_unique<TestStateProvider>();
72 if (source == PERSISTED || source == BOTH)
73 provider->SetPersistentState(bounds, work_area, show_state_persisted);
74 if (source == LAST_ACTIVE || source == BOTH)
75 provider->SetLastActiveState(bounds, show_state_last);
76
77 WindowSizer::GetBrowserWindowBoundsAndShowState(
78 std::move(provider), passed_in, browser, out_bounds, out_show_state);
79 }
80
81 // Returns browser window show state for simulated persisted and last-active
82 // window bounds, work area, show state, etc.
GetBrowserWindowShowState(ui::WindowShowState show_state_persisted,ui::WindowShowState show_state_last,Source source,const Browser * browser,const gfx::Rect & bounds,const gfx::Rect & work_area)83 static ui::WindowShowState GetBrowserWindowShowState(
84 ui::WindowShowState show_state_persisted,
85 ui::WindowShowState show_state_last,
86 Source source,
87 const Browser* browser,
88 const gfx::Rect& bounds,
89 const gfx::Rect& work_area) {
90 ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT;
91 gfx::Rect ignored;
92 GetBrowserWindowBoundsAndShowState(bounds, work_area, show_state_persisted,
93 show_state_last, source, browser,
94 gfx::Rect(), &ignored, &out_show_state);
95 return out_show_state;
96 }
97
98 protected:
99 TestingProfile profile_;
100 };
101
102 namespace {
103
104 // Shorten identifiers to improve line wrapping.
105 const int kDesktopBorderSize = WindowSizerChromeOS::kDesktopBorderSize;
106 const int kMaximumWindowWidth = WindowSizerChromeOS::kMaximumWindowWidth;
107 const int kWindowTilePixels = WindowSizer::kWindowTilePixels;
108
CreateTestBrowser(aura::Window * window,const gfx::Rect & bounds,Browser::CreateParams * params)109 std::unique_ptr<Browser> CreateTestBrowser(aura::Window* window,
110 const gfx::Rect& bounds,
111 Browser::CreateParams* params) {
112 if (!bounds.IsEmpty())
113 window->SetBounds(bounds);
114 std::unique_ptr<Browser> browser =
115 chrome::CreateBrowserWithAuraTestWindowForParams(base::WrapUnique(window),
116 params);
117 if (browser->is_type_normal()) {
118 browser->window()->GetNativeWindow()->SetProperty(
119 ash::kWindowPositionManagedTypeKey, true);
120 }
121 return browser;
122 }
123
124 } // namespace
125
126 // Test that the window is sized appropriately for the first run experience
127 // where the default window bounds calculation is invoked.
TEST_F(WindowSizerChromeOSTest,DefaultSizeCase)128 TEST_F(WindowSizerChromeOSTest, DefaultSizeCase) {
129 {
130 // 4:3 monitor case, 1024x768, no taskbar.
131 gfx::Rect window_bounds;
132 WindowSizerTestUtil::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
133 gfx::Rect(), gfx::Rect(), DEFAULT,
134 NULL, gfx::Rect(), &window_bounds);
135 EXPECT_EQ(
136 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
137 1024 - kDesktopBorderSize * 2, 768 - kDesktopBorderSize),
138 window_bounds);
139 }
140
141 {
142 // 4:3 monitor case, 1024x768, taskbar on bottom.
143 gfx::Rect window_bounds;
144 WindowSizerTestUtil::GetWindowBounds(
145 p1024x768, taskbar_bottom_work_area, gfx::Rect(), gfx::Rect(),
146 gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
147 EXPECT_EQ(gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
148 1024 - kDesktopBorderSize * 2,
149 taskbar_bottom_work_area.height() - kDesktopBorderSize),
150 window_bounds);
151 }
152
153 {
154 // 4:3 monitor case, 1024x768, taskbar on right.
155 gfx::Rect window_bounds;
156 WindowSizerTestUtil::GetWindowBounds(
157 p1024x768, taskbar_right_work_area, gfx::Rect(), gfx::Rect(),
158 gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
159 EXPECT_EQ(
160 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
161 taskbar_right_work_area.width() - kDesktopBorderSize * 2,
162 768 - kDesktopBorderSize),
163 window_bounds);
164 }
165
166 {
167 // 4:3 monitor case, 1024x768, taskbar on left.
168 gfx::Rect window_bounds;
169 WindowSizerTestUtil::GetWindowBounds(
170 p1024x768, taskbar_left_work_area, gfx::Rect(), gfx::Rect(),
171 gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
172 EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() + kDesktopBorderSize,
173 kDesktopBorderSize,
174 taskbar_left_work_area.width() - kDesktopBorderSize * 2,
175 taskbar_left_work_area.height() - kDesktopBorderSize),
176 window_bounds);
177 }
178
179 {
180 // 4:3 monitor case, 1024x768, taskbar on top.
181 gfx::Rect window_bounds;
182 WindowSizerTestUtil::GetWindowBounds(
183 p1024x768, taskbar_top_work_area, gfx::Rect(), gfx::Rect(), gfx::Rect(),
184 DEFAULT, NULL, gfx::Rect(), &window_bounds);
185 EXPECT_EQ(gfx::Rect(kDesktopBorderSize,
186 taskbar_top_work_area.y() + kDesktopBorderSize,
187 1024 - kDesktopBorderSize * 2,
188 taskbar_top_work_area.height() - kDesktopBorderSize),
189 window_bounds);
190 }
191
192 {
193 // 4:3 monitor case, 1280x1024.
194 gfx::Rect window_bounds;
195 WindowSizerTestUtil::GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(),
196 gfx::Rect(), gfx::Rect(), DEFAULT,
197 NULL, gfx::Rect(), &window_bounds);
198 EXPECT_EQ(gfx::Rect((1280 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
199 kMaximumWindowWidth, 1024 - kDesktopBorderSize),
200 window_bounds);
201 }
202
203 {
204 // 4:3 monitor case, 1600x1200.
205 gfx::Rect window_bounds;
206 WindowSizerTestUtil::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
207 gfx::Rect(), gfx::Rect(), DEFAULT,
208 NULL, gfx::Rect(), &window_bounds);
209 EXPECT_EQ(gfx::Rect((1600 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
210 kMaximumWindowWidth, 1200 - kDesktopBorderSize),
211 window_bounds);
212 }
213
214 {
215 // 16:10 monitor case, 1680x1050.
216 gfx::Rect window_bounds;
217 WindowSizerTestUtil::GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(),
218 gfx::Rect(), gfx::Rect(), DEFAULT,
219 NULL, gfx::Rect(), &window_bounds);
220 EXPECT_EQ(gfx::Rect((1680 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
221 kMaximumWindowWidth, 1050 - kDesktopBorderSize),
222 window_bounds);
223 }
224
225 {
226 // 16:10 monitor case, 1920x1200.
227 gfx::Rect window_bounds;
228 WindowSizerTestUtil::GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(),
229 gfx::Rect(), gfx::Rect(), DEFAULT,
230 NULL, gfx::Rect(), &window_bounds);
231 EXPECT_EQ(gfx::Rect((1920 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
232 kMaximumWindowWidth, 1200 - kDesktopBorderSize),
233 window_bounds);
234 }
235 }
236
237 // Test that the next opened window is positioned appropriately given the
238 // bounds of an existing window of the same type.
TEST_F(WindowSizerChromeOSTest,LastWindowBoundsCase)239 TEST_F(WindowSizerChromeOSTest, LastWindowBoundsCase) {
240 {
241 // Normal, in the middle of the screen somewhere.
242 gfx::Rect window_bounds;
243 WindowSizerTestUtil::GetWindowBounds(
244 p1024x768, p1024x768, gfx::Rect(),
245 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
246 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
247 EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
248 kWindowTilePixels + kDesktopBorderSize, 500, 400)
249 .ToString(),
250 window_bounds.ToString());
251 }
252
253 {
254 // Taskbar on top.
255 gfx::Rect window_bounds;
256 WindowSizerTestUtil::GetWindowBounds(
257 p1024x768, taskbar_top_work_area, gfx::Rect(),
258 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
259 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
260 EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
261 std::max(kWindowTilePixels + kDesktopBorderSize,
262 34 /* toolbar height */),
263 500, 400)
264 .ToString(),
265 window_bounds.ToString());
266 }
267
268 {
269 // Too small to satisify the minimum visibility condition.
270 gfx::Rect window_bounds;
271 WindowSizerTestUtil::GetWindowBounds(
272 p1024x768, p1024x768, gfx::Rect(),
273 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 29, 29), gfx::Rect(),
274 LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
275 EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
276 kWindowTilePixels + kDesktopBorderSize, 30 /* not 29 */,
277 30 /* not 29 */)
278 .ToString(),
279 window_bounds.ToString());
280 }
281
282 {
283 // Normal.
284 gfx::Rect window_bounds;
285 WindowSizerTestUtil::GetWindowBounds(
286 p1024x768, p1024x768, gfx::Rect(),
287 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
288 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
289 EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
290 kWindowTilePixels + kDesktopBorderSize, 500, 400)
291 .ToString(),
292 window_bounds.ToString());
293 }
294 }
295
TEST_F(WindowSizerChromeOSTest,LastWindowOffscreenWithNonAggressiveRepositioning)296 TEST_F(WindowSizerChromeOSTest,
297 LastWindowOffscreenWithNonAggressiveRepositioning) {
298 {
299 // Taskbar on left.
300 gfx::Rect window_bounds;
301 WindowSizerTestUtil::GetWindowBounds(
302 p1024x768, taskbar_left_work_area, gfx::Rect(),
303 gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
304 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
305 EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
306 kWindowTilePixels + kDesktopBorderSize, 500, 400)
307 .ToString(),
308 window_bounds.ToString());
309 }
310
311 {
312 // Offset would put the new window offscreen at the bottom but the minimum
313 // visibility condition is barely satisfied without relocation.
314 gfx::Rect window_bounds;
315 WindowSizerTestUtil::GetWindowBounds(
316 p1024x768, p1024x768, gfx::Rect(), gfx::Rect(10, 728, 500, 400),
317 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
318 EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738, 500, 400).ToString(),
319 window_bounds.ToString());
320 }
321
322 {
323 // Offset would put the new window offscreen at the bottom and the minimum
324 // visibility condition is satisified by relocation.
325 gfx::Rect window_bounds;
326 WindowSizerTestUtil::GetWindowBounds(
327 p1024x768, p1024x768, gfx::Rect(), gfx::Rect(10, 729, 500, 400),
328 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
329 EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738 /* not 739 */, 500, 400)
330 .ToString(),
331 window_bounds.ToString());
332 }
333
334 {
335 // Offset would put the new window offscreen at the right but the minimum
336 // visibility condition is barely satisfied without relocation.
337 gfx::Rect window_bounds;
338 WindowSizerTestUtil::GetWindowBounds(
339 p1024x768, p1024x768, gfx::Rect(), gfx::Rect(984, 10, 500, 400),
340 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
341 EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400).ToString(),
342 window_bounds.ToString());
343 }
344
345 {
346 // Offset would put the new window offscreen at the right and the minimum
347 // visibility condition is satisified by relocation.
348 gfx::Rect window_bounds;
349 WindowSizerTestUtil::GetWindowBounds(
350 p1024x768, p1024x768, gfx::Rect(), gfx::Rect(985, 10, 500, 400),
351 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
352 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 10 + kWindowTilePixels, 500, 400)
353 .ToString(),
354 window_bounds.ToString());
355 }
356
357 {
358 // Offset would put the new window offscreen at the bottom right and the
359 // minimum visibility condition is satisified by relocation.
360 gfx::Rect window_bounds;
361 WindowSizerTestUtil::GetWindowBounds(
362 p1024x768, p1024x768, gfx::Rect(), gfx::Rect(985, 729, 500, 400),
363 gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
364 EXPECT_EQ(
365 gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400).ToString(),
366 window_bounds.ToString());
367 }
368 }
369
370 // Test the placement of newly created windows.
TEST_F(WindowSizerChromeOSTest,PlaceNewWindows)371 TEST_F(WindowSizerChromeOSTest, PlaceNewWindows) {
372 // Create a browser to pass into the WindowSizerTestUtil::GetWindowBounds
373 // function.
374 Browser::CreateParams native_params(&profile_, true);
375 auto browser = CreateWindowlessBrowser(native_params);
376
377 // Creating a popup handler here to make sure it does not interfere with the
378 // existing windows.
379 Browser::CreateParams params2(&profile_, true);
380 std::unique_ptr<Browser> browser2 = (CreateTestBrowser(
381 CreateTestWindowInShellWithId(0), gfx::Rect(16, 32, 640, 320), ¶ms2));
382 BrowserWindow* browser_window = browser2->window();
383
384 // Creating a popup to make sure it does not interfere with the positioning.
385 Browser::CreateParams params_popup(Browser::TYPE_POPUP, &profile_, true);
386 std::unique_ptr<Browser> browser_popup(
387 CreateTestBrowser(CreateTestWindowInShellWithId(1),
388 gfx::Rect(16, 32, 128, 256), ¶ms_popup));
389
390 browser_window->Show();
391
392 // Make sure that popups do not get changed.
393 {
394 Browser::CreateParams params_popup(Browser::TYPE_POPUP, &profile_, true);
395 auto new_popup = CreateWindowlessBrowser(params_popup);
396 gfx::Rect window_bounds;
397 WindowSizerTestUtil::GetWindowBounds(
398 p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(50, 100, 300, 150),
399 bottom_s1600x1200, PERSISTED, new_popup.get(), gfx::Rect(),
400 &window_bounds);
401 EXPECT_EQ("50,100 300x150", window_bounds.ToString());
402 }
403
404 browser_window->Hide();
405 {
406 // If a window is there but not shown the persisted default should be used.
407 gfx::Rect window_bounds;
408 WindowSizerTestUtil::GetWindowBounds(
409 p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(50, 100, 300, 150),
410 bottom_s1600x1200, PERSISTED, browser.get(), gfx::Rect(),
411 &window_bounds);
412 EXPECT_EQ("50,100 300x150", window_bounds.ToString());
413 }
414
415 {
416 // If a window is there but not shown the default should be returned.
417 gfx::Rect window_bounds;
418 WindowSizerTestUtil::GetWindowBounds(
419 p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(), bottom_s1600x1200,
420 DEFAULT, browser.get(), gfx::Rect(), &window_bounds);
421 // Note: We need to also take the defaults maximum width into account here
422 // since that might get used if the resolution is too big.
423 EXPECT_EQ(
424 gfx::Rect(
425 std::max(kDesktopBorderSize, (1600 - kMaximumWindowWidth) / 2),
426 kDesktopBorderSize,
427 std::min(kMaximumWindowWidth, 1600 - 2 * kDesktopBorderSize),
428 1200 - kDesktopBorderSize)
429 .ToString(),
430 window_bounds.ToString());
431 }
432 }
433
434 // Test the placement of newly created windows on an empty desktop.
435 // This test supplements "PlaceNewWindows" by testing the creation of a newly
436 // created browser window on an empty desktop.
TEST_F(WindowSizerChromeOSTest,PlaceNewBrowserWindowOnEmptyDesktop)437 TEST_F(WindowSizerChromeOSTest, PlaceNewBrowserWindowOnEmptyDesktop) {
438 Browser::CreateParams native_params(&profile_, true);
439 auto browser = CreateWindowlessBrowser(native_params);
440
441 // A common screen size for Chrome OS devices where forced-maximized
442 // windows are desirable.
443 UpdateDisplay("1366x768");
444 const gfx::Rect p1366x768(0, 0, 1366, 768);
445
446 // If there is no previous state the window should get maximized if the
447 // screen is less than or equal to our limit (1366 pixels width).
448 gfx::Rect window_bounds;
449 ui::WindowShowState out_show_state1 = ui::SHOW_STATE_DEFAULT;
450 GetBrowserWindowBoundsAndShowState(
451 gfx::Rect(), // The (persisted) bounds.
452 p1366x768, // The overall work area.
453 ui::SHOW_STATE_NORMAL, // The persisted show state.
454 ui::SHOW_STATE_DEFAULT, // The last show state.
455 DEFAULT, // No persisted values.
456 browser.get(), // Use this browser.
457 gfx::Rect(), // Don't request valid bounds.
458 &window_bounds, &out_show_state1);
459 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, out_show_state1);
460
461 // If there is a stored coordinate however, that should be taken instead.
462 ui::WindowShowState out_show_state2 = ui::SHOW_STATE_DEFAULT;
463 GetBrowserWindowBoundsAndShowState(
464 gfx::Rect(50, 100, 300, 150), // The (persisted) bounds.
465 p1366x768, // The overall work area.
466 ui::SHOW_STATE_NORMAL, // The persisted show state.
467 ui::SHOW_STATE_DEFAULT, // The last show state.
468 PERSISTED, // Set the persisted values.
469 browser.get(), // Use this browser.
470 gfx::Rect(), // Don't request valid bounds.
471 &window_bounds, &out_show_state2);
472 EXPECT_EQ(ui::SHOW_STATE_NORMAL, out_show_state2);
473 EXPECT_EQ("50,100 300x150", window_bounds.ToString());
474 }
475
TEST_F(WindowSizerChromeOSTest,PlaceNewBrowserWindowOnLargeDesktop)476 TEST_F(WindowSizerChromeOSTest, PlaceNewBrowserWindowOnLargeDesktop) {
477 Browser::CreateParams native_params(&profile_, true);
478 auto browser = CreateWindowlessBrowser(native_params);
479
480 // A larger monitor should not trigger auto-maximize.
481 UpdateDisplay("1600x1200");
482 gfx::Rect window_bounds;
483 ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT;
484 GetBrowserWindowBoundsAndShowState(
485 gfx::Rect(), // The (persisted) bounds.
486 p1600x1200, // The overall work area.
487 ui::SHOW_STATE_NORMAL, // The persisted show state.
488 ui::SHOW_STATE_DEFAULT, // The last show state.
489 DEFAULT, // No persisted values.
490 browser.get(), // Use this browser.
491 gfx::Rect(), // Don't request valid bounds.
492 &window_bounds, &out_show_state);
493 EXPECT_EQ(ui::SHOW_STATE_DEFAULT, out_show_state);
494 }
495
496 // Test the placement of newly created windows on multiple dislays.
TEST_F(WindowSizerChromeOSTest,PlaceNewWindowsOnMultipleDisplays)497 TEST_F(WindowSizerChromeOSTest, PlaceNewWindowsOnMultipleDisplays) {
498 UpdateDisplay("1600x1200,1600x1200");
499 display::Display primary_display =
500 display::Screen::GetScreen()->GetPrimaryDisplay();
501 display::Display second_display =
502 display::test::DisplayManagerTestApi(display_manager())
503 .GetSecondaryDisplay();
504 gfx::Rect primary_bounds = primary_display.bounds();
505 gfx::Rect secondary_bounds = second_display.bounds();
506
507 // Create browser windows that are used as reference.
508 Browser::CreateParams params(&profile_, true);
509 std::unique_ptr<Browser> browser(CreateTestBrowser(
510 CreateTestWindowInShellWithId(0), gfx::Rect(10, 10, 200, 200), ¶ms));
511 BrowserWindow* browser_window = browser->window();
512 gfx::NativeWindow native_window = browser_window->GetNativeWindow();
513 browser_window->Show();
514 EXPECT_EQ(native_window->GetRootWindow(),
515 ash::Shell::GetRootWindowForNewWindows());
516
517 Browser::CreateParams another_params(&profile_, true);
518 std::unique_ptr<Browser> another_browser(
519 CreateTestBrowser(CreateTestWindowInShellWithId(1),
520 gfx::Rect(400, 10, 300, 300), &another_params));
521 BrowserWindow* another_browser_window = another_browser->window();
522 gfx::NativeWindow another_native_window =
523 another_browser_window->GetNativeWindow();
524 another_browser_window->Show();
525
526 // Creating a new window to verify the new placement.
527 Browser::CreateParams new_params(&profile_, true);
528 auto new_browser = CreateWindowlessBrowser(new_params);
529
530 // Make sure the primary root is active.
531 ASSERT_EQ(ash::Shell::GetPrimaryRootWindow(),
532 ash::Shell::GetRootWindowForNewWindows());
533
534 // First new window should be in the primary.
535 {
536 gfx::Rect window_bounds;
537 GetWindowBounds(new_browser.get(), gfx::Rect(), primary_display.id(),
538 &window_bounds);
539 // TODO(oshima): Use exact bounds when the window sizer includes the result
540 // from RearrangeVisibleWindowOnShow.
541 EXPECT_TRUE(primary_bounds.Contains(window_bounds));
542 }
543
544 // Move the window to the right side of the secondary display and create a new
545 // window. It should be opened then on the secondary display.
546 {
547 browser_window->GetNativeWindow()->SetBoundsInScreen(
548 gfx::Rect(secondary_bounds.CenterPoint().x() - 100, 10, 200, 200),
549 second_display);
550 wm::GetActivationClient(native_window->GetRootWindow())
551 ->ActivateWindow(native_window);
552 EXPECT_NE(ash::Shell::GetPrimaryRootWindow(),
553 ash::Shell::GetRootWindowForNewWindows());
554 gfx::Rect window_bounds;
555 GetWindowBounds(new_browser.get(), gfx::Rect(), second_display.id(),
556 &window_bounds);
557 // TODO(oshima): Use exact bounds when the window sizer includes the result
558 // from RearrangeVisibleWindowOnShow.
559 EXPECT_TRUE(secondary_bounds.Contains(window_bounds));
560 }
561
562 // Activate another window in the primary display and create a new window.
563 // It should be created in the primary display.
564 {
565 wm::GetActivationClient(another_native_window->GetRootWindow())
566 ->ActivateWindow(another_native_window);
567 EXPECT_EQ(ash::Shell::GetPrimaryRootWindow(),
568 ash::Shell::GetRootWindowForNewWindows());
569
570 gfx::Rect window_bounds;
571 GetWindowBounds(new_browser.get(), gfx::Rect(), primary_display.id(),
572 &window_bounds);
573 // TODO(oshima): Use exact bounds when the window sizer includes the result
574 // from RearrangeVisibleWindowOnShow.
575 EXPECT_TRUE(primary_bounds.Contains(window_bounds));
576 }
577 }
578
579 // Test that the show state is properly returned for non default cases.
TEST_F(WindowSizerChromeOSTest,TestShowState)580 TEST_F(WindowSizerChromeOSTest, TestShowState) {
581 UpdateDisplay("1600x1200");
582
583 // Creating a browser & window to play with.
584 Browser::CreateParams params(Browser::TYPE_NORMAL, &profile_, true);
585 auto browser = CreateWindowlessBrowser(params);
586
587 // Create also a popup browser since that behaves different.
588 Browser::CreateParams params_popup(Browser::TYPE_POPUP, &profile_, true);
589 auto browser_popup = CreateWindowlessBrowser(params_popup);
590
591 // Tabbed windows should retrieve the saved window state - since there is a
592 // top window.
593 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
594 GetBrowserWindowShowState(ui::SHOW_STATE_MAXIMIZED,
595 ui::SHOW_STATE_NORMAL, PERSISTED,
596 browser.get(), p1600x1200, p1600x1200));
597 // A window that is smaller than the whole work area is set to default state.
598 EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
599 GetBrowserWindowShowState(ui::SHOW_STATE_DEFAULT,
600 ui::SHOW_STATE_NORMAL, PERSISTED,
601 browser.get(), p1280x1024, p1600x1200));
602 // A window that is sized to occupy the whole work area is maximized.
603 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
604 GetBrowserWindowShowState(ui::SHOW_STATE_DEFAULT,
605 ui::SHOW_STATE_NORMAL, PERSISTED,
606 browser.get(), p1600x1200, p1600x1200));
607 // Non tabbed windows should always follow the window saved visibility state.
608 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
609 GetBrowserWindowShowState(
610 ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL, BOTH,
611 browser_popup.get(), p1600x1200, p1600x1200));
612 // The non tabbed window will take the status of the last active of its kind.
613 EXPECT_EQ(ui::SHOW_STATE_NORMAL,
614 GetBrowserWindowShowState(
615 ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
616 browser_popup.get(), p1600x1200, p1600x1200));
617
618 // A tabbed window should now take the top level window state.
619 EXPECT_EQ(
620 ui::SHOW_STATE_NORMAL,
621 GetBrowserWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL,
622 BOTH, browser.get(), p1600x1200, p1600x1200));
623 // Non tabbed windows should always follow the window saved visibility state.
624 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
625 GetBrowserWindowShowState(
626 ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MINIMIZED, BOTH,
627 browser_popup.get(), p1600x1200, p1600x1200));
628 }
629
TEST_F(WindowSizerChromeOSTest,TestShowStateOnTinyScreen)630 TEST_F(WindowSizerChromeOSTest, TestShowStateOnTinyScreen) {
631 Browser::CreateParams params(Browser::TYPE_NORMAL, &profile_, true);
632 auto browser = CreateWindowlessBrowser(params);
633
634 // In smaller screen resolutions we default to maximized if there is no other
635 // window visible.
636 UpdateDisplay("640x480");
637 const gfx::Rect tiny_screen(0, 0, 640, 480);
638 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
639 GetBrowserWindowShowState(ui::SHOW_STATE_MAXIMIZED,
640 ui::SHOW_STATE_DEFAULT, BOTH,
641 browser.get(), tiny_screen, tiny_screen));
642 }
643
644 // Test that the default show state override behavior is properly handled.
TEST_F(WindowSizerChromeOSTest,TestShowStateDefaults)645 TEST_F(WindowSizerChromeOSTest, TestShowStateDefaults) {
646 UpdateDisplay("1600x1200");
647 // Creating a browser & window to play with.
648
649 Browser::CreateParams params(Browser::TYPE_NORMAL, &profile_, true);
650 auto browser = CreateWindowlessBrowser(params);
651
652 // Create also a popup browser since that behaves slightly different for
653 // defaults.
654 Browser::CreateParams params_popup(Browser::TYPE_POPUP, &profile_, true);
655 auto browser_popup = CreateWindowlessBrowser(params_popup);
656
657 // Check that a browser creation state always get used if not given as
658 // SHOW_STATE_DEFAULT.
659 ui::WindowShowState window_show_state = GetBrowserWindowShowState(
660 ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MAXIMIZED, DEFAULT,
661 browser.get(), p1600x1200, p1600x1200);
662 EXPECT_EQ(window_show_state, ui::SHOW_STATE_DEFAULT);
663
664 browser->set_initial_show_state(ui::SHOW_STATE_MINIMIZED);
665 EXPECT_EQ(GetBrowserWindowShowState(ui::SHOW_STATE_MAXIMIZED,
666 ui::SHOW_STATE_MAXIMIZED, BOTH,
667 browser.get(), p1600x1200, p1600x1200),
668 ui::SHOW_STATE_MINIMIZED);
669 browser->set_initial_show_state(ui::SHOW_STATE_NORMAL);
670 EXPECT_EQ(GetBrowserWindowShowState(ui::SHOW_STATE_MAXIMIZED,
671 ui::SHOW_STATE_MAXIMIZED, BOTH,
672 browser.get(), p1600x1200, p1600x1200),
673 ui::SHOW_STATE_NORMAL);
674 browser->set_initial_show_state(ui::SHOW_STATE_MAXIMIZED);
675 EXPECT_EQ(
676 GetBrowserWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
677 BOTH, browser.get(), p1600x1200, p1600x1200),
678 ui::SHOW_STATE_MAXIMIZED);
679
680 // Check that setting the maximized command line option is forcing the
681 // maximized state.
682 base::CommandLine::ForCurrentProcess()->AppendSwitch(
683 switches::kStartMaximized);
684
685 browser->set_initial_show_state(ui::SHOW_STATE_NORMAL);
686 EXPECT_EQ(
687 GetBrowserWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
688 BOTH, browser.get(), p1600x1200, p1600x1200),
689 ui::SHOW_STATE_MAXIMIZED);
690
691 // The popup should favor the initial show state over the command line.
692 EXPECT_EQ(GetBrowserWindowShowState(
693 ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL, BOTH,
694 browser_popup.get(), p1600x1200, p1600x1200),
695 ui::SHOW_STATE_NORMAL);
696 }
697
TEST_F(WindowSizerChromeOSTest,DefaultStateBecomesMaximized)698 TEST_F(WindowSizerChromeOSTest, DefaultStateBecomesMaximized) {
699 // Create a browser to pass into the WindowSizerTestUtil::GetWindowBounds
700 // function.
701 Browser::CreateParams native_params(&profile_, true);
702 auto browser = CreateWindowlessBrowser(native_params);
703
704 gfx::Rect display_bounds =
705 display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
706 gfx::Rect specified_bounds = display_bounds;
707
708 // Make a window bigger than the display work area.
709 specified_bounds.Inset(-20, -20);
710 ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
711 gfx::Rect bounds;
712 WindowSizer::GetBrowserWindowBoundsAndShowState(
713 specified_bounds, browser.get(), &bounds, &show_state);
714 // The window should start maximized with its restore bounds shrunken.
715 EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, show_state);
716 EXPECT_NE(display_bounds.ToString(), bounds.ToString());
717 EXPECT_TRUE(display_bounds.Contains(bounds));
718
719 // Make a window smaller than the display work area.
720 specified_bounds.Inset(100, 100);
721 show_state = ui::SHOW_STATE_DEFAULT;
722 WindowSizer::GetBrowserWindowBoundsAndShowState(
723 specified_bounds, browser.get(), &bounds, &show_state);
724 // The window should start in default state.
725 EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
726 EXPECT_EQ(specified_bounds.ToString(), bounds.ToString());
727 }
728
729 // Test that the target root window is used as the destination of
730 // the non browser window. This differ from PersistedBoundsCase
731 // in that this uses real ash shell implementations + StateProvider
732 // rather than mocks.
TEST_F(WindowSizerChromeOSTest,DefaultBoundsInTargetDisplay)733 TEST_F(WindowSizerChromeOSTest, DefaultBoundsInTargetDisplay) {
734 UpdateDisplay("500x500,600x600");
735
736 // By default windows are placed on the primary display.
737 aura::Window* first_root = ash::Shell::GetAllRootWindows()[0];
738 EXPECT_EQ(first_root, ash::Shell::GetRootWindowForNewWindows());
739 gfx::Rect bounds;
740 ui::WindowShowState show_state;
741 WindowSizer::GetBrowserWindowBoundsAndShowState(gfx::Rect(), nullptr, &bounds,
742 &show_state);
743 EXPECT_TRUE(first_root->GetBoundsInScreen().Contains(bounds));
744
745 {
746 // When the second display is active new windows are placed there.
747 aura::Window* second_root = ash::Shell::GetAllRootWindows()[1];
748 int64_t second_display_id =
749 display::test::DisplayManagerTestApi(display_manager())
750 .GetSecondaryDisplay()
751 .id();
752 display::Screen::GetScreen()->SetDisplayForNewWindows(second_display_id);
753 gfx::Rect bounds;
754 ui::WindowShowState show_state;
755 WindowSizer::GetBrowserWindowBoundsAndShowState(gfx::Rect(), nullptr,
756 &bounds, &show_state);
757 EXPECT_TRUE(second_root->GetBoundsInScreen().Contains(bounds));
758 }
759 }
760
TEST_F(WindowSizerChromeOSTest,TrustedPopupBehavior)761 TEST_F(WindowSizerChromeOSTest, TrustedPopupBehavior) {
762 Browser::CreateParams trusted_popup_create_params(Browser::TYPE_POPUP,
763 &profile_, true);
764 trusted_popup_create_params.trusted_source = true;
765
766 auto trusted_popup = CreateWindowlessBrowser(trusted_popup_create_params);
767 // Trusted popup windows should follow the saved show state and ignore the
768 // last show state.
769 EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
770 GetBrowserWindowShowState(
771 ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
772 trusted_popup.get(), p1280x1024, p1600x1200));
773 // A popup that is sized to occupy the whole work area has default state.
774 EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
775 GetBrowserWindowShowState(
776 ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
777 trusted_popup.get(), p1600x1200, p1600x1200));
778 }
779