1 // Copyright 2013 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.
5 #include "apps/ui/native_app_window.h"
6 #include "chrome/browser/apps/app_browsertest_util.h"
7 #include "chrome/browser/extensions/extension_test_message_listener.h"
8 #include "chrome/test/base/interactive_test_utils.h"
10 #if defined(OS_MACOSX) && !defined(OS_IOS)
11 #include "base/mac/mac_util.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
19 #include "ui/views/win/hwnd_message_handler_delegate.h"
20 #include "ui/views/win/hwnd_util.h"
23 using apps::NativeAppWindow;
25 // Helper class that has to be created in the stack to check if the fullscreen
26 // setting of a NativeWindow has changed since the creation of the object.
27 class FullscreenChangeWaiter {
29 explicit FullscreenChangeWaiter(NativeAppWindow* window)
31 initial_fullscreen_state_(window_->IsFullscreen()) {}
34 while (initial_fullscreen_state_ == window_->IsFullscreen())
35 content::RunAllPendingInMessageLoop();
39 NativeAppWindow* window_;
40 bool initial_fullscreen_state_;
42 DISALLOW_COPY_AND_ASSIGN(FullscreenChangeWaiter);
45 class AppWindowInteractiveTest : public extensions::PlatformAppBrowserTest {
47 bool RunAppWindowInteractiveTest(const char* testName) {
48 ExtensionTestMessageListener launched_listener("Launched", true);
49 LoadAndLaunchPlatformApp("window_api_interactive", &launched_listener);
51 ResultCatcher catcher;
52 launched_listener.Reply(testName);
54 if (!catcher.GetNextResult()) {
55 message_ = catcher.message();
62 bool SimulateKeyPress(ui::KeyboardCode key) {
63 return ui_test_utils::SendKeyPressToWindowSync(
64 GetFirstAppWindow()->GetNativeWindow(),
72 // This method will wait until the application is able to ack a key event.
73 void WaitUntilKeyFocus() {
74 ExtensionTestMessageListener key_listener("KeyReceived", false);
76 while (!key_listener.was_satisfied()) {
77 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z));
78 content::RunAllPendingInMessageLoop();
82 // This test is a method so that we can test with each frame type.
83 void TestOuterBoundsHelper(const std::string& frame_type);
86 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, ESCLeavesFullscreenWindow) {
87 // This test is flaky on MacOS 10.6.
88 #if defined(OS_MACOSX) && !defined(OS_IOS)
89 if (base::mac::IsOSSnowLeopard())
93 ExtensionTestMessageListener launched_listener("Launched", true);
94 LoadAndLaunchPlatformApp("leave_fullscreen", &launched_listener);
96 // We start by making sure the window is actually focused.
97 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
98 GetFirstAppWindow()->GetNativeWindow()));
100 // When receiving the reply, the application will try to go fullscreen using
101 // the Window API but there is no synchronous way to know if that actually
102 // succeeded. Also, failure will not be notified. A failure case will only be
103 // known with a timeout.
105 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
107 launched_listener.Reply("window");
112 // Depending on the platform, going fullscreen might create an animation.
113 // We want to make sure that the ESC key we will send next is actually going
114 // to be received and the application might not receive key events during the
115 // animation so we should wait for the key focus to be back.
118 // Same idea as above but for leaving fullscreen. Fullscreen mode should be
119 // left when ESC is received.
121 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
123 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
129 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, ESCLeavesFullscreenDOM) {
130 // This test is flaky on MacOS 10.6.
131 #if defined(OS_MACOSX) && !defined(OS_IOS)
132 if (base::mac::IsOSSnowLeopard())
136 ExtensionTestMessageListener launched_listener("Launched", true);
137 LoadAndLaunchPlatformApp("leave_fullscreen", &launched_listener);
139 // We start by making sure the window is actually focused.
140 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
141 GetFirstAppWindow()->GetNativeWindow()));
143 launched_listener.Reply("dom");
145 // Because the DOM way to go fullscreen requires user gesture, we simulate a
146 // key event to get the window entering in fullscreen mode. The reply will
147 // make the window listen for the key event. The reply will be sent to the
148 // renderer process before the keypress and should be received in that order.
149 // When receiving the key event, the application will try to go fullscreen
150 // using the Window API but there is no synchronous way to know if that
151 // actually succeeded. Also, failure will not be notified. A failure case will
152 // only be known with a timeout.
154 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
157 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
162 // Depending on the platform, going fullscreen might create an animation.
163 // We want to make sure that the ESC key we will send next is actually going
164 // to be received and the application might not receive key events during the
165 // animation so we should wait for the key focus to be back.
168 // Same idea as above but for leaving fullscreen. Fullscreen mode should be
169 // left when ESC is received.
171 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
173 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
179 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
180 ESCDoesNotLeaveFullscreenWindow) {
181 // This test is flaky on MacOS 10.6.
182 #if defined(OS_MACOSX) && !defined(OS_IOS)
183 if (base::mac::IsOSSnowLeopard())
187 ExtensionTestMessageListener launched_listener("Launched", true);
188 LoadAndLaunchPlatformApp("prevent_leave_fullscreen", &launched_listener);
190 // We start by making sure the window is actually focused.
191 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
192 GetFirstAppWindow()->GetNativeWindow()));
194 // When receiving the reply, the application will try to go fullscreen using
195 // the Window API but there is no synchronous way to know if that actually
196 // succeeded. Also, failure will not be notified. A failure case will only be
197 // known with a timeout.
199 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
201 launched_listener.Reply("window");
206 // Depending on the platform, going fullscreen might create an animation.
207 // We want to make sure that the ESC key we will send next is actually going
208 // to be received and the application might not receive key events during the
209 // animation so we should wait for the key focus to be back.
212 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
214 ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
216 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
218 ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
220 // We assume that at that point, if we had to leave fullscreen, we should be.
221 // However, by nature, we can not guarantee that and given that we do test
222 // that nothing happens, we might end up with random-success when the feature
224 EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
227 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
228 ESCDoesNotLeaveFullscreenDOM) {
229 // This test is flaky on MacOS 10.6.
230 #if defined(OS_MACOSX) && !defined(OS_IOS)
231 if (base::mac::IsOSSnowLeopard())
235 ExtensionTestMessageListener launched_listener("Launched", true);
236 LoadAndLaunchPlatformApp("prevent_leave_fullscreen", &launched_listener);
238 // We start by making sure the window is actually focused.
239 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
240 GetFirstAppWindow()->GetNativeWindow()));
242 launched_listener.Reply("dom");
244 // Because the DOM way to go fullscreen requires user gesture, we simulate a
245 // key event to get the window entering in fullscreen mode. The reply will
246 // make the window listen for the key event. The reply will be sent to the
247 // renderer process before the keypress and should be received in that order.
248 // When receiving the key event, the application will try to go fullscreen
249 // using the Window API but there is no synchronous way to know if that
250 // actually succeeded. Also, failure will not be notified. A failure case will
251 // only be known with a timeout.
253 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
256 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
261 // Depending on the platform, going fullscreen might create an animation.
262 // We want to make sure that the ESC key we will send next is actually going
263 // to be received and the application might not receive key events during the
264 // animation so we should wait for the key focus to be back.
267 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
269 ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
271 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
273 ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
275 // We assume that at that point, if we had to leave fullscreen, we should be.
276 // However, by nature, we can not guarantee that and given that we do test
277 // that nothing happens, we might end up with random-success when the feature
279 EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
282 // This test is duplicated from ESCDoesNotLeaveFullscreenWindow.
283 // It runs the same test, but uses the old permission names: 'fullscreen'
284 // and 'overrideEscFullscreen'.
285 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
286 ESCDoesNotLeaveFullscreenOldPermission) {
287 // This test is flaky on MacOS 10.6.
288 #if defined(OS_MACOSX) && !defined(OS_IOS)
289 if (base::mac::IsOSSnowLeopard())
293 ExtensionTestMessageListener launched_listener("Launched", true);
294 LoadAndLaunchPlatformApp("prevent_leave_fullscreen_old", &launched_listener);
296 // We start by making sure the window is actually focused.
297 ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
298 GetFirstAppWindow()->GetNativeWindow()));
300 // When receiving the reply, the application will try to go fullscreen using
301 // the Window API but there is no synchronous way to know if that actually
302 // succeeded. Also, failure will not be notified. A failure case will only be
303 // known with a timeout.
305 FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
307 launched_listener.Reply("window");
312 // Depending on the platform, going fullscreen might create an animation.
313 // We want to make sure that the ESC key we will send next is actually going
314 // to be received and the application might not receive key events during the
315 // animation so we should wait for the key focus to be back.
318 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
320 ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
322 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
324 ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
326 // We assume that at that point, if we had to leave fullscreen, we should be.
327 // However, by nature, we can not guarantee that and given that we do test
328 // that nothing happens, we might end up with random-success when the feature
330 EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
333 #if defined(OS_MACOSX)
334 // http://crbug.com/404081
335 #define MAYBE_TestInnerBounds DISABLED_TestInnerBounds
337 #define MAYBE_TestInnerBounds TestInnerBounds
339 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestInnerBounds) {
340 ASSERT_TRUE(RunAppWindowInteractiveTest("testInnerBounds")) << message_;
343 void AppWindowInteractiveTest::TestOuterBoundsHelper(
344 const std::string& frame_type) {
345 ExtensionTestMessageListener launched_listener("Launched", true);
346 const extensions::Extension* app =
347 LoadAndLaunchPlatformApp("outer_bounds", &launched_listener);
349 launched_listener.Reply(frame_type);
350 launched_listener.Reset();
351 ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
353 apps::AppWindow* window = GetFirstAppWindowForApp(app->id());
354 gfx::Rect window_bounds;
355 gfx::Size min_size, max_size;
358 // Get the bounds from the HWND.
359 HWND hwnd = views::HWNDForNativeWindow(window->GetNativeWindow());
361 ::GetWindowRect(hwnd, &rect);
362 window_bounds = gfx::Rect(
363 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
365 // HWNDMessageHandler calls this when responding to WM_GETMINMAXSIZE, so it's
366 // the closest to what the window will see.
367 views::HWNDMessageHandlerDelegate* host =
368 static_cast<views::HWNDMessageHandlerDelegate*>(
369 static_cast<views::DesktopWindowTreeHostWin*>(
370 aura::WindowTreeHost::GetForAcceleratedWidget(hwnd)));
371 host->GetMinMaxSize(&min_size, &max_size);
372 // Note that this does not include the the client area insets so we need to
375 host->GetClientAreaInsets(&insets);
376 min_size = gfx::Size(min_size.width() + insets.left() + insets.right(),
377 min_size.height() + insets.top() + insets.bottom());
378 max_size = gfx::Size(
379 max_size.width() ? max_size.width() + insets.left() + insets.right() : 0,
380 max_size.height() ? max_size.height() + insets.top() + insets.bottom()
382 #endif // defined(OS_WIN)
384 // These match the values in the outer_bounds/test.js
385 EXPECT_EQ(gfx::Rect(10, 11, 300, 301), window_bounds);
386 EXPECT_EQ(window->GetBaseWindow()->GetBounds(), window_bounds);
387 EXPECT_EQ(200, min_size.width());
388 EXPECT_EQ(201, min_size.height());
389 EXPECT_EQ(400, max_size.width());
390 EXPECT_EQ(401, max_size.height());
393 // TODO(jackhou): Make this test work for other OSes.
395 #define MAYBE_TestOuterBoundsFrameChrome DISABLED_TestOuterBoundsFrameChrome
396 #define MAYBE_TestOuterBoundsFrameNone DISABLED_TestOuterBoundsFrameNone
397 #define MAYBE_TestOuterBoundsFrameColor DISABLED_TestOuterBoundsFrameColor
399 #define MAYBE_TestOuterBoundsFrameChrome TestOuterBoundsFrameChrome
400 #define MAYBE_TestOuterBoundsFrameNone TestOuterBoundsFrameNone
401 #define MAYBE_TestOuterBoundsFrameColor TestOuterBoundsFrameColor
404 // Test that the outer bounds match that of the native window.
405 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
406 MAYBE_TestOuterBoundsFrameChrome) {
407 TestOuterBoundsHelper("chrome");
409 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
410 MAYBE_TestOuterBoundsFrameNone) {
411 TestOuterBoundsHelper("none");
413 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
414 MAYBE_TestOuterBoundsFrameColor) {
415 TestOuterBoundsHelper("color");
418 // This test does not work on Linux Aura because ShowInactive() is not
419 // implemented. See http://crbug.com/325142
420 // It also does not work on Windows because of the document being focused even
421 // though the window is not activated. See http://crbug.com/326986
422 // It also does not work on MacOS because ::ShowInactive() ends up behaving like
423 // ::Show() because of Cocoa conventions. See http://crbug.com/326987
424 // Those tests should be disabled on Linux GTK when they are enabled on the
425 // other platforms, see http://crbug.com/328829
426 #if (defined(OS_LINUX) && defined(USE_AURA)) || \
427 defined(OS_WIN) || defined(OS_MACOSX)
428 #define MAYBE_TestCreate DISABLED_TestCreate
429 #define MAYBE_TestShow DISABLED_TestShow
431 #define MAYBE_TestCreate TestCreate
432 #define MAYBE_TestShow TestShow
435 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestCreate) {
436 ASSERT_TRUE(RunAppWindowInteractiveTest("testCreate")) << message_;
439 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestShow) {
440 ASSERT_TRUE(RunAppWindowInteractiveTest("testShow")) << message_;