Commit bd59c164 authored by Andrew Xu's avatar Andrew Xu Committed by Commit Bot

part 4 of the arrow button implementation

This CL is the forth part of code to implement the arrow button in
the overflow bubble view.
See more details from the below doc link:
https://docs.google.com/document/d/1dO4H_4T6ttWFc75nCNi2Uh18k-3_M8-eOHcfMTcNwd0/edit?usp=sharing

Bug: 918024
Change-Id: I2ee940845c61a52e1250487c8dce1e942759adb9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1703268
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Reviewed-by: default avatarMitsuru Oshima (Slow - traveling) <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683031}
parent ae360e2d
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_mask.h" #include "ui/views/animation/ink_drop_mask.h"
#include "ui/views/animation/ink_drop_painted_layer_delegates.h" #include "ui/views/animation/ink_drop_painted_layer_delegates.h"
#include "ui/views/view_model.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace ash { namespace ash {
...@@ -51,6 +52,10 @@ int GetGestureDragTheshold() { ...@@ -51,6 +52,10 @@ int GetGestureDragTheshold() {
return ShelfConstants::button_size() / 2; return ShelfConstants::button_size() / 2;
} }
int GetBubbleCornerRadius() {
return ShelfConstants::button_size() / 2;
}
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -156,7 +161,8 @@ OverflowBubbleView::ScrollArrowView::CreateInkDropRipple() const { ...@@ -156,7 +161,8 @@ OverflowBubbleView::ScrollArrowView::CreateInkDropRipple() const {
class OverflowBubbleView::OverflowShelfContainerView : public views::View { class OverflowBubbleView::OverflowShelfContainerView : public views::View {
public: public:
explicit OverflowShelfContainerView(ShelfView* shelf_view); OverflowShelfContainerView(ShelfView* shelf_view,
OverflowBubbleView* bubble_view);
~OverflowShelfContainerView() override = default; ~OverflowShelfContainerView() override = default;
void Initialize(); void Initialize();
...@@ -164,22 +170,47 @@ class OverflowBubbleView::OverflowShelfContainerView : public views::View { ...@@ -164,22 +170,47 @@ class OverflowBubbleView::OverflowShelfContainerView : public views::View {
// Translate |shelf_view_| by |offset|. // Translate |shelf_view_| by |offset|.
void TranslateShelfView(const gfx::Vector2dF& offset); void TranslateShelfView(const gfx::Vector2dF& offset);
// Update the shelf icons' opacity.
void UpdateShelfIconsOpacity();
// views::View: // views::View:
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
void ChildPreferredSizeChanged(views::View* child) override; void ChildPreferredSizeChanged(views::View* child) override;
void Layout() override; void Layout() override;
const char* GetClassName() const override; const char* GetClassName() const override;
int first_visible_index() const { return first_visible_index_; }
int last_visible_index() const { return last_visible_index_; }
private: private:
// Update the opacity of shelf icons on both edges based on the drag offset.
void UpdateOpacityOfEdgeIcons(int offset_distance);
// Set all of shelf icons within the bounds of the shelf container view to be
// fully opaque.
void ShowShelfIconsWithinBounds();
// Owned by views hierarchy. // Owned by views hierarchy.
ShelfView* shelf_view_; ShelfView* shelf_view_;
// Parent view. Not owned.
OverflowBubbleView* bubble_view_;
// The index of the leftmost/rightmost shelf icon within the bounds of
// |shelf_container_view_|. Different from the |first_visible_index_| or
// |last_visible_index_| in ShelfView which specifies the range of shelf icons
// belonging to the shelf view, the two attributes in OverflowBubbleView
// indicate the shelf icons not hidden by the parent view.
int first_visible_index_ = -1;
int last_visible_index_ = -1;
DISALLOW_COPY_AND_ASSIGN(OverflowShelfContainerView); DISALLOW_COPY_AND_ASSIGN(OverflowShelfContainerView);
}; };
OverflowBubbleView::OverflowShelfContainerView::OverflowShelfContainerView( OverflowBubbleView::OverflowShelfContainerView::OverflowShelfContainerView(
ShelfView* shelf_view) ShelfView* shelf_view,
: shelf_view_(shelf_view) {} OverflowBubbleView* bubble_view)
: shelf_view_(shelf_view), bubble_view_(bubble_view) {}
void OverflowBubbleView::OverflowShelfContainerView::Initialize() { void OverflowBubbleView::OverflowShelfContainerView::Initialize() {
SetPaintToLayer(); SetPaintToLayer();
...@@ -218,6 +249,79 @@ void OverflowBubbleView::OverflowShelfContainerView::TranslateShelfView( ...@@ -218,6 +249,79 @@ void OverflowBubbleView::OverflowShelfContainerView::TranslateShelfView(
shelf_view_->SetTransform(transform_matrix); shelf_view_->SetTransform(transform_matrix);
} }
void OverflowBubbleView::OverflowShelfContainerView::UpdateShelfIconsOpacity() {
gfx::Vector2dF scroll_offset = bubble_view_->scroll_offset();
LayoutStrategy layout_strategy = bubble_view_->layout_strategy();
int updated_first_visible_index = shelf_view_->first_visible_index();
if (layout_strategy == NOT_SHOW_ARROW_BUTTONS) {
first_visible_index_ = updated_first_visible_index;
last_visible_index_ = shelf_view_->last_visible_index();
return;
}
const bool is_horizontal_aligned =
shelf_view_->shelf()->IsHorizontalAlignment();
const int scroll_distance =
is_horizontal_aligned ? scroll_offset.x() : scroll_offset.y();
updated_first_visible_index += scroll_distance / GetUnit();
if (layout_strategy == SHOW_LEFT_ARROW_BUTTON ||
layout_strategy == SHOW_BUTTONS) {
updated_first_visible_index++;
}
const int offset = (is_horizontal_aligned ? bubble_view_->bounds().width()
: bubble_view_->bounds().height()) -
2 * GetUnit();
int updated_last_visible_index =
updated_first_visible_index + offset / GetUnit();
if (layout_strategy == SHOW_BUTTONS)
updated_last_visible_index--;
if (updated_first_visible_index != first_visible_index_ ||
updated_last_visible_index != last_visible_index_) {
first_visible_index_ = updated_first_visible_index;
last_visible_index_ = updated_last_visible_index;
ShowShelfIconsWithinBounds();
}
UpdateOpacityOfEdgeIcons(scroll_distance);
}
void OverflowBubbleView::OverflowShelfContainerView::UpdateOpacityOfEdgeIcons(
int offset_distance) {
const int remainder = offset_distance % GetUnit();
const int complement = GetUnit() - remainder;
views::ViewModel* shelf_view_model = shelf_view_->view_model();
// Calculate the opacity of the leftmost visible shelf icon.
views::View* leftmost_view = shelf_view_model->view_at(first_visible_index_);
leftmost_view->layer()->SetOpacity(
remainder >= kFadingZone ? 0 : (1.0f - remainder / (float)kFadingZone));
// Instead of the shelf icon denoted by |last_visible_index_|, we should
// update the opacity of the icon right after if any. Because
// |last_visible_index_| is calculated with flooring.
if (last_visible_index_ + 1 < shelf_view_model->view_size()) {
views::View* rightmost_view =
shelf_view_model->view_at(last_visible_index_ + 1);
rightmost_view->layer()->SetOpacity(complement >= kFadingZone
? 0.f
: (kFadingZone - complement) /
(float)(kFadingZone));
}
}
void OverflowBubbleView::OverflowShelfContainerView::
ShowShelfIconsWithinBounds() {
for (int i = first_visible_index_; i <= last_visible_index_; i++) {
views::View* shelf_icon = shelf_view_->view_model()->view_at(i);
shelf_icon->layer()->SetOpacity(1);
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// OverflowBubbleView // OverflowBubbleView
...@@ -241,6 +345,8 @@ OverflowBubbleView::OverflowBubbleView(ShelfView* shelf_view, ...@@ -241,6 +345,8 @@ OverflowBubbleView::OverflowBubbleView(ShelfView* shelf_view,
SetPaintToLayer(); SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false); layer()->SetFillsBoundsOpaquely(false);
layer()->SetMasksToBounds(true); layer()->SetMasksToBounds(true);
layer()->SetRoundedCornerRadius(
gfx::RoundedCornersF(GetBubbleCornerRadius()));
// Initialize the left arrow button. // Initialize the left arrow button.
left_arrow_ = new ScrollArrowView(ScrollArrowView::LEFT, left_arrow_ = new ScrollArrowView(ScrollArrowView::LEFT,
...@@ -253,7 +359,7 @@ OverflowBubbleView::OverflowBubbleView(ShelfView* shelf_view, ...@@ -253,7 +359,7 @@ OverflowBubbleView::OverflowBubbleView(ShelfView* shelf_view,
AddChildView(right_arrow_); AddChildView(right_arrow_);
// Initialize the shelf container view. // Initialize the shelf container view.
shelf_container_view_ = new OverflowShelfContainerView(shelf_view); shelf_container_view_ = new OverflowShelfContainerView(shelf_view, this);
shelf_container_view_->Initialize(); shelf_container_view_->Initialize();
AddChildView(shelf_container_view_); AddChildView(shelf_container_view_);
...@@ -323,6 +429,14 @@ int OverflowBubbleView::ScrollByYOffset(float y_offset, bool animating) { ...@@ -323,6 +429,14 @@ int OverflowBubbleView::ScrollByYOffset(float y_offset, bool animating) {
return diff; return diff;
} }
int OverflowBubbleView::GetFirstVisibleIndexForTest() const {
return shelf_container_view_->first_visible_index();
}
int OverflowBubbleView::GetLastVisibleIndexForTest() const {
return shelf_container_view_->last_visible_index();
}
int OverflowBubbleView::CalculateScrollUpperBound() const { int OverflowBubbleView::CalculateScrollUpperBound() const {
const bool is_horizontal = shelf_->IsHorizontalAlignment(); const bool is_horizontal = shelf_->IsHorizontalAlignment();
...@@ -349,7 +463,7 @@ float OverflowBubbleView::CalculateLayoutStrategyAfterScroll(float scroll) { ...@@ -349,7 +463,7 @@ float OverflowBubbleView::CalculateLayoutStrategyAfterScroll(float scroll) {
const float scroll_upper_bound = const float scroll_upper_bound =
static_cast<float>(CalculateScrollUpperBound()); static_cast<float>(CalculateScrollUpperBound());
scroll = std::min(scroll_upper_bound, std::max(0.f, old_scroll + scroll)); scroll = std::min(scroll_upper_bound, std::max(0.f, old_scroll + scroll));
if (layout_strategy_ != NOT_SHOW_ARROW_BUTTON) { if (layout_strategy_ != NOT_SHOW_ARROW_BUTTONS) {
if (scroll <= 0.f) if (scroll <= 0.f)
layout_strategy_ = SHOW_RIGHT_ARROW_BUTTON; layout_strategy_ = SHOW_RIGHT_ARROW_BUTTON;
else if (scroll >= scroll_upper_bound) else if (scroll >= scroll_upper_bound)
...@@ -362,7 +476,7 @@ float OverflowBubbleView::CalculateLayoutStrategyAfterScroll(float scroll) { ...@@ -362,7 +476,7 @@ float OverflowBubbleView::CalculateLayoutStrategyAfterScroll(float scroll) {
void OverflowBubbleView::AdjustToEnsureIconsFullyVisible( void OverflowBubbleView::AdjustToEnsureIconsFullyVisible(
gfx::Rect* bubble_bounds) const { gfx::Rect* bubble_bounds) const {
if (layout_strategy_ == NOT_SHOW_ARROW_BUTTON) if (layout_strategy_ == NOT_SHOW_ARROW_BUTTONS)
return; return;
int width = shelf_->IsHorizontalAlignment() ? bubble_bounds->width() int width = shelf_->IsHorizontalAlignment() ? bubble_bounds->width()
...@@ -416,7 +530,7 @@ gfx::Size OverflowBubbleView::CalculatePreferredSize() const { ...@@ -416,7 +530,7 @@ gfx::Size OverflowBubbleView::CalculatePreferredSize() const {
if (preferred_length <= available_length) { if (preferred_length <= available_length) {
// Enough space to accommodate all of shelf buttons. So hide arrow buttons. // Enough space to accommodate all of shelf buttons. So hide arrow buttons.
layout_strategy_ = NOT_SHOW_ARROW_BUTTON; layout_strategy_ = NOT_SHOW_ARROW_BUTTONS;
} else if (scroll_length == 0) { } else if (scroll_length == 0) {
// No invisible shelf buttons at the left side. So hide the left button. // No invisible shelf buttons at the left side. So hide the left button.
layout_strategy_ = SHOW_RIGHT_ARROW_BUTTON; layout_strategy_ = SHOW_RIGHT_ARROW_BUTTON;
...@@ -453,14 +567,21 @@ void OverflowBubbleView::Layout() { ...@@ -453,14 +567,21 @@ void OverflowBubbleView::Layout() {
// The bounds of |left_arrow_| and |right_arrow_| in the parent coordinates. // The bounds of |left_arrow_| and |right_arrow_| in the parent coordinates.
gfx::Rect left_arrow_bounds, right_arrow_bounds; gfx::Rect left_arrow_bounds, right_arrow_bounds;
// Widen the shelf container view a little bit to ensure enough space for
// the fading out zone.
const int fading_zone_inset =
std::max(0, kFadingZone - GetDistanceToArrowButton() - kEndPadding);
// Calculates the bounds of the left arrow button. If the left arrow button // Calculates the bounds of the left arrow button. If the left arrow button
// should not show, |left_arrow_bounds| should be empty. // should not show, |left_arrow_bounds| should be empty.
if (layout_strategy_ == SHOW_LEFT_ARROW_BUTTON || if (layout_strategy_ == SHOW_LEFT_ARROW_BUTTON ||
layout_strategy_ == SHOW_BUTTONS) { layout_strategy_ == SHOW_BUTTONS) {
left_arrow_bounds = gfx::Rect(shelf_button_size); left_arrow_bounds = gfx::Rect(shelf_button_size);
left_arrow_bounds.ClampToCenteredSize(arrow_button_size); left_arrow_bounds.ClampToCenteredSize(arrow_button_size);
shelf_container_bounds.Inset( shelf_container_bounds.Inset(ShelfConstants::button_size() +
ShelfConstants::button_size() + GetDistanceToArrowButton(), 0, 0, 0); GetDistanceToArrowButton() -
fading_zone_inset,
0, 0, 0);
} }
if (layout_strategy_ == SHOW_RIGHT_ARROW_BUTTON || if (layout_strategy_ == SHOW_RIGHT_ARROW_BUTTON ||
...@@ -469,7 +590,8 @@ void OverflowBubbleView::Layout() { ...@@ -469,7 +590,8 @@ void OverflowBubbleView::Layout() {
right_arrow_bounds = right_arrow_bounds =
gfx::Rect(shelf_container_bounds.top_right(), shelf_button_size); gfx::Rect(shelf_container_bounds.top_right(), shelf_button_size);
right_arrow_bounds.ClampToCenteredSize(arrow_button_size); right_arrow_bounds.ClampToCenteredSize(arrow_button_size);
shelf_container_bounds.Inset(0, 0, GetDistanceToArrowButton(), 0); shelf_container_bounds.Inset(
0, 0, GetDistanceToArrowButton() - fading_zone_inset, 0);
} }
shelf_container_bounds.Inset(kEndPadding, 0, kEndPadding, 0); shelf_container_bounds.Inset(kEndPadding, 0, kEndPadding, 0);
...@@ -505,6 +627,7 @@ void OverflowBubbleView::Layout() { ...@@ -505,6 +627,7 @@ void OverflowBubbleView::Layout() {
} }
shelf_container_view_->TranslateShelfView(scroll_offset_ + translate_vector); shelf_container_view_->TranslateShelfView(scroll_offset_ + translate_vector);
shelf_container_view_->UpdateShelfIconsOpacity();
} }
void OverflowBubbleView::ChildPreferredSizeChanged(views::View* child) { void OverflowBubbleView::ChildPreferredSizeChanged(views::View* child) {
......
...@@ -23,7 +23,7 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble, ...@@ -23,7 +23,7 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble,
enum LayoutStrategy { enum LayoutStrategy {
// The arrow buttons are not shown. It means that there is enough space to // The arrow buttons are not shown. It means that there is enough space to
// accommodate all of shelf icons. // accommodate all of shelf icons.
NOT_SHOW_ARROW_BUTTON, NOT_SHOW_ARROW_BUTTONS,
// Only the left arrow button is shown. // Only the left arrow button is shown.
SHOW_LEFT_ARROW_BUTTON, SHOW_LEFT_ARROW_BUTTON,
...@@ -52,6 +52,9 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble, ...@@ -52,6 +52,9 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble,
int ScrollByXOffset(float x_offset, bool animating); int ScrollByXOffset(float x_offset, bool animating);
int ScrollByYOffset(float y_offset, bool animating); int ScrollByYOffset(float y_offset, bool animating);
int GetFirstVisibleIndexForTest() const;
int GetLastVisibleIndexForTest() const;
// views::BubbleDialogDelegateView: // views::BubbleDialogDelegateView:
gfx::Rect GetBubbleBounds() override; gfx::Rect GetBubbleBounds() override;
bool CanActivate() const override; bool CanActivate() const override;
...@@ -74,6 +77,8 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble, ...@@ -74,6 +77,8 @@ class ASH_EXPORT OverflowBubbleView : public ShelfBubble,
// Minimum margin around the bubble so that it doesn't hug the screen edges. // Minimum margin around the bubble so that it doesn't hug the screen edges.
static constexpr int kMinimumMargin = 8; static constexpr int kMinimumMargin = 8;
static constexpr int kFadingZone = 16;
private: private:
friend class OverflowBubbleViewTestAPI; friend class OverflowBubbleViewTestAPI;
......
...@@ -1768,207 +1768,6 @@ TEST_F(ShelfViewTest, CheckDragInsertBoundsWithMultiMonitor) { ...@@ -1768,207 +1768,6 @@ TEST_F(ShelfViewTest, CheckDragInsertBoundsWithMultiMonitor) {
EXPECT_FALSE(drag_reinsert_bounds_in_secondary.Contains(point_in_shelf_view)); EXPECT_FALSE(drag_reinsert_bounds_in_secondary.Contains(point_in_shelf_view));
} }
// Verifies that the arrow buttons of OverflowBubbleView work as expected.
TEST_F(ShelfViewTest, CheckOverflowBubbleViewArrowButton) {
UpdateDisplay("300x600");
AddAppShortcutsUntilOverflow();
// Show overflow bubble.
test_api_->ShowOverflowBubble();
ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
const int button_size = ShelfConstants::button_size();
const gfx::Size shelf_icon_size(button_size, button_size);
const int arrow_button_size = OverflowBubbleView::GetArrowButtonSize();
const int bubble_view_min_margin = OverflowBubbleView::kMinimumMargin;
const int end_padding = OverflowBubbleView::kEndPadding;
const int unit = button_size + ShelfConstants::button_spacing();
// Add sufficient app icons to ensure that it needs to press the right arrow
// buttons twice to reach the end.
int current_item_count = bubble_view->shelf_view()->last_visible_index() -
bubble_view->shelf_view()->first_visible_index() + 1;
const int available_width_for_shortcuts =
GetPrimaryDisplay().work_area().width() - 2 * bubble_view_min_margin -
2 * end_padding;
const int max_accommodated_shelf_num =
(available_width_for_shortcuts - arrow_button_size) / unit + 1;
int additional_item_num =
2 * max_accommodated_shelf_num - 1 - current_item_count;
while (additional_item_num) {
AddAppShortcut();
additional_item_num--;
}
const gfx::Rect overflow_bubble_bounds = bubble_view->GetBoundsInScreen();
views::View* left_arrow_button = bubble_view->left_arrow();
views::View* right_arrow_button = bubble_view->right_arrow();
ShelfViewTestAPI test_for_overflow_view(
test_api_->overflow_bubble()->bubble_view()->shelf_view());
// Verifies that the overflow bubble has the correct bounds. In detail:
// (1) The width of the overflow bubble should be the multiple of |unit|.
// (2) The overflow bubble's gap between left and right display edge should
// be the same.
EXPECT_EQ(
overflow_bubble_bounds.origin().x(),
GetPrimaryDisplay().bounds().right() - overflow_bubble_bounds.right());
const int available_width_for_bubble =
GetPrimaryDisplay().bounds().width() - 2 * bubble_view_min_margin;
const int rd = available_width_for_bubble % unit;
EXPECT_EQ(rd / 2 + bubble_view_min_margin,
overflow_bubble_bounds.origin().x());
EXPECT_EQ(0, overflow_bubble_bounds.width() % unit);
// Verifies the following things right after showing the overflow bubble view:
// (1) The layout strategy is SHOW_RIGHT_ARROW_BUTTON.
// (2) The right button is visible.
// (3) The left button is invisible.
// (4) The first visible shelf button has the correct origin.
EXPECT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_TRUE(right_arrow_button->GetVisible());
EXPECT_FALSE(left_arrow_button->GetVisible());
gfx::Rect expected_first_icon_bounds(overflow_bubble_bounds.origin(),
shelf_icon_size);
expected_first_icon_bounds.Offset(end_padding, 0);
EXPECT_EQ(expected_first_icon_bounds,
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->first_visible_index())
->GetBoundsInScreen());
// Taps at the right arrow button.
const gfx::Point right_button_center =
right_arrow_button->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->GestureTapAt(right_button_center);
// Verifies that the layout strategy is SHOW_BUTTONS.
EXPECT_EQ(OverflowBubbleView::SHOW_BUTTONS, bubble_view->layout_strategy());
// Verifies that the right button shows in the expected bounds.
EXPECT_TRUE(right_arrow_button->GetVisible());
gfx::Rect expected_right_arrow_bounds =
gfx::Rect(overflow_bubble_bounds.width() - button_size, 0, button_size,
button_size);
expected_right_arrow_bounds.ClampToCenteredSize(
gfx::Size(arrow_button_size, arrow_button_size));
EXPECT_EQ(expected_right_arrow_bounds, right_arrow_button->bounds());
// Verifies that the left button shows in the expected bounds.
EXPECT_TRUE(left_arrow_button->GetVisible());
gfx::Rect expected_left_arrow_bounds =
gfx::Rect(0, 0, button_size, button_size);
expected_left_arrow_bounds.ClampToCenteredSize(
gfx::Size(arrow_button_size, arrow_button_size));
EXPECT_EQ(expected_left_arrow_bounds, left_arrow_button->bounds());
// Verifies that the scroll offset of the overflow bubble should be expected.
const int expected_scroll_distance =
overflow_bubble_bounds.width() - 2 * unit;
EXPECT_EQ(expected_scroll_distance, bubble_view->scroll_offset().x());
// Tap at the right arrow button. Then check the following things:
// (1) The layout strategy is SHOW_LEFT_ARROW_BUTTON.
// (2) The left button is visible.
// (3) The right button is invisible.
// (4) The last visible shelf button has the expected bounds in screen.
GetEventGenerator()->GestureTapAt(right_button_center);
EXPECT_EQ(OverflowBubbleView::SHOW_LEFT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_FALSE(right_arrow_button->GetVisible());
EXPECT_TRUE(left_arrow_button->GetVisible());
gfx::Rect expected_last_icon_bounds(overflow_bubble_bounds.top_right(),
shelf_icon_size);
expected_last_icon_bounds.Offset(-button_size - end_padding, 0);
EXPECT_EQ(expected_last_icon_bounds,
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->last_visible_index())
->GetBoundsInScreen());
// Tap at the left arrow button twice. Check the following things:
// (1) The layout strategy is SHOW_RIGHT_ARROW_BUTTON.
// (2) The right button is visible.
// (3) The left button is invisible.
const gfx::Point left_button_center =
left_arrow_button->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->GestureTapAt(left_button_center);
GetEventGenerator()->GestureTapAt(left_button_center);
EXPECT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_TRUE(right_arrow_button->GetVisible());
EXPECT_FALSE(left_arrow_button->GetVisible());
}
// Verifies that the overflow bubble view handles the gesture events correctly.
TEST_F(ShelfViewTest, CheckGestureDraggingOverflowBubbleView) {
UpdateDisplay("300x600");
AddAppShortcutsUntilOverflow();
// Show overflow bubble.
test_api_->ShowOverflowBubble();
ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
const int bubble_view_min_margin = OverflowBubbleView::kMinimumMargin;
const int end_padding = OverflowBubbleView::kEndPadding;
const int unit =
ShelfConstants::button_size() + ShelfConstants::button_spacing();
// Calculates the start point of the gesture drag event. Ensures that the
// start point is not within the bounds of any shelf icon.
ShelfViewTestAPI test_for_overflow_view(
test_api_->overflow_bubble()->bubble_view()->shelf_view());
const gfx::Rect first_icon_bounds =
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->first_visible_index())
->GetBoundsInScreen();
gfx::Point gesture_drag_point = first_icon_bounds.right_center();
gesture_drag_point.Offset(1, 0);
// Verifies that gesture dragging is disabled when no arrow button shows.
ASSERT_EQ(OverflowBubbleView::NOT_SHOW_ARROW_BUTTON,
bubble_view->layout_strategy());
gfx::Point gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-ShelfConstants::button_size(), 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 5);
EXPECT_EQ(0, bubble_view->scroll_offset().x());
// Adds enough shelf icons to show the right arrow button.
const int available_width_for_shortcuts =
GetPrimaryDisplay().bounds().width() - 2 * bubble_view_min_margin -
2 * end_padding;
int max_accommodated_shelf_num = (available_width_for_shortcuts -
OverflowBubbleView::GetArrowButtonSize()) /
unit +
1;
while (max_accommodated_shelf_num) {
AddAppShortcut();
max_accommodated_shelf_num--;
}
ASSERT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
// Verifies that the small gesutre offset will not scroll the overflow bubble.
gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-10, 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 1);
EXPECT_EQ(0, bubble_view->scroll_offset().x());
// Verifies that the large gesture offset will scroll the overflow bubble. The
// scroll offset is adjusted to fully show all of shelf icons.
gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-ShelfConstants::button_size(), 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 1);
EXPECT_EQ(unit, bubble_view->scroll_offset().x());
}
// Checks the rip an item off from left aligned shelf in secondary monitor. // Checks the rip an item off from left aligned shelf in secondary monitor.
TEST_F(ShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) { TEST_F(ShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) {
UpdateDisplay("800x600,800x600"); UpdateDisplay("800x600,800x600");
...@@ -2610,6 +2409,255 @@ TEST_F(ShelfViewTest, ReplacingDelegateCancelsContextMenu) { ...@@ -2610,6 +2409,255 @@ TEST_F(ShelfViewTest, ReplacingDelegateCancelsContextMenu) {
EXPECT_FALSE(shelf_view_->IsShowingMenu()); EXPECT_FALSE(shelf_view_->IsShowingMenu());
} }
class OverflowBubbleViewTest : public ShelfViewTest {
public:
OverflowBubbleViewTest() = default;
~OverflowBubbleViewTest() override = default;
void SetUp() override {
ShelfViewTest::SetUp();
UpdateDisplay("300x600");
AddAppShortcutsUntilOverflow();
test_api_->ShowOverflowBubble();
ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
}
int GetMaxAccommodatedShelfNum() const {
const int available_width_for_shortcuts =
GetPrimaryDisplay().work_area().width() - 2 * bubble_view_min_margin_ -
2 * end_padding_;
return std::ceil(available_width_for_shortcuts / unit_);
}
protected:
const gfx::Size shelf_icon_size_ =
gfx::Size(kShelfButtonSize, kShelfButtonSize);
const int arrow_button_size_ = OverflowBubbleView::GetArrowButtonSize();
const int bubble_view_min_margin_ = OverflowBubbleView::kMinimumMargin;
const int end_padding_ = OverflowBubbleView::kEndPadding;
const int unit_ =
ShelfConstants::button_size() + ShelfConstants::button_spacing();
const int fading_zone_ = OverflowBubbleView::kFadingZone;
private:
DISALLOW_COPY_AND_ASSIGN(OverflowBubbleViewTest);
};
// Verifies that the arrow buttons of OverflowBubbleView work as expected.
TEST_F(OverflowBubbleViewTest, CheckOverflowBubbleViewArrowButton) {
OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
// Add sufficient app icons to ensure that it needs to press the right arrow
// buttons twice to reach the end.
int current_item_count = bubble_view->shelf_view()->last_visible_index() -
bubble_view->shelf_view()->first_visible_index() + 1;
const int max_accommodated_shelf_num = GetMaxAccommodatedShelfNum();
int additional_item_num =
2 * max_accommodated_shelf_num - 1 - current_item_count;
while (additional_item_num) {
AddAppShortcut();
additional_item_num--;
}
const gfx::Rect overflow_bubble_bounds = bubble_view->GetBoundsInScreen();
views::View* left_arrow_button = bubble_view->left_arrow();
views::View* right_arrow_button = bubble_view->right_arrow();
ShelfViewTestAPI test_for_overflow_view(
test_api_->overflow_bubble()->bubble_view()->shelf_view());
// Verifies that the overflow bubble has the correct bounds. In detail:
// (1) The width of the overflow bubble should be the multiple of |unit|.
// (2) The overflow bubble's gap between left and right display edge should
// be the same.
EXPECT_EQ(
overflow_bubble_bounds.origin().x(),
GetPrimaryDisplay().bounds().right() - overflow_bubble_bounds.right());
const int available_width_for_bubble =
GetPrimaryDisplay().bounds().width() - 2 * bubble_view_min_margin_;
const int remainder = available_width_for_bubble % unit_;
EXPECT_EQ(remainder / 2 + bubble_view_min_margin_,
overflow_bubble_bounds.origin().x());
EXPECT_EQ(0, overflow_bubble_bounds.width() % unit_);
// Verifies the following things right after showing the overflow bubble view:
// (1) The layout strategy is SHOW_RIGHT_ARROW_BUTTON.
// (2) The right button is visible.
// (3) The left button is invisible.
// (4) The first visible shelf button has the correct origin.
EXPECT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_TRUE(right_arrow_button->GetVisible());
EXPECT_FALSE(left_arrow_button->GetVisible());
gfx::Rect expected_first_icon_bounds(overflow_bubble_bounds.origin(),
shelf_icon_size_);
expected_first_icon_bounds.Offset(end_padding_, 0);
EXPECT_EQ(expected_first_icon_bounds,
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->first_visible_index())
->GetBoundsInScreen());
// Taps at the right arrow button.
const gfx::Point right_button_center =
right_arrow_button->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->GestureTapAt(right_button_center);
// Verifies that the layout strategy is SHOW_BUTTONS.
EXPECT_EQ(OverflowBubbleView::SHOW_BUTTONS, bubble_view->layout_strategy());
// Verifies that the right button shows in the expected bounds.
EXPECT_TRUE(right_arrow_button->GetVisible());
gfx::Rect expected_right_arrow_bounds =
gfx::Rect(overflow_bubble_bounds.width() - kShelfButtonSize, 0,
kShelfButtonSize, kShelfButtonSize);
expected_right_arrow_bounds.ClampToCenteredSize(
gfx::Size(arrow_button_size_, arrow_button_size_));
EXPECT_EQ(expected_right_arrow_bounds, right_arrow_button->bounds());
// Verifies that the left button shows in the expected bounds.
EXPECT_TRUE(left_arrow_button->GetVisible());
gfx::Rect expected_left_arrow_bounds =
gfx::Rect(0, 0, kShelfButtonSize, kShelfButtonSize);
expected_left_arrow_bounds.ClampToCenteredSize(
gfx::Size(arrow_button_size_, arrow_button_size_));
EXPECT_EQ(expected_left_arrow_bounds, left_arrow_button->bounds());
// Verifies that the scroll offset of the overflow bubble should be expected.
const int expected_scroll_distance =
overflow_bubble_bounds.width() - 2 * unit_;
EXPECT_EQ(expected_scroll_distance, bubble_view->scroll_offset().x());
// Tap at the right arrow button. Then check the following things:
// (1) The layout strategy is SHOW_LEFT_ARROW_BUTTON.
// (2) The left button is visible.
// (3) The right button is invisible.
// (4) The last visible shelf button has the expected bounds in screen.
GetEventGenerator()->GestureTapAt(right_button_center);
EXPECT_EQ(OverflowBubbleView::SHOW_LEFT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_FALSE(right_arrow_button->GetVisible());
EXPECT_TRUE(left_arrow_button->GetVisible());
gfx::Rect expected_last_icon_bounds(overflow_bubble_bounds.top_right(),
shelf_icon_size_);
expected_last_icon_bounds.Offset(-kShelfButtonSize - end_padding_, 0);
EXPECT_EQ(expected_last_icon_bounds,
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->last_visible_index())
->GetBoundsInScreen());
// Tap at the left arrow button twice. Check the following things:
// (1) The layout strategy is SHOW_RIGHT_ARROW_BUTTON.
// (2) The right button is visible.
// (3) The left button is invisible.
const gfx::Point left_button_center =
left_arrow_button->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->GestureTapAt(left_button_center);
GetEventGenerator()->GestureTapAt(left_button_center);
EXPECT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
EXPECT_TRUE(right_arrow_button->GetVisible());
EXPECT_FALSE(left_arrow_button->GetVisible());
}
// Verifies that the overflow bubble view handles the gesture events correctly.
TEST_F(OverflowBubbleViewTest, CheckGestureDraggingOverflowBubbleView) {
OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
// Calculates the start point of the gesture drag event. Ensures that the
// start point is not within the bounds of any shelf icon.
ShelfViewTestAPI test_for_overflow_view(
test_api_->overflow_bubble()->bubble_view()->shelf_view());
const gfx::Rect first_icon_bounds =
test_for_overflow_view
.GetButton(bubble_view->shelf_view()->first_visible_index())
->GetBoundsInScreen();
gfx::Point gesture_drag_point = first_icon_bounds.right_center();
gesture_drag_point.Offset(1, 0);
// Verifies that gesture dragging is disabled when no arrow button shows.
ASSERT_EQ(OverflowBubbleView::NOT_SHOW_ARROW_BUTTONS,
bubble_view->layout_strategy());
gfx::Point gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-kShelfButtonSize, 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 5);
EXPECT_EQ(0, bubble_view->scroll_offset().x());
// Adds enough shelf icons to show the right arrow button.
int max_accommodated_shelf_num = GetMaxAccommodatedShelfNum();
while (max_accommodated_shelf_num) {
AddAppShortcut();
max_accommodated_shelf_num--;
}
ASSERT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
// Verifies that the small gesutre offset will not scroll the overflow bubble.
gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-10, 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 1);
EXPECT_EQ(0, bubble_view->scroll_offset().x());
// Verifies that the large gesture offset will scroll the overflow bubble. The
// scroll offset is adjusted to fully show all of shelf icons.
gesture_end_point = gesture_drag_point;
gesture_end_point.Offset(-kShelfButtonSize, 0);
GetEventGenerator()->GestureScrollSequence(
gesture_drag_point, gesture_end_point,
base::TimeDelta::FromMilliseconds(100), 1);
EXPECT_EQ(unit_, bubble_view->scroll_offset().x());
}
// Verifies that the leftmost/rightmost shelf icon has correct fading in/out
// behavior when scrolling the overflow bubble.
TEST_F(OverflowBubbleViewTest, CheckFadingBehaviorOfOverflowBubbleView) {
const int max_accommodated_shelf_num = GetMaxAccommodatedShelfNum();
OverflowBubbleView* bubble_view = test_api_->overflow_bubble()->bubble_view();
views::ViewModel* shelf_view_model = bubble_view->shelf_view()->view_model();
const int base_index = bubble_view->shelf_view()->first_visible_index();
// Add enough app shortcuts to the shelf to ensure that the right arrow button
// shows.
for (int i = 0; i < max_accommodated_shelf_num; i++)
AddAppShortcut();
ASSERT_EQ(OverflowBubbleView::SHOW_RIGHT_ARROW_BUTTON,
bubble_view->layout_strategy());
// Verifies that at the beginning, the first/last visible index of the
// overflow bubble is correct. Note that the last visible index should be
// |base_index| + |max_accommodated_shelf_num| - 2, because one place is
// occupied by the arrow button.
EXPECT_EQ(base_index, bubble_view->GetFirstVisibleIndexForTest());
EXPECT_EQ(base_index + max_accommodated_shelf_num - 2,
bubble_view->GetLastVisibleIndexForTest());
// Scroll the overflow bubble by half of |fading_zone_|.
bubble_view->ScrollByXOffset(fading_zone_ / 2, false);
ASSERT_EQ(OverflowBubbleView::SHOW_BUTTONS, bubble_view->layout_strategy());
// Verifies that the first visible index increases by 1 because the left arrow
// button shows. The app short referred by the first visible index has the
// correct opacity.
EXPECT_EQ(base_index + 1, bubble_view->GetFirstVisibleIndexForTest());
views::View* leftmost_view =
shelf_view_model->view_at(bubble_view->GetFirstVisibleIndexForTest());
EXPECT_EQ(0.5f, leftmost_view->layer()->opacity());
// Verifies that the last visible index is expected. Note that we need to
// check the opacity of the app shortcut whose index is |last_visible_index| +
// 1. See OverflowBubbleView::UpdateOpacityOfEdgeIcons for more details.
EXPECT_EQ(base_index + max_accommodated_shelf_num - 2,
bubble_view->GetLastVisibleIndexForTest());
ASSERT_LT(bubble_view->GetLastVisibleIndexForTest() + 1,
shelf_view_model->view_size());
views::View* rightmost_view =
shelf_view_model->view_at(bubble_view->GetLastVisibleIndexForTest() + 1);
EXPECT_EQ(0.f, rightmost_view->layer()->opacity());
}
// Test class that tests both context and application menus. // Test class that tests both context and application menus.
class ShelfViewMenuTest : public ShelfViewTest, class ShelfViewMenuTest : public ShelfViewTest,
public testing::WithParamInterface<bool> { public testing::WithParamInterface<bool> {
......
...@@ -509,12 +509,12 @@ void AshTestBase::SwapPrimaryDisplay() { ...@@ -509,12 +509,12 @@ void AshTestBase::SwapPrimaryDisplay() {
display_manager()->GetSecondaryDisplay().id()); display_manager()->GetSecondaryDisplay().id());
} }
display::Display AshTestBase::GetPrimaryDisplay() { display::Display AshTestBase::GetPrimaryDisplay() const {
return display::Screen::GetScreen()->GetDisplayNearestWindow( return display::Screen::GetScreen()->GetDisplayNearestWindow(
Shell::GetPrimaryRootWindow()); Shell::GetPrimaryRootWindow());
} }
display::Display AshTestBase::GetSecondaryDisplay() { display::Display AshTestBase::GetSecondaryDisplay() const {
return ash_test_helper_.GetSecondaryDisplay(); return ash_test_helper_.GetSecondaryDisplay();
} }
......
...@@ -258,8 +258,8 @@ class AshTestBase : public testing::Test { ...@@ -258,8 +258,8 @@ class AshTestBase : public testing::Test {
// Swap the primary display with the secondary. // Swap the primary display with the secondary.
void SwapPrimaryDisplay(); void SwapPrimaryDisplay();
display::Display GetPrimaryDisplay(); display::Display GetPrimaryDisplay() const;
display::Display GetSecondaryDisplay(); display::Display GetSecondaryDisplay() const;
private: private:
void CreateWindowTreeIfNecessary(); void CreateWindowTreeIfNecessary();
......
...@@ -299,7 +299,7 @@ aura::Window* AshTestHelper::CurrentContext() { ...@@ -299,7 +299,7 @@ aura::Window* AshTestHelper::CurrentContext() {
return root_window; return root_window;
} }
display::Display AshTestHelper::GetSecondaryDisplay() { display::Display AshTestHelper::GetSecondaryDisplay() const {
return Shell::Get()->display_manager()->GetSecondaryDisplay(); return Shell::Get()->display_manager()->GetSecondaryDisplay();
} }
......
...@@ -105,7 +105,7 @@ class AshTestHelper { ...@@ -105,7 +105,7 @@ class AshTestHelper {
return test_views_delegate_.get(); return test_views_delegate_.get();
} }
display::Display GetSecondaryDisplay(); display::Display GetSecondaryDisplay() const;
TestSessionControllerClient* test_session_controller_client() { TestSessionControllerClient* test_session_controller_client() {
return session_controller_client_.get(); return session_controller_client_.get();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment