1// Copyright 2014 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 "ash/frame/custom_frame_view_ash.h"
6
7#include "ash/frame/caption_buttons/frame_caption_button.h"
8#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
9#include "ash/shell.h"
10#include "ash/test/ash_test_base.h"
11#include "ash/test/test_session_state_delegate.h"
12#include "ash/wm/maximize_mode/maximize_mode_controller.h"
13#include "base/memory/scoped_ptr.h"
14#include "grit/ash_resources.h"
15#include "ui/base/resource/resource_bundle.h"
16#include "ui/gfx/image/image_skia.h"
17#include "ui/gfx/rect.h"
18#include "ui/views/widget/widget.h"
19#include "ui/views/widget/widget_delegate.h"
20
21namespace ash {
22
23// A views::WidgetDelegate which uses a CustomFrameViewAsh.
24class TestWidgetDelegate : public views::WidgetDelegateView {
25 public:
26  TestWidgetDelegate() {}
27  virtual ~TestWidgetDelegate() {}
28
29  virtual views::NonClientFrameView* CreateNonClientFrameView(
30      views::Widget* widget) OVERRIDE {
31    custom_frame_view_ = new CustomFrameViewAsh(widget);
32    return custom_frame_view_;
33  }
34
35  CustomFrameViewAsh* custom_frame_view() const {
36    return custom_frame_view_;
37  }
38
39 private:
40  // Not owned.
41  CustomFrameViewAsh* custom_frame_view_;
42
43  DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
44};
45
46class TestWidgetConstraintsDelegate : public TestWidgetDelegate {
47 public:
48  TestWidgetConstraintsDelegate() {}
49  virtual ~TestWidgetConstraintsDelegate() {}
50
51  // views::View:
52  virtual gfx::Size GetMinimumSize() const OVERRIDE {
53    return minimum_size_;
54  }
55
56  virtual gfx::Size GetMaximumSize() const OVERRIDE {
57    return maximum_size_;
58  }
59
60  virtual views::View* GetContentsView() OVERRIDE {
61    // Set this instance as the contents view so that the maximum and minimum
62    // size constraints will be used.
63    return this;
64  }
65
66  // views::WidgetDelegate:
67  virtual bool CanMaximize() const OVERRIDE {
68    return true;
69  }
70
71  virtual bool CanMinimize() const OVERRIDE {
72    return true;
73  }
74
75  void set_minimum_size(const gfx::Size& min_size) {
76    minimum_size_ = min_size;
77  }
78
79  void set_maximum_size(const gfx::Size& max_size) {
80    maximum_size_ = max_size;
81  }
82
83  const gfx::Rect& GetFrameCaptionButtonContainerViewBounds() {
84    return custom_frame_view()->GetFrameCaptionButtonContainerViewForTest()->
85        bounds();
86  }
87
88  void EndFrameCaptionButtonContainerViewAnimations() {
89    FrameCaptionButtonContainerView::TestApi test(custom_frame_view()->
90        GetFrameCaptionButtonContainerViewForTest());
91    test.EndAnimations();
92  }
93
94  int GetTitleBarHeight() const {
95    return custom_frame_view()->NonClientTopBorderHeight();
96  }
97
98 private:
99  gfx::Size minimum_size_;
100  gfx::Size maximum_size_;
101
102  DISALLOW_COPY_AND_ASSIGN(TestWidgetConstraintsDelegate);
103};
104
105class CustomFrameViewAshTest : public test::AshTestBase {
106 public:
107  CustomFrameViewAshTest() {}
108  virtual ~CustomFrameViewAshTest() {}
109
110 protected:
111  scoped_ptr<views::Widget> CreateWidget(TestWidgetDelegate* delegate) {
112    scoped_ptr<views::Widget> widget(new views::Widget);
113    views::Widget::InitParams params;
114    params.delegate = delegate;
115    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
116    params.bounds = gfx::Rect(0, 0, 100, 100);
117    params.context = CurrentContext();
118    widget->Init(params);
119    return widget.Pass();
120  }
121
122  test::TestSessionStateDelegate* GetTestSessionStateDelegate() {
123    return static_cast<ash::test::TestSessionStateDelegate*>(
124        Shell::GetInstance()->session_state_delegate());
125  }
126
127 private:
128  DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest);
129};
130
131// Test that the height of the header is correct upon initially displaying
132// the widget.
133TEST_F(CustomFrameViewAshTest, HeaderHeight) {
134  TestWidgetDelegate* delegate = new TestWidgetDelegate;
135
136  scoped_ptr<views::Widget> widget(CreateWidget(delegate));
137  widget->Show();
138
139  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
140  gfx::ImageSkia* close_button =
141      rb.GetImageSkiaNamed(IDR_AURA_WINDOW_CONTROL_BACKGROUND_H);
142
143  // The header should have enough room for the window controls. The
144  // header/content separator line overlays the window controls.
145  EXPECT_EQ(close_button->height(),
146            delegate->custom_frame_view()->GetHeaderView()->height());
147}
148
149// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame
150// sizes when the client view does not specify any size constraints.
151TEST_F(CustomFrameViewAshTest, NoSizeConstraints) {
152  TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate;
153  scoped_ptr<views::Widget> widget(CreateWidget(delegate));
154
155  CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view();
156  gfx::Size min_frame_size = custom_frame_view->GetMinimumSize();
157  gfx::Size max_frame_size = custom_frame_view->GetMaximumSize();
158
159  EXPECT_EQ(delegate->GetTitleBarHeight(), min_frame_size.height());
160
161  // A width and height constraint of 0 denotes unbounded.
162  EXPECT_EQ(0, max_frame_size.width());
163  EXPECT_EQ(0, max_frame_size.height());
164}
165
166// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame
167// sizes when the client view specifies size constraints.
168TEST_F(CustomFrameViewAshTest, MinimumAndMaximumSize) {
169  gfx::Size min_client_size(500, 500);
170  gfx::Size max_client_size(800, 800);
171  TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate;
172  delegate->set_minimum_size(min_client_size);
173  delegate->set_maximum_size(max_client_size);
174  scoped_ptr<views::Widget> widget(CreateWidget(delegate));
175
176  CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view();
177  gfx::Size min_frame_size = custom_frame_view->GetMinimumSize();
178  gfx::Size max_frame_size = custom_frame_view->GetMaximumSize();
179
180  EXPECT_EQ(min_client_size.width(), min_frame_size.width());
181  EXPECT_EQ(max_client_size.width(), max_frame_size.width());
182  EXPECT_EQ(min_client_size.height() + delegate->GetTitleBarHeight(),
183            min_frame_size.height());
184  EXPECT_EQ(max_client_size.height() + delegate->GetTitleBarHeight(),
185            max_frame_size.height());
186}
187
188// Verify that CustomFrameViewAsh updates the avatar icon based on the
189// state of the SessionStateDelegate after visibility change.
190TEST_F(CustomFrameViewAshTest, AvatarIcon) {
191  TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate;
192  scoped_ptr<views::Widget> widget(CreateWidget(delegate));
193
194  CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view();
195  EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest());
196
197  // Avatar image becomes available.
198  const gfx::ImageSkia user_image =
199      *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
200          IDR_AURA_UBER_TRAY_GUEST_ICON);
201  GetTestSessionStateDelegate()->SetUserImage(user_image);
202  widget->Hide();
203  widget->Show();
204  EXPECT_TRUE(custom_frame_view->GetAvatarIconViewForTest());
205
206  // Avatar image is gone; the ImageView for the avatar icon should be
207  // removed.
208  GetTestSessionStateDelegate()->SetUserImage(gfx::ImageSkia());
209  widget->Hide();
210  widget->Show();
211  EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest());
212}
213
214// The visibility of the size button is updated when maximize mode is toggled.
215// Verify that the layout of the HeaderView is updated for the size button's
216// new visibility.
217TEST_F(CustomFrameViewAshTest, HeaderViewNotifiedOfChildSizeChange) {
218  TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate;
219  scoped_ptr<views::Widget> widget(CreateWidget(delegate));
220
221  const gfx::Rect initial = delegate->
222      GetFrameCaptionButtonContainerViewBounds();
223  Shell::GetInstance()->maximize_mode_controller()->
224      EnableMaximizeModeWindowManager(true);
225  delegate->EndFrameCaptionButtonContainerViewAnimations();
226  const gfx::Rect maximize_mode_bounds = delegate->
227      GetFrameCaptionButtonContainerViewBounds();
228  EXPECT_GT(initial.width(), maximize_mode_bounds.width());
229  Shell::GetInstance()->maximize_mode_controller()->
230      EnableMaximizeModeWindowManager(false);
231  delegate->EndFrameCaptionButtonContainerViewAnimations();
232  const gfx::Rect after_restore = delegate->
233      GetFrameCaptionButtonContainerViewBounds();
234  EXPECT_EQ(initial, after_restore);
235}
236
237}  // namespace ash
238