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), &params2));
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), &params_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), &params));
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