Home | History | Annotate | Download | only in frame
      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/chrome_notification_types.h"
      6 #include "chrome/browser/ui/browser.h"
      7 #include "chrome/browser/ui/browser_finder.h"
      8 #include "chrome/browser/ui/browser_list.h"
      9 #include "chrome/browser/ui/browser_tabstrip.h"
     10 #include "chrome/browser/ui/browser_window.h"
     11 #include "chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h"
     12 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
     13 #include "chrome/browser/ui/views/frame/browser_view.h"
     14 #include "chrome/test/base/in_process_browser_test.h"
     15 #include "content/public/test/test_utils.h"
     16 #include "ui/aura/client/aura_constants.h"
     17 #include "ui/aura/root_window.h"
     18 #include "ui/aura/test/event_generator.h"
     19 #include "ui/aura/window.h"
     20 #include "ui/gfx/screen.h"
     21 
     22 using aura::Window;
     23 
     24 namespace {
     25 
     26 Window* GetChildWindowNamed(Window* window, const char* name) {
     27   for (size_t i = 0; i < window->children().size(); ++i) {
     28     Window* child = window->children()[i];
     29     if (child->name() == name)
     30       return child;
     31   }
     32   return NULL;
     33 }
     34 
     35 bool HasChildWindowNamed(Window* window, const char* name) {
     36   return GetChildWindowNamed(window, name) != NULL;
     37 }
     38 
     39 void MaximizeWindow(aura::Window* window) {
     40   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
     41 }
     42 
     43 void MinimizeWindow(aura::Window* window) {
     44   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
     45 }
     46 
     47 void RestoreWindow(Window* window) {
     48   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
     49 }
     50 
     51 }  // namespace
     52 
     53 class AppNonClientFrameViewAshTest : public InProcessBrowserTest {
     54  public:
     55   AppNonClientFrameViewAshTest() : InProcessBrowserTest(), app_browser_(NULL) {
     56   }
     57   virtual ~AppNonClientFrameViewAshTest() {}
     58 
     59   virtual void SetUpOnMainThread() OVERRIDE {
     60     Browser::CreateParams params = Browser::CreateParams::CreateForApp(
     61         Browser::TYPE_POPUP,
     62         std::string("Test"),
     63         gfx::Rect(),
     64         browser()->profile(),
     65         browser()->host_desktop_type());
     66     params.initial_show_state = ui::SHOW_STATE_MAXIMIZED;
     67     params.app_type = Browser::APP_TYPE_HOST;
     68     app_browser_ = new Browser(params);
     69     chrome::AddBlankTabAt(app_browser_, -1, true);
     70     app_browser_->window()->Show();
     71   }
     72 
     73   // Returns the class name of the NonClientFrameView.
     74   std::string GetFrameClassName() const {
     75     BrowserView* browser_view =
     76         static_cast<BrowserView*>(app_browser_->window());
     77     BrowserFrame* browser_frame = browser_view->frame();
     78     return browser_frame->GetFrameView()->GetClassName();
     79   }
     80 
     81   aura::RootWindow* GetRootWindow() const {
     82     BrowserView* browser_view =
     83         static_cast<BrowserView*>(app_browser_->window());
     84     views::Widget* widget = browser_view->GetWidget();
     85     aura::Window* window =
     86         static_cast<aura::Window*>(widget->GetNativeWindow());
     87     return window->GetRootWindow();
     88   }
     89 
     90   Browser* app_browser() const { return app_browser_; }
     91 
     92  private:
     93   Browser *app_browser_;
     94 };
     95 
     96 #if defined(USE_ASH)
     97 // Ensure that restoring the app window replaces the frame with a normal one,
     98 // and maximizing again brings back the app frame. This has been the source of
     99 // some crash bugs like crbug.com/155634
    100 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, SwitchFrames) {
    101   // Convert to std::string so Windows can match EXPECT_EQ.
    102   const std::string kAppFrameClassName =
    103       AppNonClientFrameViewAsh::kViewClassName;
    104   const std::string kNormalFrameClassName =
    105       BrowserNonClientFrameViewAsh::kViewClassName;
    106 
    107   // We start with the app frame.
    108   EXPECT_EQ(kAppFrameClassName, GetFrameClassName());
    109 
    110   // Restoring the window gives us the normal frame.
    111   Window* native_window = app_browser()->window()->GetNativeWindow();
    112   RestoreWindow(native_window);
    113   EXPECT_EQ(kNormalFrameClassName, GetFrameClassName());
    114 
    115   // Maximizing the window switches back to the app frame.
    116   MaximizeWindow(native_window);
    117   EXPECT_EQ(kAppFrameClassName, GetFrameClassName());
    118 
    119   // Minimizing the window switches to normal frame.
    120   // TODO(jamescook): This seems wasteful, since the user is likely to bring
    121   // the window back to the maximized state.
    122   MinimizeWindow(native_window);
    123   EXPECT_EQ(kNormalFrameClassName, GetFrameClassName());
    124 
    125   // Coming back to maximized switches to app frame.
    126   MaximizeWindow(native_window);
    127   EXPECT_EQ(kAppFrameClassName, GetFrameClassName());
    128 
    129   // One more restore/maximize cycle for good measure.
    130   RestoreWindow(native_window);
    131   EXPECT_EQ(kNormalFrameClassName, GetFrameClassName());
    132   MaximizeWindow(native_window);
    133   EXPECT_EQ(kAppFrameClassName, GetFrameClassName());
    134 }
    135 #endif  // USE_ASH
    136 
    137 // Ensure that we can click the close button when the controls are shown.
    138 // In particular make sure that we can click it on the top pixel of the button.
    139 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, ClickClose) {
    140   aura::RootWindow* root_window = GetRootWindow();
    141   aura::test::EventGenerator eg(root_window, gfx::Point(0, 1));
    142 
    143   // Click close button.
    144   eg.MoveMouseTo(root_window->bounds().width() - 1, 0);
    145   content::WindowedNotificationObserver signal(
    146       chrome::NOTIFICATION_BROWSER_CLOSED,
    147       content::Source<Browser>(app_browser()));
    148   eg.ClickLeftButton();
    149   signal.Wait();
    150   EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
    151                                       browser()->host_desktop_type()));
    152 }
    153 
    154 // Ensure that closing a maximized app with Ctrl-W does not crash the
    155 // application.  crbug.com/147635
    156 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, KeyboardClose) {
    157   aura::RootWindow* root_window = GetRootWindow();
    158   aura::test::EventGenerator eg(root_window);
    159 
    160   // Base browser and app browser.
    161   EXPECT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
    162                                         browser()->host_desktop_type()));
    163 
    164   // Send Control-W.
    165   content::WindowedNotificationObserver signal(
    166       chrome::NOTIFICATION_BROWSER_CLOSED,
    167       content::Source<Browser>(app_browser()));
    168   eg.PressKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
    169   eg.ReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
    170   signal.Wait();
    171 
    172   // App browser is closed.
    173   EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
    174                                         browser()->host_desktop_type()));
    175 }
    176 
    177 // Ensure that snapping left with Alt-[ closes the control window.
    178 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, SnapLeftClosesControls) {
    179   aura::RootWindow* root_window = GetRootWindow();
    180   aura::test::EventGenerator eg(root_window);
    181   aura::Window* native_window = app_browser()->window()->GetNativeWindow();
    182 
    183   // Control window exists.
    184   EXPECT_TRUE(HasChildWindowNamed(
    185       native_window, AppNonClientFrameViewAsh::kControlWindowName));
    186 
    187   // Send Alt-[
    188   eg.PressKey(ui::VKEY_OEM_4, ui::EF_ALT_DOWN);
    189   eg.ReleaseKey(ui::VKEY_OEM_4, ui::EF_ALT_DOWN);
    190   content::RunAllPendingInMessageLoop();
    191 
    192   // Control window is gone.
    193   EXPECT_FALSE(HasChildWindowNamed(
    194       native_window, AppNonClientFrameViewAsh::kControlWindowName));
    195 }
    196 
    197 // Ensure that the controls are at the proper locations.
    198 IN_PROC_BROWSER_TEST_F(AppNonClientFrameViewAshTest, ControlsAtRightSide) {
    199   aura::RootWindow* root_window = GetRootWindow();
    200   aura::test::EventGenerator eg(root_window);
    201   aura::Window* native_window = app_browser()->window()->GetNativeWindow();
    202   const gfx::Rect work_area =
    203       gfx::Screen::GetScreenFor(native_window)->GetPrimaryDisplay().work_area();
    204 
    205   // Control window exists.
    206   aura::Window* window = GetChildWindowNamed(
    207       native_window, AppNonClientFrameViewAsh::kControlWindowName);
    208 
    209   ASSERT_TRUE(window);
    210   gfx::Rect rect = window->bounds();
    211   EXPECT_EQ(work_area.right(), rect.right());
    212   EXPECT_EQ(work_area.y(), rect.y());
    213 
    214   MinimizeWindow(native_window);
    215   content::RunAllPendingInMessageLoop();
    216   window = GetChildWindowNamed(
    217       native_window, AppNonClientFrameViewAsh::kControlWindowName);
    218   EXPECT_FALSE(window);
    219   MaximizeWindow(native_window);
    220   content::RunAllPendingInMessageLoop();
    221 
    222   // Control window exists.
    223   aura::Window* window_after = GetChildWindowNamed(
    224       native_window, AppNonClientFrameViewAsh::kControlWindowName);
    225   ASSERT_TRUE(window_after);
    226   gfx::Rect rect_after = window_after->bounds();
    227   EXPECT_EQ(work_area.right(), rect_after.right());
    228   EXPECT_EQ(work_area.y(), rect_after.y());
    229 }
    230