Home | History | Annotate | Download | only in apps
      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.
      4 
      5 #include "chrome/browser/apps/app_browsertest_util.h"
      6 #include "chrome/test/base/interactive_test_utils.h"
      7 #include "extensions/browser/app_window/native_app_window.h"
      8 #include "extensions/test/extension_test_message_listener.h"
      9 #include "extensions/test/result_catcher.h"
     10 
     11 #if defined(OS_MACOSX) && !defined(OS_IOS)
     12 #include "base/mac/mac_util.h"
     13 #endif
     14 
     15 #if defined(OS_WIN)
     16 #include <windows.h>
     17 #include "ui/aura/window.h"
     18 #include "ui/aura/window_tree_host.h"
     19 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
     20 #include "ui/views/win/hwnd_message_handler_delegate.h"
     21 #include "ui/views/win/hwnd_util.h"
     22 #endif
     23 
     24 using extensions::AppWindow;
     25 using extensions::NativeAppWindow;
     26 
     27 // Helper class that has to be created in the stack to check if the fullscreen
     28 // setting of a NativeWindow has changed since the creation of the object.
     29 class FullscreenChangeWaiter {
     30  public:
     31   explicit FullscreenChangeWaiter(NativeAppWindow* window)
     32       : window_(window),
     33         initial_fullscreen_state_(window_->IsFullscreen()) {}
     34 
     35   void Wait() {
     36     while (initial_fullscreen_state_ == window_->IsFullscreen())
     37       content::RunAllPendingInMessageLoop();
     38   }
     39 
     40  private:
     41   NativeAppWindow* window_;
     42   bool initial_fullscreen_state_;
     43 
     44   DISALLOW_COPY_AND_ASSIGN(FullscreenChangeWaiter);
     45 };
     46 
     47 class AppWindowInteractiveTest : public extensions::PlatformAppBrowserTest {
     48  public:
     49   bool RunAppWindowInteractiveTest(const char* testName) {
     50     ExtensionTestMessageListener launched_listener("Launched", true);
     51     LoadAndLaunchPlatformApp("window_api_interactive", &launched_listener);
     52 
     53     extensions::ResultCatcher catcher;
     54     launched_listener.Reply(testName);
     55 
     56     if (!catcher.GetNextResult()) {
     57       message_ = catcher.message();
     58       return false;
     59     }
     60 
     61     return true;
     62   }
     63 
     64   bool SimulateKeyPress(ui::KeyboardCode key) {
     65     return ui_test_utils::SendKeyPressToWindowSync(
     66         GetFirstAppWindow()->GetNativeWindow(),
     67         key,
     68         false,
     69         false,
     70         false,
     71         false);
     72   }
     73 
     74   // This method will wait until the application is able to ack a key event.
     75   void WaitUntilKeyFocus() {
     76     ExtensionTestMessageListener key_listener("KeyReceived", false);
     77 
     78     while (!key_listener.was_satisfied()) {
     79       ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z));
     80       content::RunAllPendingInMessageLoop();
     81     }
     82   }
     83 
     84   // This test is a method so that we can test with each frame type.
     85   void TestOuterBoundsHelper(const std::string& frame_type);
     86 };
     87 
     88 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, ESCLeavesFullscreenWindow) {
     89 // This test is flaky on MacOS 10.6.
     90 #if defined(OS_MACOSX) && !defined(OS_IOS)
     91   if (base::mac::IsOSSnowLeopard())
     92     return;
     93 #endif
     94 
     95   ExtensionTestMessageListener launched_listener("Launched", true);
     96   LoadAndLaunchPlatformApp("leave_fullscreen", &launched_listener);
     97 
     98   // We start by making sure the window is actually focused.
     99   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
    100       GetFirstAppWindow()->GetNativeWindow()));
    101 
    102   // When receiving the reply, the application will try to go fullscreen using
    103   // the Window API but there is no synchronous way to know if that actually
    104   // succeeded. Also, failure will not be notified. A failure case will only be
    105   // known with a timeout.
    106   {
    107     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    108 
    109     launched_listener.Reply("window");
    110 
    111     fs_changed.Wait();
    112   }
    113 
    114   // Depending on the platform, going fullscreen might create an animation.
    115   // We want to make sure that the ESC key we will send next is actually going
    116   // to be received and the application might not receive key events during the
    117   // animation so we should wait for the key focus to be back.
    118   WaitUntilKeyFocus();
    119 
    120   // Same idea as above but for leaving fullscreen. Fullscreen mode should be
    121   // left when ESC is received.
    122   {
    123     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    124 
    125     ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
    126 
    127     fs_changed.Wait();
    128   }
    129 }
    130 
    131 #if defined(OS_MACOSX)
    132 // http://crbug.com/406009
    133 #define MAYBE_ESCLeavesFullscreenDOM DISABLED_ESCLeavesFullscreenDOM
    134 #else
    135 #define MAYBE_ESCLeavesFullscreenDOM ESCLeavesFullscreenDOM
    136 #endif
    137 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_ESCLeavesFullscreenDOM) {
    138 // This test is flaky on MacOS 10.6.
    139 #if defined(OS_MACOSX) && !defined(OS_IOS)
    140   if (base::mac::IsOSSnowLeopard())
    141     return;
    142 #endif
    143 
    144   ExtensionTestMessageListener launched_listener("Launched", true);
    145   LoadAndLaunchPlatformApp("leave_fullscreen", &launched_listener);
    146 
    147   // We start by making sure the window is actually focused.
    148   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
    149       GetFirstAppWindow()->GetNativeWindow()));
    150 
    151   launched_listener.Reply("dom");
    152 
    153   // Because the DOM way to go fullscreen requires user gesture, we simulate a
    154   // key event to get the window entering in fullscreen mode. The reply will
    155   // make the window listen for the key event. The reply will be sent to the
    156   // renderer process before the keypress and should be received in that order.
    157   // When receiving the key event, the application will try to go fullscreen
    158   // using the Window API but there is no synchronous way to know if that
    159   // actually succeeded. Also, failure will not be notified. A failure case will
    160   // only be known with a timeout.
    161   {
    162     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    163 
    164     WaitUntilKeyFocus();
    165     ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
    166 
    167     fs_changed.Wait();
    168   }
    169 
    170   // Depending on the platform, going fullscreen might create an animation.
    171   // We want to make sure that the ESC key we will send next is actually going
    172   // to be received and the application might not receive key events during the
    173   // animation so we should wait for the key focus to be back.
    174   WaitUntilKeyFocus();
    175 
    176   // Same idea as above but for leaving fullscreen. Fullscreen mode should be
    177   // left when ESC is received.
    178   {
    179     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    180 
    181     ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
    182 
    183     fs_changed.Wait();
    184   }
    185 }
    186 
    187 #if defined(OS_MACOSX)
    188 // http://crbug.com/406009
    189 #define MAYBE_ESCDoesNotLeaveFullscreenWindow DISABLED_ESCDoesNotLeaveFullscreenWindow
    190 #else
    191 #define MAYBE_ESCDoesNotLeaveFullscreenWindow ESCDoesNotLeaveFullscreenWindow
    192 #endif
    193 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    194                        MAYBE_ESCDoesNotLeaveFullscreenWindow) {
    195 // This test is flaky on MacOS 10.6.
    196 #if defined(OS_MACOSX) && !defined(OS_IOS)
    197   if (base::mac::IsOSSnowLeopard())
    198     return;
    199 #endif
    200 
    201   ExtensionTestMessageListener launched_listener("Launched", true);
    202   LoadAndLaunchPlatformApp("prevent_leave_fullscreen", &launched_listener);
    203 
    204   // We start by making sure the window is actually focused.
    205   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
    206       GetFirstAppWindow()->GetNativeWindow()));
    207 
    208   // When receiving the reply, the application will try to go fullscreen using
    209   // the Window API but there is no synchronous way to know if that actually
    210   // succeeded. Also, failure will not be notified. A failure case will only be
    211   // known with a timeout.
    212   {
    213     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    214 
    215     launched_listener.Reply("window");
    216 
    217     fs_changed.Wait();
    218   }
    219 
    220   // Depending on the platform, going fullscreen might create an animation.
    221   // We want to make sure that the ESC key we will send next is actually going
    222   // to be received and the application might not receive key events during the
    223   // animation so we should wait for the key focus to be back.
    224   WaitUntilKeyFocus();
    225 
    226   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
    227 
    228   ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
    229 
    230   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
    231 
    232   ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
    233 
    234   // We assume that at that point, if we had to leave fullscreen, we should be.
    235   // However, by nature, we can not guarantee that and given that we do test
    236   // that nothing happens, we might end up with random-success when the feature
    237   // is broken.
    238   EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
    239 }
    240 
    241 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    242                        ESCDoesNotLeaveFullscreenDOM) {
    243 // This test is flaky on MacOS 10.6.
    244 #if defined(OS_MACOSX) && !defined(OS_IOS)
    245   if (base::mac::IsOSSnowLeopard())
    246     return;
    247 #endif
    248 
    249   ExtensionTestMessageListener launched_listener("Launched", true);
    250   LoadAndLaunchPlatformApp("prevent_leave_fullscreen", &launched_listener);
    251 
    252   // We start by making sure the window is actually focused.
    253   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
    254       GetFirstAppWindow()->GetNativeWindow()));
    255 
    256   launched_listener.Reply("dom");
    257 
    258   // Because the DOM way to go fullscreen requires user gesture, we simulate a
    259   // key event to get the window entering in fullscreen mode. The reply will
    260   // make the window listen for the key event. The reply will be sent to the
    261   // renderer process before the keypress and should be received in that order.
    262   // When receiving the key event, the application will try to go fullscreen
    263   // using the Window API but there is no synchronous way to know if that
    264   // actually succeeded. Also, failure will not be notified. A failure case will
    265   // only be known with a timeout.
    266   {
    267     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    268 
    269     WaitUntilKeyFocus();
    270     ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
    271 
    272     fs_changed.Wait();
    273   }
    274 
    275   // Depending on the platform, going fullscreen might create an animation.
    276   // We want to make sure that the ESC key we will send next is actually going
    277   // to be received and the application might not receive key events during the
    278   // animation so we should wait for the key focus to be back.
    279   WaitUntilKeyFocus();
    280 
    281   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
    282 
    283   ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
    284 
    285   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
    286 
    287   ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
    288 
    289   // We assume that at that point, if we had to leave fullscreen, we should be.
    290   // However, by nature, we can not guarantee that and given that we do test
    291   // that nothing happens, we might end up with random-success when the feature
    292   // is broken.
    293   EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
    294 }
    295 
    296 // This test is duplicated from ESCDoesNotLeaveFullscreenWindow.
    297 // It runs the same test, but uses the old permission names: 'fullscreen'
    298 // and 'overrideEscFullscreen'.
    299 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    300                        ESCDoesNotLeaveFullscreenOldPermission) {
    301 // This test is flaky on MacOS 10.6.
    302 #if defined(OS_MACOSX) && !defined(OS_IOS)
    303   if (base::mac::IsOSSnowLeopard())
    304     return;
    305 #endif
    306 
    307   ExtensionTestMessageListener launched_listener("Launched", true);
    308   LoadAndLaunchPlatformApp("prevent_leave_fullscreen_old", &launched_listener);
    309 
    310   // We start by making sure the window is actually focused.
    311   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
    312       GetFirstAppWindow()->GetNativeWindow()));
    313 
    314   // When receiving the reply, the application will try to go fullscreen using
    315   // the Window API but there is no synchronous way to know if that actually
    316   // succeeded. Also, failure will not be notified. A failure case will only be
    317   // known with a timeout.
    318   {
    319     FullscreenChangeWaiter fs_changed(GetFirstAppWindow()->GetBaseWindow());
    320 
    321     launched_listener.Reply("window");
    322 
    323     fs_changed.Wait();
    324   }
    325 
    326   // Depending on the platform, going fullscreen might create an animation.
    327   // We want to make sure that the ESC key we will send next is actually going
    328   // to be received and the application might not receive key events during the
    329   // animation so we should wait for the key focus to be back.
    330   WaitUntilKeyFocus();
    331 
    332   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
    333 
    334   ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
    335 
    336   ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
    337 
    338   ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
    339 
    340   // We assume that at that point, if we had to leave fullscreen, we should be.
    341   // However, by nature, we can not guarantee that and given that we do test
    342   // that nothing happens, we might end up with random-success when the feature
    343   // is broken.
    344   EXPECT_TRUE(GetFirstAppWindow()->GetBaseWindow()->IsFullscreen());
    345 }
    346 
    347 #if defined(OS_MACOSX) || defined(OS_WIN)
    348 // http://crbug.com/404081
    349 #define MAYBE_TestInnerBounds DISABLED_TestInnerBounds
    350 #else
    351 #define MAYBE_TestInnerBounds TestInnerBounds
    352 #endif
    353 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestInnerBounds) {
    354   ASSERT_TRUE(RunAppWindowInteractiveTest("testInnerBounds")) << message_;
    355 }
    356 
    357 void AppWindowInteractiveTest::TestOuterBoundsHelper(
    358     const std::string& frame_type) {
    359   ExtensionTestMessageListener launched_listener("Launched", true);
    360   const extensions::Extension* app =
    361       LoadAndLaunchPlatformApp("outer_bounds", &launched_listener);
    362 
    363   launched_listener.Reply(frame_type);
    364   launched_listener.Reset();
    365   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    366 
    367   AppWindow* window = GetFirstAppWindowForApp(app->id());
    368   gfx::Rect window_bounds;
    369   gfx::Size min_size, max_size;
    370 
    371 #if defined(OS_WIN)
    372   // Get the bounds from the HWND.
    373   HWND hwnd = views::HWNDForNativeWindow(window->GetNativeWindow());
    374   RECT rect;
    375   ::GetWindowRect(hwnd, &rect);
    376   window_bounds = gfx::Rect(
    377       rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
    378 
    379   // HWNDMessageHandler calls this when responding to WM_GETMINMAXSIZE, so it's
    380   // the closest to what the window will see.
    381   views::HWNDMessageHandlerDelegate* host =
    382       static_cast<views::HWNDMessageHandlerDelegate*>(
    383           static_cast<views::DesktopWindowTreeHostWin*>(
    384               aura::WindowTreeHost::GetForAcceleratedWidget(hwnd)));
    385   host->GetMinMaxSize(&min_size, &max_size);
    386   // Note that this does not include the the client area insets so we need to
    387   // add them.
    388   gfx::Insets insets;
    389   host->GetClientAreaInsets(&insets);
    390   min_size = gfx::Size(min_size.width() + insets.left() + insets.right(),
    391                        min_size.height() + insets.top() + insets.bottom());
    392   max_size = gfx::Size(
    393       max_size.width() ? max_size.width() + insets.left() + insets.right() : 0,
    394       max_size.height() ? max_size.height() + insets.top() + insets.bottom()
    395                         : 0);
    396 #endif  // defined(OS_WIN)
    397 
    398   // These match the values in the outer_bounds/test.js
    399   EXPECT_EQ(gfx::Rect(10, 11, 300, 301), window_bounds);
    400   EXPECT_EQ(window->GetBaseWindow()->GetBounds(), window_bounds);
    401   EXPECT_EQ(200, min_size.width());
    402   EXPECT_EQ(201, min_size.height());
    403   EXPECT_EQ(400, max_size.width());
    404   EXPECT_EQ(401, max_size.height());
    405 }
    406 
    407 // TODO(jackhou): Make this test work for other OSes.
    408 #if !defined(OS_WIN)
    409 #define MAYBE_TestOuterBoundsFrameChrome DISABLED_TestOuterBoundsFrameChrome
    410 #define MAYBE_TestOuterBoundsFrameNone DISABLED_TestOuterBoundsFrameNone
    411 #define MAYBE_TestOuterBoundsFrameColor DISABLED_TestOuterBoundsFrameColor
    412 #else
    413 #define MAYBE_TestOuterBoundsFrameChrome TestOuterBoundsFrameChrome
    414 #define MAYBE_TestOuterBoundsFrameNone TestOuterBoundsFrameNone
    415 #define MAYBE_TestOuterBoundsFrameColor TestOuterBoundsFrameColor
    416 #endif
    417 
    418 // Test that the outer bounds match that of the native window.
    419 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    420                        MAYBE_TestOuterBoundsFrameChrome) {
    421   TestOuterBoundsHelper("chrome");
    422 }
    423 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    424                        MAYBE_TestOuterBoundsFrameNone) {
    425   TestOuterBoundsHelper("none");
    426 }
    427 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest,
    428                        MAYBE_TestOuterBoundsFrameColor) {
    429   TestOuterBoundsHelper("color");
    430 }
    431 
    432 // This test does not work on Linux Aura because ShowInactive() is not
    433 // implemented. See http://crbug.com/325142
    434 // It also does not work on Windows because of the document being focused even
    435 // though the window is not activated. See http://crbug.com/326986
    436 // It also does not work on MacOS because ::ShowInactive() ends up behaving like
    437 // ::Show() because of Cocoa conventions. See http://crbug.com/326987
    438 // Those tests should be disabled on Linux GTK when they are enabled on the
    439 // other platforms, see http://crbug.com/328829
    440 #if (defined(OS_LINUX) && defined(USE_AURA)) || \
    441     defined(OS_WIN) || defined(OS_MACOSX)
    442 #define MAYBE_TestCreate DISABLED_TestCreate
    443 #define MAYBE_TestShow DISABLED_TestShow
    444 #else
    445 #define MAYBE_TestCreate TestCreate
    446 #define MAYBE_TestShow TestShow
    447 #endif
    448 
    449 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestCreate) {
    450   ASSERT_TRUE(RunAppWindowInteractiveTest("testCreate")) << message_;
    451 }
    452 
    453 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, MAYBE_TestShow) {
    454   ASSERT_TRUE(RunAppWindowInteractiveTest("testShow")) << message_;
    455 }
    456 
    457 IN_PROC_BROWSER_TEST_F(AppWindowInteractiveTest, TestDrawAttention) {
    458   ASSERT_TRUE(RunAppWindowInteractiveTest("testDrawAttention")) << message_;
    459 }
    460