blob: 988d32f635e9fa3c6b5ee957845d1d18ad256fb4 [file] [log] [blame]
// Copyright (c) 2019 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/shelf/scrollable_shelf_view.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/shelf/shelf_test_util.h"
#include "ash/shelf/shelf_tooltip_manager.h"
#include "ash/shelf/shelf_view_test_api.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/test/ash_test_base.h"
#include "chromeos/constants/chromeos_switches.h"
#include "ui/display/manager/display_manager.h"
namespace ash {
class TestShelfItemDelegate : public ShelfItemDelegate {
public:
explicit TestShelfItemDelegate(const ShelfID& shelf_id)
: ShelfItemDelegate(shelf_id) {}
// ShelfItemDelegate:
void ItemSelected(std::unique_ptr<ui::Event> event,
int64_t display_id,
ash::ShelfLaunchSource source,
ItemSelectedCallback callback) override {
std::move(callback).Run(SHELF_ACTION_WINDOW_ACTIVATED, {});
}
void ExecuteCommand(bool from_context_menu,
int64_t command_id,
int32_t event_flags,
int64_t display_id) override {}
void Close() override {}
};
class ScrollableShelfViewTest : public AshTestBase {
public:
ScrollableShelfViewTest() = default;
~ScrollableShelfViewTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
scrollable_shelf_view_ = GetPrimaryShelf()
->shelf_widget()
->hotseat_widget()
->scrollable_shelf_view();
shelf_view_ = scrollable_shelf_view_->shelf_view();
test_api_ = std::make_unique<ShelfViewTestAPI>(
scrollable_shelf_view_->shelf_view());
}
protected:
ShelfID AddAppShortcut() {
ShelfItem item = ShelfTestUtil::AddAppShortcut(base::NumberToString(id_++),
TYPE_PINNED_APP);
// Wait for shelf view's bounds animation to end. Otherwise the scrollable
// shelf's bounds are not updated yet.
test_api_->RunMessageLoopUntilAnimationsDone();
return item.id;
}
void AddAppShortcutUntilOverflow() {
while (scrollable_shelf_view_->layout_strategy_for_test() ==
ScrollableShelfView::kNotShowArrowButtons)
AddAppShortcut();
}
ScrollableShelfView* scrollable_shelf_view_ = nullptr;
ShelfView* shelf_view_ = nullptr;
std::unique_ptr<ShelfViewTestAPI> test_api_;
int id_ = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ScrollableShelfViewTest);
};
// Verifies that the display rotation from the short side to the long side
// should not break the scrollable shelf's UI
// behavior(https://crbug.com/1000764).
TEST_F(ScrollableShelfViewTest, CorrectUIAfterDisplayRotationShortToLong) {
// Changes the display setting in order that the display's height is greater
// than the width.
UpdateDisplay("600x800");
display::Display display = GetPrimaryDisplay();
// Adds enough app icons so that after display rotation the scrollable
// shelf is still in overflow mode.
const int num = display.bounds().height() / ShelfConfig::Get()->button_size();
for (int i = 0; i < num; i++)
AddAppShortcut();
// Because the display's height is greater than the display's width,
// the scrollable shelf is in overflow mode before display rotation.
ASSERT_EQ(ScrollableShelfView::kShowRightArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
// Presses the right arrow until reaching the last page of shelf icons.
const views::View* right_arrow = scrollable_shelf_view_->right_arrow();
const gfx::Point center_point =
right_arrow->GetBoundsInScreen().CenterPoint();
while (right_arrow->GetVisible()) {
GetEventGenerator()->MoveMouseTo(center_point);
GetEventGenerator()->PressLeftButton();
GetEventGenerator()->ReleaseLeftButton();
}
ASSERT_EQ(ScrollableShelfView::kShowLeftArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
// Rotates the display by 90 degrees.
display::DisplayManager* display_manager = Shell::Get()->display_manager();
display_manager->SetDisplayRotation(display.id(), display::Display::ROTATE_90,
display::Display::RotationSource::ACTIVE);
// After rotation, checks the following things:
// (1) The scrollable shelf has the correct layout strategy.
// (2) The last app icon has the correct bounds.
// (3) The scrollable shelf does not need further adjustment.
EXPECT_EQ(ScrollableShelfView::kShowLeftArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
views::ViewModel* view_model = shelf_view_->view_model();
const views::View* last_visible_icon =
view_model->view_at(scrollable_shelf_view_->last_tappable_app_index());
const gfx::Rect icon_bounds = last_visible_icon->GetBoundsInScreen();
const gfx::Rect shelf_container_bounds =
scrollable_shelf_view_->shelf_container_view()->GetBoundsInScreen();
EXPECT_EQ(icon_bounds.right() +
ShelfConfig::Get()->scrollable_shelf_ripple_padding(),
shelf_container_bounds.right());
EXPECT_FALSE(scrollable_shelf_view_->ShouldAdjustForTest());
}
// Verifies that the display rotation from the long side to the short side
// should not break the scrollable shelf's UI behavior
// (https://crbug.com/1000764).
TEST_F(ScrollableShelfViewTest, CorrectUIAfterDisplayRotationLongToShort) {
// Changes the display setting in order that the display's width is greater
// than the height.
UpdateDisplay("600x300");
display::Display display = GetPrimaryDisplay();
AddAppShortcutUntilOverflow();
// Presses the right arrow until reaching the last page of shelf icons.
const views::View* right_arrow = scrollable_shelf_view_->right_arrow();
const gfx::Point center_point =
right_arrow->GetBoundsInScreen().CenterPoint();
while (right_arrow->GetVisible()) {
GetEventGenerator()->MoveMouseTo(center_point);
GetEventGenerator()->PressLeftButton();
GetEventGenerator()->ReleaseLeftButton();
}
ASSERT_EQ(ScrollableShelfView::kShowLeftArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
// Rotates the display by 90 degrees. In order to reproduce the bug,
// both arrow buttons should show after rotation.
display::DisplayManager* display_manager = Shell::Get()->display_manager();
display_manager->SetDisplayRotation(display.id(), display::Display::ROTATE_90,
display::Display::RotationSource::ACTIVE);
ASSERT_EQ(ScrollableShelfView::kShowButtons,
scrollable_shelf_view_->layout_strategy_for_test());
// Verifies that the scrollable shelf does not need further adjustment.
EXPECT_FALSE(scrollable_shelf_view_->ShouldAdjustForTest());
}
// When hovering mouse on a shelf icon, the tooltip only shows for the visible
// icon (see https://crbug.com/997807).
TEST_F(ScrollableShelfViewTest, NotShowTooltipForHiddenIcons) {
AddAppShortcutUntilOverflow();
ASSERT_EQ(ScrollableShelfView::kShowRightArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
scrollable_shelf_view_->first_tappable_app_index();
views::ViewModel* view_model = shelf_view_->view_model();
// Check the initial state of |tooltip_manager|.
ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager();
EXPECT_FALSE(tooltip_manager->IsVisible());
// Verifies that tooltip should show for a visible shelf item.
views::View* visible_icon =
view_model->view_at(scrollable_shelf_view_->first_tappable_app_index());
GetEventGenerator()->MoveMouseTo(
visible_icon->GetBoundsInScreen().CenterPoint());
tooltip_manager->ShowTooltip(visible_icon);
EXPECT_TRUE(tooltip_manager->IsVisible());
// Reset |tooltip_manager|.
GetEventGenerator()->MoveMouseTo(gfx::Point());
tooltip_manager->Close();
EXPECT_FALSE(tooltip_manager->IsVisible());
// Verifies that tooltip should not show for a hidden shelf item.
views::View* hidden_icon = view_model->view_at(
scrollable_shelf_view_->last_tappable_app_index() + 1);
GetEventGenerator()->MoveMouseTo(
hidden_icon->GetBoundsInScreen().CenterPoint());
tooltip_manager->ShowTooltip(hidden_icon);
EXPECT_FALSE(tooltip_manager->IsVisible());
}
// Test that tapping near the scroll arrow button triggers scrolling. (see
// https://crbug.com/1004998)
TEST_F(ScrollableShelfViewTest, ScrollAfterTappingNearScrollArrow) {
AddAppShortcutUntilOverflow();
ASSERT_EQ(ScrollableShelfView::kShowRightArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
// Tap right arrow and check that the scrollable shelf now shows the left
// arrow only. Then do the same for the left arrow.
const gfx::Rect right_arrow =
scrollable_shelf_view_->right_arrow()->GetBoundsInScreen();
GetEventGenerator()->GestureTapAt(right_arrow.CenterPoint());
ASSERT_EQ(ScrollableShelfView::kShowLeftArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
const gfx::Rect left_arrow =
scrollable_shelf_view_->left_arrow()->GetBoundsInScreen();
GetEventGenerator()->GestureTapAt(left_arrow.CenterPoint());
ASSERT_EQ(ScrollableShelfView::kShowRightArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
// Recalculate the right arrow bounds considering the padding for the tap
// area.
const int horizontalPadding = (32 - right_arrow.width()) / 2;
const int verticalPadding =
(ShelfConfig::Get()->button_size() - right_arrow.height()) / 2;
// Tap near the right arrow and check that the scrollable shelf now shows the
// left arrow only. Then do the same for the left arrow.
GetEventGenerator()->GestureTapAt(
gfx::Point(right_arrow.top_right().x() - horizontalPadding,
right_arrow.top_right().y() + verticalPadding));
ASSERT_EQ(ScrollableShelfView::kShowLeftArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
GetEventGenerator()->GestureTapAt(
gfx::Point(left_arrow.top_right().x(), left_arrow.top_right().y()));
EXPECT_EQ(ScrollableShelfView::kShowRightArrowButton,
scrollable_shelf_view_->layout_strategy_for_test());
}
} // namespace ash