Commit 982a5694 authored by Andrew Xu's avatar Andrew Xu Committed by Commit Bot

Make the icon's final bounds be minimization's target bounds

The current minimization animation, which is triggered by going to
home screen from in-app shelf, uses the bounds of the icon
which corresponds to the active window to be minimized as the
animation's target bounds. However, hotseat's bounds change due to
entering the home screen. As a result, the target bounds are not the
final bounds.

This CL fixes the issue by providing an interface to calculate
the icon's bounds according to the hotseat's target bounds instead
of the actual bounds.

There are four ways to show the home screen from in-app shelf:
(1) Press the home button.
(2) Gesture fling up on the hotseat.
(3) Back gesture.
(4) Tap on the shelf icon.

In case (1), hotseat's target bounds have been set before starting
the window scaling animation. In other cases, target bounds are not
set yet. Thanks to https://crrev.com/c/1999443, case 3 and case 4 are
solved. The last one, case 2, will be fixed in the following CL.

Bug: 1030819
Change-Id: I63cafabe6527aba49e9f98e338f9f248284e1d0d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1996268
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732416}
parent 8630c10d
......@@ -109,12 +109,9 @@ gfx::Transform WindowScaleAnimation::GetWindowTransformToShelf() {
gfx::Transform transform;
Shelf* shelf = Shelf::ForWindow(window_);
gfx::Rect shelf_item_bounds =
const gfx::Rect shelf_item_bounds =
shelf->GetScreenBoundsOfItemIconForWindow(window_);
// |shelf_item_bounds| is the item bounds in a extended hotseat (i.e., the
// hotseat state during dragging). Adjust it to the bounds in a shown
// hotseat (i.e., the hotseat state after dragging).
shelf_item_bounds.Offset(0, ShelfConfig::Get()->shelf_size());
if (!shelf_item_bounds.IsEmpty()) {
transform.Translate(shelf_item_bounds.x() - origin_without_transform.x(),
......
......@@ -572,7 +572,8 @@ views::View* ScrollableShelfView::GetDefaultFocusableChild() {
// ring is enabled.
if (default_last_focusable_child_) {
ScrollToMainOffset(CalculateScrollUpperBound(), /*animating=*/true);
ScrollToMainOffset(CalculateScrollUpperBound(GetSpaceForIcons()),
/*animating=*/true);
return FindLastFocusableChild();
} else {
ScrollToMainOffset(/*target_offset=*/0.f, /*animating=*/true);
......@@ -588,13 +589,70 @@ bool ScrollableShelfView::ShouldAdaptToRTL() const {
return base::i18n::IsRTL() && GetShelf()->IsHorizontalAlignment();
}
gfx::Rect ScrollableShelfView::GetTargetScreenBoundsOfItemIcon(
const ShelfID& id) const {
DCHECK(GetShelf()->IsHorizontalAlignment());
// Calculates the available space for child views based on the target bounds.
const gfx::Insets edge_padding =
CalculateEdgePadding(/*use_target_bounds=*/true);
gfx::Rect target_space = GetAvailableLocalBounds(/*use_target_bounds=*/true);
target_space.Inset(edge_padding);
const int target_scroll_offset =
CalculateScrollOffsetForTargetAvailableSpace(target_space);
gfx::Rect icon_bounds = shelf_view_->view_model()->ideal_bounds(
shelf_view_->model()->ItemIndexByID(id));
// Transforms |icon_bounds| from shelf view's coordinates to scrollable shelf
// view's coordinates manually.
icon_bounds.Offset(
-target_scroll_offset + ShelfConfig::Get()->GetAppIconEndPadding(), 0);
// If the icon is invisible under the target view bounds, replaces the actual
// icon's bounds with the rectangle centering on the edge of |target_space|.
const gfx::Point icon_bounds_center = icon_bounds.CenterPoint();
if (icon_bounds_center.x() > target_space.right()) {
icon_bounds.Offset(target_space.right_center().OffsetFromOrigin() -
icon_bounds_center.OffsetFromOrigin());
} else if (icon_bounds_center.x() < target_space.x()) {
icon_bounds.Offset(target_space.left_center().OffsetFromOrigin() -
icon_bounds_center.OffsetFromOrigin());
}
// Hotseat's target bounds may differ from the actual bounds. So it has to
// transform the bounds manually from view's local coordinates to screen.
// Notes that the target bounds stored in shelf layout manager are adapted to
// RTL already while |icon_bounds| are not adjusted to RTL yet.
gfx::Rect hotseat_bounds_in_screen =
GetShelf()->shelf_layout_manager()->GetHotseatBounds();
if (ShouldAdaptToRTL()) {
// One simple way for transformation under RTL is: (1) Transforms hotseat
// target bounds from RTL to LTR. (2) Calculates the icon's bounds in screen
// under LTR. (3) Transforms the icon's bounds to RTL.
gfx::Rect display_bounds =
display::Screen::GetScreen()
->GetDisplayNearestWindow(GetWidget()->GetNativeView())
.bounds();
hotseat_bounds_in_screen.set_x(display_bounds.right() -
hotseat_bounds_in_screen.right());
icon_bounds.Offset(hotseat_bounds_in_screen.OffsetFromOrigin());
icon_bounds.set_x(display_bounds.right() - icon_bounds.right());
} else {
icon_bounds.Offset(hotseat_bounds_in_screen.OffsetFromOrigin());
}
return icon_bounds;
}
views::View* ScrollableShelfView::GetShelfContainerViewForTest() {
return shelf_container_view_;
}
bool ScrollableShelfView::ShouldAdjustForTest() const {
return CalculateAdjustmentOffset(CalculateMainAxisScrollDistance(),
layout_strategy_);
layout_strategy_, GetSpaceForIcons());
}
void ScrollableShelfView::SetTestObserver(TestObserver* test_observer) {
......@@ -603,13 +661,14 @@ void ScrollableShelfView::SetTestObserver(TestObserver* test_observer) {
test_observer_ = test_observer;
}
int ScrollableShelfView::CalculateScrollUpperBound() const {
int ScrollableShelfView::CalculateScrollUpperBound(
int available_space_for_icons) const {
if (layout_strategy_ == kNotShowArrowButtons)
return 0;
// Calculate the length of the available space.
int available_length =
GetSpaceForIcons() - 2 * ShelfConfig::Get()->GetAppIconEndPadding();
int available_length = available_space_for_icons -
2 * ShelfConfig::Get()->GetAppIconEndPadding();
// Calculate the length of the preferred size.
const gfx::Size shelf_preferred_size(
......@@ -621,8 +680,11 @@ int ScrollableShelfView::CalculateScrollUpperBound() const {
return std::max(0, preferred_length - available_length);
}
float ScrollableShelfView::CalculateClampedScrollOffset(float scroll) const {
const float scroll_upper_bound = CalculateScrollUpperBound();
float ScrollableShelfView::CalculateClampedScrollOffset(
float scroll,
int available_space_for_icons) const {
const float scroll_upper_bound =
CalculateScrollUpperBound(available_space_for_icons);
scroll = base::ClampToRange(scroll, 0.0f, scroll_upper_bound);
return scroll;
}
......@@ -652,9 +714,10 @@ void ScrollableShelfView::StartShelfScrollAnimation(float scroll_distance) {
}
ScrollableShelfView::LayoutStrategy
ScrollableShelfView::CalculateLayoutStrategy(
int scroll_distance_on_main_axis) const {
if (CanFitAllAppsWithoutScrolling())
ScrollableShelfView::CalculateLayoutStrategy(int scroll_distance_on_main_axis,
int space_for_icons,
bool use_target_bounds) const {
if (CanFitAllAppsWithoutScrolling(use_target_bounds))
return kNotShowArrowButtons;
if (scroll_distance_on_main_axis == 0) {
......@@ -662,7 +725,8 @@ ScrollableShelfView::CalculateLayoutStrategy(
return kShowRightArrowButton;
}
if (scroll_distance_on_main_axis == CalculateScrollUpperBound()) {
if (scroll_distance_on_main_axis ==
CalculateScrollUpperBound(space_for_icons)) {
// If there is no invisible shelf button at the right side, hide the right
// button.
return kShowLeftArrowButton;
......@@ -672,19 +736,17 @@ ScrollableShelfView::CalculateLayoutStrategy(
return kShowButtons;
}
bool ScrollableShelfView::ShouldApplyDisplayCentering() const {
if (!CanFitAllAppsWithoutScrolling())
bool ScrollableShelfView::ShouldApplyDisplayCentering(
bool use_target_bounds) const {
if (!CanFitAllAppsWithoutScrolling(use_target_bounds))
return false;
const gfx::Rect display_bounds =
screen_util::GetDisplayBoundsWithShelf(GetWidget()->GetNativeWindow());
const int display_size_primary = GetShelf()->PrimaryAxisValue(
display_bounds.width(), display_bounds.height());
StatusAreaWidget* status_widget =
GetShelf()->shelf_widget()->status_area_widget();
const int status_widget_size = GetShelf()->PrimaryAxisValue(
status_widget->GetWindowBoundsInScreen().width(),
status_widget->GetWindowBoundsInScreen().height());
const int status_widget_size =
GetStatusWidgetSizeOnPrimaryAxis(use_target_bounds);
// An easy way to check whether the apps fit at the exact center of the
// screen is to imagine that we have another status widget on the other
......@@ -930,10 +992,11 @@ void ScrollableShelfView::ScrollRectToVisible(const gfx::Rect& rect) {
break;
main_axis_offset_after_scroll += page_scroll_distance;
main_axis_offset_after_scroll =
CalculateClampedScrollOffset(main_axis_offset_after_scroll);
layout_strategy_after_scroll =
CalculateLayoutStrategy(main_axis_offset_after_scroll);
main_axis_offset_after_scroll = CalculateClampedScrollOffset(
main_axis_offset_after_scroll, GetSpaceForIcons());
layout_strategy_after_scroll = CalculateLayoutStrategy(
main_axis_offset_after_scroll, GetSpaceForIcons(),
/*use_target_bounds= =*/false);
main_axis_offset_after_scroll = CalculateScrollDistanceAfterAdjustment(
main_axis_offset_after_scroll, layout_strategy_after_scroll);
visible_space_after_scroll =
......@@ -1195,9 +1258,10 @@ bool ScrollableShelfView::ShouldShowRightArrow() const {
(layout_strategy_ == kShowButtons);
}
gfx::Insets ScrollableShelfView::CalculateEdgePadding() const {
gfx::Insets ScrollableShelfView::CalculateEdgePadding(
bool use_target_bounds) const {
// Display centering alignment
if (ShouldApplyDisplayCentering())
if (ShouldApplyDisplayCentering(use_target_bounds))
return CalculatePaddingForDisplayCentering();
const int icons_size = shelf_view_->GetSizeOfAppIcons(
......@@ -1205,11 +1269,14 @@ gfx::Insets ScrollableShelfView::CalculateEdgePadding() const {
2 * ShelfConfig::Get()->GetAppIconEndPadding();
const int base_padding = ShelfConfig::Get()->app_icon_group_margin();
const gfx::Rect available_local_bounds =
GetAvailableLocalBounds(use_target_bounds);
const int available_size_for_app_icons =
(GetShelf()->IsHorizontalAlignment() ? width() : height()) -
GetShelf()->PrimaryAxisValue(available_local_bounds.width(),
available_local_bounds.height()) -
2 * ShelfConfig::Get()->app_icon_group_margin();
int gap = CanFitAllAppsWithoutScrolling()
int gap = CanFitAllAppsWithoutScrolling(use_target_bounds)
? available_size_for_app_icons - icons_size // shelf centering
: 0; // overflow
......@@ -1229,6 +1296,29 @@ gfx::Insets ScrollableShelfView::CalculateEdgePadding() const {
return padding_insets;
}
int ScrollableShelfView::GetStatusWidgetSizeOnPrimaryAxis(
bool use_target_bounds) const {
const gfx::Size status_widget_size =
use_target_bounds
? GetShelf()->shelf_layout_manager()->GetStatusAreaBounds().size()
: GetShelf()
->shelf_widget()
->status_area_widget()
->GetWindowBoundsInScreen()
.size();
return GetShelf()->PrimaryAxisValue(status_widget_size.width(),
status_widget_size.height());
}
gfx::Rect ScrollableShelfView::GetAvailableLocalBounds(
bool use_target_bounds) const {
return use_target_bounds ? gfx::Rect(GetShelf()
->shelf_layout_manager()
->GetHotseatBounds()
.size())
: GetLocalBounds();
}
gfx::Insets ScrollableShelfView::CalculatePaddingForDisplayCentering() const {
const int icons_size = shelf_view_->GetSizeOfAppIcons(
shelf_view_->number_of_visible_apps(), false) +
......@@ -1733,9 +1823,12 @@ int ScrollableShelfView::GetSpaceForIcons() const {
: available_space_.height();
}
bool ScrollableShelfView::CanFitAllAppsWithoutScrolling() const {
bool ScrollableShelfView::CanFitAllAppsWithoutScrolling(
bool use_target_bounds) const {
const gfx::Rect available_rect = GetAvailableLocalBounds(use_target_bounds);
const int available_length =
(GetShelf()->IsHorizontalAlignment() ? width() : height()) -
(GetShelf()->IsHorizontalAlignment() ? available_rect.width()
: available_rect.height()) -
2 * ShelfConfig::Get()->app_icon_group_margin();
gfx::Size preferred_size = GetPreferredSize();
......@@ -1766,7 +1859,7 @@ bool ScrollableShelfView::ShouldHandleScroll(const gfx::Vector2dF& offset,
bool ScrollableShelfView::AdjustOffset() {
const int offset = CalculateAdjustmentOffset(
CalculateMainAxisScrollDistance(), layout_strategy_);
CalculateMainAxisScrollDistance(), layout_strategy_, GetSpaceForIcons());
// Returns early when it does not need to adjust the shelf view's location.
if (!offset)
......@@ -1782,10 +1875,12 @@ bool ScrollableShelfView::AdjustOffset() {
int ScrollableShelfView::CalculateAdjustmentOffset(
int main_axis_scroll_distance,
LayoutStrategy layout_strategy) const {
LayoutStrategy layout_strategy,
int available_space_for_icons) const {
// Returns early when it does not need to adjust the shelf view's location.
if (layout_strategy == kNotShowArrowButtons ||
main_axis_scroll_distance >= CalculateScrollUpperBound()) {
main_axis_scroll_distance >=
CalculateScrollUpperBound(available_space_for_icons)) {
return 0;
}
......@@ -1802,11 +1897,12 @@ int ScrollableShelfView::CalculateScrollDistanceAfterAdjustment(
int main_axis_scroll_distance,
LayoutStrategy layout_strategy) const {
return main_axis_scroll_distance +
CalculateAdjustmentOffset(main_axis_scroll_distance, layout_strategy);
CalculateAdjustmentOffset(main_axis_scroll_distance, layout_strategy,
GetSpaceForIcons());
}
void ScrollableShelfView::UpdateAvailableSpace() {
padding_insets_ = CalculateEdgePadding();
padding_insets_ = CalculateEdgePadding(/*use_target_bounds=*/false);
available_space_ = GetLocalBounds();
available_space_.Inset(padding_insets_);
if (ShouldAdaptToRTL())
......@@ -1832,7 +1928,7 @@ gfx::Rect ScrollableShelfView::CalculateVisibleSpace(
const bool in_hotseat_tablet =
chromeos::switches::ShouldShowShelfHotseat() && IsInTabletMode();
if (layout_strategy == kNotShowArrowButtons && !in_hotseat_tablet)
return GetLocalBounds();
return GetAvailableLocalBounds(/*use_target_bounds=*/false);
const bool should_show_left_arrow =
(layout_strategy == kShowLeftArrowButton) ||
......@@ -1976,7 +2072,8 @@ float ScrollableShelfView::CalculateMainAxisScrollDistance() const {
}
void ScrollableShelfView::UpdateScrollOffset(float target_offset) {
target_offset = CalculateClampedScrollOffset(target_offset);
target_offset =
CalculateClampedScrollOffset(target_offset, GetSpaceForIcons());
if (GetShelf()->IsHorizontalAlignment())
scroll_offset_.set_x(target_offset);
......@@ -1984,8 +2081,9 @@ void ScrollableShelfView::UpdateScrollOffset(float target_offset) {
scroll_offset_.set_y(target_offset);
// Calculating the layout strategy relies on |scroll_offset_|.
LayoutStrategy new_strategy =
CalculateLayoutStrategy(CalculateMainAxisScrollDistance());
LayoutStrategy new_strategy = CalculateLayoutStrategy(
CalculateMainAxisScrollDistance(), GetSpaceForIcons(),
/*use_target_bounds=*/false);
const bool strategy_needs_update = (layout_strategy_ != new_strategy);
if (strategy_needs_update) {
......@@ -2004,4 +2102,24 @@ void ScrollableShelfView::UpdateAvailableSpaceAndScroll() {
UpdateScrollOffset(CalculateMainAxisScrollDistance());
}
int ScrollableShelfView::CalculateScrollOffsetForTargetAvailableSpace(
const gfx::Rect& target_space) const {
// Ensures that the scroll offset is legal under the updated available space.
const int available_space_for_icons =
GetShelf()->PrimaryAxisValue(target_space.width(), target_space.height());
int target_scroll_offset = CalculateClampedScrollOffset(
CalculateMainAxisScrollDistance(), available_space_for_icons);
// Calculates the layout strategy based on the new scroll offset.
LayoutStrategy new_strategy =
CalculateLayoutStrategy(target_scroll_offset, available_space_for_icons,
/*use_target_bounds=*/true);
// Adjusts the scroll offset with the new strategy.
target_scroll_offset += CalculateAdjustmentOffset(
target_scroll_offset, new_strategy, available_space_for_icons);
return target_scroll_offset;
}
} // namespace ash
......@@ -82,6 +82,12 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
// Returns whether the view should adapt to RTL.
bool ShouldAdaptToRTL() const;
// Returns the icon's target bounds in screen. The returned bounds are
// calculated with the hotseat's target bounds instead of the actual bounds.
// It helps to get the icon's final location before the bounds animation on
// hotseat ends.
gfx::Rect GetTargetScreenBoundsOfItemIcon(const ShelfID& id) const;
views::View* GetShelfContainerViewForTest();
bool ShouldAdjustForTest() const;
......@@ -147,22 +153,28 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
kNotInScroll
};
// Returns the maximum scroll distance.
int CalculateScrollUpperBound() const;
// Returns the maximum scroll distance based on the given space for icons.
int CalculateScrollUpperBound(int available_space_for_icons) const;
// Returns the clamped scroll offset.
float CalculateClampedScrollOffset(float scroll) const;
float CalculateClampedScrollOffset(float scroll,
int available_space_for_icons) const;
// Creates the animation for scrolling shelf by |scroll_distance|.
void StartShelfScrollAnimation(float scroll_distance);
// Calculates the layout strategy based on the available space and scroll
// distance.
LayoutStrategy CalculateLayoutStrategy(
int scroll_distance_on_main_axis) const;
// Calculates the layout strategy based on the three factors:
// (1) scroll offset on the main axis; (2) available space for shelf icons;
// (3) Bounds of the scrollable shelf view: actual view bounds or target
// bounds.
LayoutStrategy CalculateLayoutStrategy(int scroll_distance_on_main_axis,
int space_for_icons,
bool use_target_bounds) const;
// Returns whether the app icon layout should be centering alignment.
bool ShouldApplyDisplayCentering() const;
// |use_target_bounds| indicates which view bounds are used for
// calculation: actual view bounds or target view bounds.
bool ShouldApplyDisplayCentering(bool use_target_bounds) const;
Shelf* GetShelf();
const Shelf* GetShelf() const;
......@@ -235,7 +247,15 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
// (1) display centering alignment
// (2) scrollable shelf centering alignment
// (3) overflow mode
gfx::Insets CalculateEdgePadding() const;
// |use_target_bounds| indicates which view bounds are used for
// calculation: actual view bounds or target view bounds.
gfx::Insets CalculateEdgePadding(bool use_target_bounds) const;
int GetStatusWidgetSizeOnPrimaryAxis(bool use_target_bounds) const;
// Returns the local bounds depending on which view bounds are used: actual
// view bounds or target view bounds.
gfx::Rect GetAvailableLocalBounds(bool use_target_bounds) const;
// Calculates padding for display centering alignment.
gfx::Insets CalculatePaddingForDisplayCentering() const;
......@@ -312,7 +332,9 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
int GetSpaceForIcons() const;
// Returns whether there is available space to accommodate all shelf icons.
bool CanFitAllAppsWithoutScrolling() const;
// |use_target_bounds| indicates which view bounds are used for
// calculation: actual view bounds or target view bounds.
bool CanFitAllAppsWithoutScrolling(bool use_target_bounds) const;
// Returns whether scrolling should be handled. |is_gesture_fling| is true
// when the scrolling is triggered by gesture fling event; when it is false,
......@@ -326,8 +348,11 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
// Returns the offset by which the scroll distance along the main axis should
// be adjusted to ensure the correct UI under the specific layout strategy.
// Three parameters are needed: (1) scroll offset on the main axis (2) layout
// strategy (3) available space for shelf icons.
int CalculateAdjustmentOffset(int main_axis_scroll_distance,
LayoutStrategy layout_strategy) const;
LayoutStrategy layout_strategy,
int available_space_for_icons) const;
int CalculateScrollDistanceAfterAdjustment(
int main_axis_scroll_distance,
......@@ -374,6 +399,10 @@ class ASH_EXPORT ScrollableShelfView : public views::AccessiblePaneView,
// offset and layout strategy.
void UpdateAvailableSpaceAndScroll();
// Returns the scroll offset assuming view bounds being the target bounds.
int CalculateScrollOffsetForTargetAvailableSpace(
const gfx::Rect& target_space) const;
LayoutStrategy layout_strategy_ = kNotShowArrowButtons;
// Child views Owned by views hierarchy.
......
......@@ -23,6 +23,7 @@
#include "ash/shelf/login_shelf_view.h"
#include "ash/shelf/overflow_bubble.h"
#include "ash/shelf/overflow_bubble_view.h"
#include "ash/shelf/scrollable_shelf_view.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_background_animator_observer.h"
#include "ash/shelf/shelf_layout_manager.h"
......@@ -630,6 +631,12 @@ gfx::Rect ShelfWidget::GetScreenBoundsOfItemIconForWindow(
if (id.IsNull())
return gfx::Rect();
if (chromeos::switches::ShouldShowShelfHotseat()) {
return hotseat_widget()
->scrollable_shelf_view()
->GetTargetScreenBoundsOfItemIcon(id);
}
gfx::Rect bounds(
hotseat_widget()->GetShelfView()->GetIdealBoundsOfItemIcon(id));
gfx::Point screen_origin;
......
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