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 "ash/wm/caption_buttons/frame_caption_button_container_view.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/test/ash_test_base.h" 9 #include "ash/wm/caption_buttons/frame_caption_button.h" 10 #include "base/command_line.h" 11 #include "grit/ash_resources.h" 12 #include "ui/aura/root_window.h" 13 #include "ui/base/resource/resource_bundle.h" 14 #include "ui/views/border.h" 15 #include "ui/views/widget/widget.h" 16 #include "ui/views/widget/widget_delegate.h" 17 18 namespace ash { 19 20 namespace { 21 22 class TestWidgetDelegate : public views::WidgetDelegateView { 23 public: 24 TestWidgetDelegate(bool can_maximize) : can_maximize_(can_maximize) { 25 } 26 virtual ~TestWidgetDelegate() { 27 } 28 29 virtual bool CanMaximize() const OVERRIDE { 30 return can_maximize_; 31 } 32 33 private: 34 bool can_maximize_; 35 36 DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); 37 }; 38 39 } // namespace 40 41 class FrameCaptionButtonContainerViewTest : public ash::test::AshTestBase { 42 public: 43 enum MaximizeAllowed { 44 MAXIMIZE_ALLOWED, 45 MAXIMIZE_DISALLOWED 46 }; 47 48 FrameCaptionButtonContainerViewTest() { 49 } 50 51 virtual ~FrameCaptionButtonContainerViewTest() { 52 } 53 54 // Creates a widget which allows maximizing based on |maximize_allowed|. 55 // The caller takes ownership of the returned widget. 56 views::Widget* CreateTestWidget( 57 MaximizeAllowed maximize_allowed) WARN_UNUSED_RESULT { 58 views::Widget* widget = new views::Widget; 59 views::Widget::InitParams params; 60 params.delegate = new TestWidgetDelegate( 61 maximize_allowed == MAXIMIZE_ALLOWED); 62 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 63 params.context = CurrentContext(); 64 widget->Init(params); 65 return widget; 66 } 67 68 // Tests that |leftmost| and |rightmost| are at |container|'s edges. 69 bool CheckButtonsAtEdges(FrameCaptionButtonContainerView* container, 70 const ash::FrameCaptionButton& leftmost, 71 const ash::FrameCaptionButton& rightmost) { 72 gfx::Rect expected(container->GetPreferredSize()); 73 74 gfx::Rect container_size(container->GetPreferredSize()); 75 if (leftmost.y() == rightmost.y() && 76 leftmost.height() == rightmost.height() && 77 leftmost.x() == expected.x() && 78 leftmost.y() == expected.y() && 79 leftmost.height() == expected.height() && 80 rightmost.bounds().right() == expected.right()) { 81 return true; 82 } 83 84 LOG(ERROR) << "Buttons " << leftmost.bounds().ToString() << " " 85 << rightmost.bounds().ToString() << " not at edges of " 86 << expected.ToString(); 87 return false; 88 } 89 90 // Returns true if the images for |button|'s states match the passed in ids. 91 bool ImagesMatch(ash::FrameCaptionButton* button, 92 int normal_image_id, 93 int hovered_image_id, 94 int pressed_image_id) { 95 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 96 gfx::ImageSkia* normal = rb.GetImageSkiaNamed(normal_image_id); 97 gfx::ImageSkia* hovered = rb.GetImageSkiaNamed(hovered_image_id); 98 gfx::ImageSkia* pressed = rb.GetImageSkiaNamed(pressed_image_id); 99 using views::Button; 100 gfx::ImageSkia actual_normal = button->GetImage(Button::STATE_NORMAL); 101 gfx::ImageSkia actual_hovered = button->GetImage(Button::STATE_HOVERED); 102 gfx::ImageSkia actual_pressed = button->GetImage(Button::STATE_PRESSED); 103 return actual_normal.BackedBySameObjectAs(*normal) && 104 actual_hovered.BackedBySameObjectAs(*hovered) && 105 actual_pressed.BackedBySameObjectAs(*pressed); 106 } 107 108 private: 109 DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTest); 110 }; 111 112 class FrameCaptionButtonContainerViewTestOldStyle 113 : public FrameCaptionButtonContainerViewTest { 114 public: 115 FrameCaptionButtonContainerViewTestOldStyle() { 116 } 117 118 virtual ~FrameCaptionButtonContainerViewTestOldStyle() { 119 } 120 121 virtual void SetUp() OVERRIDE { 122 FrameCaptionButtonContainerViewTest::SetUp(); 123 CommandLine::ForCurrentProcess()->AppendSwitch( 124 switches::kAshDisableAlternateFrameCaptionButtonStyle); 125 } 126 127 private: 128 DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTestOldStyle); 129 }; 130 131 // Test how the allowed actions affect which caption buttons are visible. 132 TEST_F(FrameCaptionButtonContainerViewTestOldStyle, ButtonVisibility) { 133 // The minimize button should be hidden when both minimizing and maximizing 134 // are allowed because the size button can do both. 135 scoped_ptr<views::Widget> widget_can_maximize( 136 CreateTestWidget(MAXIMIZE_ALLOWED)); 137 FrameCaptionButtonContainerView container1(widget_can_maximize.get(), 138 FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); 139 container1.Layout(); 140 FrameCaptionButtonContainerView::TestApi t1(&container1); 141 EXPECT_FALSE(t1.minimize_button()->visible()); 142 EXPECT_TRUE(t1.size_button()->visible()); 143 EXPECT_TRUE(t1.close_button()->visible()); 144 EXPECT_TRUE(CheckButtonsAtEdges( 145 &container1, *t1.size_button(), *t1.close_button())); 146 147 // The minimize button should be visible when minimizing is allowed but 148 // maximizing is disallowed. 149 scoped_ptr<views::Widget> widget_cannot_maximize( 150 CreateTestWidget(MAXIMIZE_DISALLOWED)); 151 FrameCaptionButtonContainerView container2(widget_cannot_maximize.get(), 152 FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); 153 container2.Layout(); 154 FrameCaptionButtonContainerView::TestApi t2(&container2); 155 EXPECT_TRUE(t2.minimize_button()->visible()); 156 EXPECT_FALSE(t2.size_button()->visible()); 157 EXPECT_TRUE(t2.close_button()->visible()); 158 EXPECT_TRUE(CheckButtonsAtEdges( 159 &container2, *t2.minimize_button(), *t2.close_button())); 160 161 // Neither the minimize button nor the size button should be visible when 162 // neither minimizing nor maximizing are allowed. 163 FrameCaptionButtonContainerView container3(widget_cannot_maximize.get(), 164 FrameCaptionButtonContainerView::MINIMIZE_DISALLOWED); 165 container3.Layout(); 166 FrameCaptionButtonContainerView::TestApi t3(&container3); 167 EXPECT_FALSE(t3.minimize_button()->visible()); 168 EXPECT_FALSE(t3.size_button()->visible()); 169 EXPECT_TRUE(t3.close_button()->visible()); 170 EXPECT_TRUE(CheckButtonsAtEdges( 171 &container3, *t3.close_button(), *t3.close_button())); 172 } 173 174 // Test how the header style affects which images are used for the buttons. 175 TEST_F(FrameCaptionButtonContainerViewTestOldStyle, HeaderStyle) { 176 scoped_ptr<views::Widget> widget(CreateTestWidget(MAXIMIZE_ALLOWED)); 177 FrameCaptionButtonContainerView container(widget.get(), 178 FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); 179 FrameCaptionButtonContainerView::TestApi t(&container); 180 181 // Tall header style. 182 container.set_header_style( 183 FrameCaptionButtonContainerView::HEADER_STYLE_TALL); 184 container.Layout(); 185 EXPECT_TRUE(ImagesMatch(t.size_button(), 186 IDR_AURA_WINDOW_MAXIMIZE, 187 IDR_AURA_WINDOW_MAXIMIZE_H, 188 IDR_AURA_WINDOW_MAXIMIZE_P)); 189 EXPECT_TRUE(ImagesMatch(t.close_button(), 190 IDR_AURA_WINDOW_CLOSE, 191 IDR_AURA_WINDOW_CLOSE_H, 192 IDR_AURA_WINDOW_CLOSE_P)); 193 194 // Short header style. 195 container.set_header_style( 196 FrameCaptionButtonContainerView::HEADER_STYLE_SHORT); 197 container.Layout(); 198 EXPECT_TRUE(ImagesMatch(t.size_button(), 199 IDR_AURA_WINDOW_MAXIMIZED_RESTORE, 200 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H, 201 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P)); 202 EXPECT_TRUE(ImagesMatch(t.close_button(), 203 IDR_AURA_WINDOW_MAXIMIZED_CLOSE, 204 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H, 205 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P)); 206 207 // Maximized short header style. 208 widget->Maximize(); 209 container.Layout(); 210 EXPECT_TRUE(ImagesMatch(t.size_button(), 211 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2, 212 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H, 213 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P)); 214 EXPECT_TRUE(ImagesMatch(t.close_button(), 215 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2, 216 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H, 217 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P)); 218 219 // The buttons are visible during a reveal of the top-of-window views in 220 // immersive fullscreen. They should use the same images as maximized. 221 widget->SetFullscreen(true); 222 container.Layout(); 223 EXPECT_TRUE(ImagesMatch(t.size_button(), 224 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2, 225 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H, 226 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P)); 227 EXPECT_TRUE(ImagesMatch(t.close_button(), 228 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2, 229 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H, 230 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P)); 231 } 232 233 class FrameCaptionButtonContainerViewTestAlternateStyle 234 : public FrameCaptionButtonContainerViewTest { 235 public: 236 FrameCaptionButtonContainerViewTestAlternateStyle() { 237 } 238 239 virtual ~FrameCaptionButtonContainerViewTestAlternateStyle() { 240 } 241 242 virtual void SetUp() OVERRIDE { 243 FrameCaptionButtonContainerViewTest::SetUp(); 244 CommandLine::ForCurrentProcess()->AppendSwitch( 245 switches::kAshEnableAlternateFrameCaptionButtonStyle); 246 } 247 248 private: 249 DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTestAlternateStyle); 250 }; 251 252 // Test how the alternate button style affects which buttons are visible in the 253 // default case. 254 TEST_F(FrameCaptionButtonContainerViewTestAlternateStyle, ButtonVisibility) { 255 // Using the alternate caption button style is dependant on all snapped 256 // windows being 50% of the screen's width. 257 if (!switches::UseAlternateFrameCaptionButtonStyle()) 258 return; 259 260 // Both the minimize button and the maximize button should be visible when 261 // both minimizing and maximizing are allowed when using the alternate 262 // button style. 263 scoped_ptr<views::Widget> widget_can_maximize( 264 CreateTestWidget(MAXIMIZE_ALLOWED)); 265 FrameCaptionButtonContainerView container(widget_can_maximize.get(), 266 FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); 267 container.Layout(); 268 FrameCaptionButtonContainerView::TestApi t(&container); 269 EXPECT_TRUE(t.minimize_button()->visible()); 270 EXPECT_TRUE(t.size_button()->visible()); 271 EXPECT_TRUE(t.close_button()->visible()); 272 EXPECT_TRUE(CheckButtonsAtEdges( 273 &container, *t.minimize_button(), *t.close_button())); 274 } 275 276 } // namespace ash 277