// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/frame/custom_frame_view_ash.h" #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_session_state_delegate.h" #include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/memory/scoped_ptr.h" #include "grit/ash_resources.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" namespace ash { // A views::WidgetDelegate which uses a CustomFrameViewAsh. class TestWidgetDelegate : public views::WidgetDelegateView { public: TestWidgetDelegate() {} ~TestWidgetDelegate() override {} views::NonClientFrameView* CreateNonClientFrameView( views::Widget* widget) override { custom_frame_view_ = new CustomFrameViewAsh(widget); return custom_frame_view_; } CustomFrameViewAsh* custom_frame_view() const { return custom_frame_view_; } private: // Not owned. CustomFrameViewAsh* custom_frame_view_; DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); }; class TestWidgetConstraintsDelegate : public TestWidgetDelegate { public: TestWidgetConstraintsDelegate() {} ~TestWidgetConstraintsDelegate() override {} // views::View: gfx::Size GetMinimumSize() const override { return minimum_size_; } gfx::Size GetMaximumSize() const override { return maximum_size_; } views::View* GetContentsView() override { // Set this instance as the contents view so that the maximum and minimum // size constraints will be used. return this; } // views::WidgetDelegate: bool CanMaximize() const override { return true; } bool CanMinimize() const override { return true; } void set_minimum_size(const gfx::Size& min_size) { minimum_size_ = min_size; } void set_maximum_size(const gfx::Size& max_size) { maximum_size_ = max_size; } const gfx::Rect& GetFrameCaptionButtonContainerViewBounds() { return custom_frame_view()->GetFrameCaptionButtonContainerViewForTest()-> bounds(); } void EndFrameCaptionButtonContainerViewAnimations() { FrameCaptionButtonContainerView::TestApi test(custom_frame_view()-> GetFrameCaptionButtonContainerViewForTest()); test.EndAnimations(); } int GetTitleBarHeight() const { return custom_frame_view()->NonClientTopBorderHeight(); } private: gfx::Size minimum_size_; gfx::Size maximum_size_; DISALLOW_COPY_AND_ASSIGN(TestWidgetConstraintsDelegate); }; class CustomFrameViewAshTest : public test::AshTestBase { public: CustomFrameViewAshTest() {} ~CustomFrameViewAshTest() override {} protected: scoped_ptr CreateWidget(TestWidgetDelegate* delegate) { scoped_ptr widget(new views::Widget); views::Widget::InitParams params; params.delegate = delegate; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 100, 100); params.context = CurrentContext(); widget->Init(params); return widget.Pass(); } test::TestSessionStateDelegate* GetTestSessionStateDelegate() { return static_cast( Shell::GetInstance()->session_state_delegate()); } private: DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest); }; // Test that the height of the header is correct upon initially displaying // the widget. TEST_F(CustomFrameViewAshTest, HeaderHeight) { TestWidgetDelegate* delegate = new TestWidgetDelegate; scoped_ptr widget(CreateWidget(delegate)); widget->Show(); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); gfx::ImageSkia* close_button = rb.GetImageSkiaNamed(IDR_AURA_WINDOW_CONTROL_BACKGROUND_H); // The header should have enough room for the window controls. The // header/content separator line overlays the window controls. EXPECT_EQ(close_button->height(), delegate->custom_frame_view()->GetHeaderView()->height()); } // Verify that CustomFrameViewAsh returns the correct minimum and maximum frame // sizes when the client view does not specify any size constraints. TEST_F(CustomFrameViewAshTest, NoSizeConstraints) { TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; scoped_ptr widget(CreateWidget(delegate)); CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); EXPECT_EQ(delegate->GetTitleBarHeight(), min_frame_size.height()); // A width and height constraint of 0 denotes unbounded. EXPECT_EQ(0, max_frame_size.width()); EXPECT_EQ(0, max_frame_size.height()); } // Verify that CustomFrameViewAsh returns the correct minimum and maximum frame // sizes when the client view specifies size constraints. TEST_F(CustomFrameViewAshTest, MinimumAndMaximumSize) { gfx::Size min_client_size(500, 500); gfx::Size max_client_size(800, 800); TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; delegate->set_minimum_size(min_client_size); delegate->set_maximum_size(max_client_size); scoped_ptr widget(CreateWidget(delegate)); CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); EXPECT_EQ(min_client_size.width(), min_frame_size.width()); EXPECT_EQ(max_client_size.width(), max_frame_size.width()); EXPECT_EQ(min_client_size.height() + delegate->GetTitleBarHeight(), min_frame_size.height()); EXPECT_EQ(max_client_size.height() + delegate->GetTitleBarHeight(), max_frame_size.height()); } // Verify that CustomFrameViewAsh updates the avatar icon based on the // state of the SessionStateDelegate after visibility change. TEST_F(CustomFrameViewAshTest, AvatarIcon) { TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; scoped_ptr widget(CreateWidget(delegate)); CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); // Avatar image becomes available. const gfx::ImageSkia user_image = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_AURA_UBER_TRAY_GUEST_ICON); GetTestSessionStateDelegate()->SetUserImage(user_image); widget->Hide(); widget->Show(); EXPECT_TRUE(custom_frame_view->GetAvatarIconViewForTest()); // Avatar image is gone; the ImageView for the avatar icon should be // removed. GetTestSessionStateDelegate()->SetUserImage(gfx::ImageSkia()); widget->Hide(); widget->Show(); EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); } // The visibility of the size button is updated when maximize mode is toggled. // Verify that the layout of the HeaderView is updated for the size button's // new visibility. TEST_F(CustomFrameViewAshTest, HeaderViewNotifiedOfChildSizeChange) { TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; scoped_ptr widget(CreateWidget(delegate)); const gfx::Rect initial = delegate-> GetFrameCaptionButtonContainerViewBounds(); Shell::GetInstance()->maximize_mode_controller()-> EnableMaximizeModeWindowManager(true); delegate->EndFrameCaptionButtonContainerViewAnimations(); const gfx::Rect maximize_mode_bounds = delegate-> GetFrameCaptionButtonContainerViewBounds(); EXPECT_GT(initial.width(), maximize_mode_bounds.width()); Shell::GetInstance()->maximize_mode_controller()-> EnableMaximizeModeWindowManager(false); delegate->EndFrameCaptionButtonContainerViewAnimations(); const gfx::Rect after_restore = delegate-> GetFrameCaptionButtonContainerViewBounds(); EXPECT_EQ(initial, after_restore); } } // namespace ash