Commit 0a1c0021 authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

App list state change animation should animate shield transform

Previously, the background shiled transform would get applied
immediately on the app list view state change, causing a small vertical
background shield jump (perceived as the app list view jump).

BUG=1004063

Change-Id: Iec874a2c0939cf415e18839d9f14b35aafe1c482
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1804780
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#696909}
parent da30a32a
...@@ -109,6 +109,30 @@ constexpr char kAppListDragInTabletHistogram[] = ...@@ -109,6 +109,30 @@ constexpr char kAppListDragInTabletHistogram[] =
constexpr char kAppListDragInTabletMaxLatencyHistogram[] = constexpr char kAppListDragInTabletMaxLatencyHistogram[] =
"Apps.StateTransition.Drag.PresentationTime.MaxLatency.TabletMode"; "Apps.StateTransition.Drag.PresentationTime.MaxLatency.TabletMode";
// Returns whether AppList's rounded corners should be hidden based on
// the app list view state and app list view bounds.
bool ShouldHideRoundedCorners(ash::AppListViewState app_list_state,
const gfx::Rect& bounds) {
switch (app_list_state) {
case ash::AppListViewState::kClosed:
return false;
case ash::AppListViewState::kFullscreenAllApps:
case ash::AppListViewState::kFullscreenSearch:
// Hide rounded corners in fullscreen state.
return true;
case ash::AppListViewState::kPeeking:
case ash::AppListViewState::kHalf:
// When the virtual keyboard shows, the AppListView is moved upward to
// avoid the overlapping area with the virtual keyboard. As a result, its
// bottom side may be on the display edge. Stop showing the rounded
// corners under this circumstance.
return bounds.y() == 0;
}
NOTREACHED();
return false;
}
// This view forwards the focus to the search box widget by providing it as a // This view forwards the focus to the search box widget by providing it as a
// FocusTraversable when a focus search is provided. // FocusTraversable when a focus search is provided.
class SearchBoxFocusHost : public views::View { class SearchBoxFocusHost : public views::View {
...@@ -791,7 +815,7 @@ void AppListView::Layout() { ...@@ -791,7 +815,7 @@ void AppListView::Layout() {
app_list_background_shield_->UpdateBounds(contents_bounds); app_list_background_shield_->UpdateBounds(contents_bounds);
UpdateAppListBackgroundYPosition(); UpdateAppListBackgroundYPosition(app_list_state_);
} }
ax::mojom::Role AppListView::GetAccessibleWindowRole() { ax::mojom::Role AppListView::GetAccessibleWindowRole() {
...@@ -1517,7 +1541,6 @@ void AppListView::SetState(ash::AppListViewState new_state) { ...@@ -1517,7 +1541,6 @@ void AppListView::SetState(ash::AppListViewState new_state) {
// Layout is called on animation completion, which makes the child views // Layout is called on animation completion, which makes the child views
// jump. Update y positions in advance here to avoid that. // jump. Update y positions in advance here to avoid that.
app_list_main_view_->contents_view()->UpdateYPositionAndOpacity(); app_list_main_view_->contents_view()->UpdateYPositionAndOpacity();
UpdateAppListBackgroundYPosition();
} }
if (GetWidget()->IsActive()) { if (GetWidget()->IsActive()) {
...@@ -1576,6 +1599,7 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state, ...@@ -1576,6 +1599,7 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state,
if (is_side_shelf_) { if (is_side_shelf_) {
// There is no animation in side shelf. // There is no animation in side shelf.
OnBoundsAnimationCompleted(); OnBoundsAnimationCompleted();
UpdateAppListBackgroundYPosition(target_state);
if (animation_observer) if (animation_observer)
animation_observer->OnImplicitAnimationsCompleted(); animation_observer->OnImplicitAnimationsCompleted();
return; return;
...@@ -1615,10 +1639,14 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state, ...@@ -1615,10 +1639,14 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state,
const int current_y_with_transform = const int current_y_with_transform =
current_bounds_y + GetRemainingBoundsAnimationDistance(); current_bounds_y + GetRemainingBoundsAnimationDistance();
const gfx::Transform current_shield_transform =
app_list_background_shield_->layer()->transform();
// Schedule the animation; set to the target bounds, and make the transform // Schedule the animation; set to the target bounds, and make the transform
// to make this appear in the original location. Then set an empty transform // to make this appear in the original location. Then set an empty transform
// with the animation. // with the animation.
layer->SetBounds(target_bounds); layer->SetBounds(target_bounds);
gfx::Transform transform; gfx::Transform transform;
const int y_offset = current_y_with_transform - target_bounds.y(); const int y_offset = current_y_with_transform - target_bounds.y();
transform.Translate(0, y_offset); transform.Translate(0, y_offset);
...@@ -1639,6 +1667,27 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state, ...@@ -1639,6 +1667,27 @@ void AppListView::ApplyBoundsAnimation(ash::AppListViewState target_state,
animation.AddObserver(animation_observer); animation.AddObserver(animation_observer);
} }
// In fullscreen state, or peeking state with restricted vertical space, the
// background shield is translated upwards to ensure background radius is not
// visible.
// NOTE: layer->SetBounds() changes shield transform, so reset the transform
// to the value before the |layer| bounds are set before starting the
// animation.
app_list_background_shield_->SetTransform(current_shield_transform);
ui::ScopedLayerAnimationSettings shield_animation(
app_list_background_shield_->layer()->GetAnimator());
shield_animation.SetTransitionDuration(duration_ms);
shield_animation.SetTweenType(gfx::Tween::EASE_OUT);
shield_animation.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
gfx::Transform shield_transform;
if (ShouldHideRoundedCorners(target_state, target_bounds)) {
shield_transform.Translate(0,
-AppListConfig::instance().background_radius());
}
app_list_background_shield_->SetTransform(shield_transform);
if (update_childview_each_frame_) { if (update_childview_each_frame_) {
layer->GetAnimator()->StartAnimation(new ui::LayerAnimationSequence( layer->GetAnimator()->StartAnimation(new ui::LayerAnimationSequence(
std::make_unique<PeekingResetAnimation>(y_offset, duration_ms, this))); std::make_unique<PeekingResetAnimation>(y_offset, duration_ms, this)));
...@@ -1921,11 +1970,15 @@ void AppListView::OnWindowBoundsChanged(aura::Window* window, ...@@ -1921,11 +1970,15 @@ void AppListView::OnWindowBoundsChanged(aura::Window* window,
UpdateAppListConfig(window); UpdateAppListConfig(window);
gfx::Transform transform; gfx::Transform transform;
if (ShouldHideRoundedCorners(new_bounds)) if (ShouldHideRoundedCorners(app_list_state_, new_bounds))
transform.Translate(0, -AppListConfig::instance().background_radius()); transform.Translate(0, -AppListConfig::instance().background_radius());
app_list_background_shield_->SetTransform(transform); // Avoid setting new transform if the shield is animating to (or already has)
app_list_background_shield_->SchedulePaint(); // the target value.
if (app_list_background_shield_->layer()->GetTargetTransform() != transform) {
app_list_background_shield_->SetTransform(transform);
app_list_background_shield_->SchedulePaint();
}
} }
void AppListView::OnBoundsAnimationCompleted() { void AppListView::OnBoundsAnimationCompleted() {
...@@ -1961,7 +2014,7 @@ void AppListView::UpdateChildViewsYPositionAndOpacity() { ...@@ -1961,7 +2014,7 @@ void AppListView::UpdateChildViewsYPositionAndOpacity() {
if (app_list_state_ == ash::AppListViewState::kClosed) if (app_list_state_ == ash::AppListViewState::kClosed)
return; return;
UpdateAppListBackgroundYPosition(); UpdateAppListBackgroundYPosition(app_list_state_);
// Update the opacity of the background shield. // Update the opacity of the background shield.
SetBackgroundShieldColor(); SetBackgroundShieldColor();
...@@ -2166,7 +2219,8 @@ gfx::Rect AppListView::GetPreferredWidgetBoundsForState( ...@@ -2166,7 +2219,8 @@ gfx::Rect AppListView::GetPreferredWidgetBoundsForState(
GetFullscreenStateHeight())); GetFullscreenStateHeight()));
} }
void AppListView::UpdateAppListBackgroundYPosition() { void AppListView::UpdateAppListBackgroundYPosition(
ash::AppListViewState state) {
// Update the y position of the background shield. // Update the y position of the background shield.
gfx::Transform transform; gfx::Transform transform;
if (is_in_drag_) { if (is_in_drag_) {
...@@ -2184,13 +2238,14 @@ void AppListView::UpdateAppListBackgroundYPosition() { ...@@ -2184,13 +2238,14 @@ void AppListView::UpdateAppListBackgroundYPosition() {
transform.Translate(0, -AppListConfig::instance().background_radius() * transform.Translate(0, -AppListConfig::instance().background_radius() *
(app_list_transition_progress - 1)); (app_list_transition_progress - 1));
} }
} else if (is_fullscreen() || ShouldHideRoundedCorners(GetBoundsInScreen())) { } else if (ShouldHideRoundedCorners(state, GetBoundsInScreen())) {
// AppListView::Layout may be called after OnWindowBoundsChanged. It may
// reset the transform of |app_list_background_shield_|. So hide the rounded
// corners here when ShouldHideRoundedCorners returns true.
transform.Translate(0, -AppListConfig::instance().background_radius()); transform.Translate(0, -AppListConfig::instance().background_radius());
} }
app_list_background_shield_->SetTransform(transform);
// Avoid setting new transform if the shield is animating to (or already has)
// the target value.
if (app_list_background_shield_->layer()->GetTargetTransform() != transform)
app_list_background_shield_->SetTransform(transform);
} }
bool AppListView::ShouldUpdateChildViewsDuringAnimation( bool AppListView::ShouldUpdateChildViewsDuringAnimation(
...@@ -2216,16 +2271,6 @@ bool AppListView::ShouldUpdateChildViewsDuringAnimation( ...@@ -2216,16 +2271,6 @@ bool AppListView::ShouldUpdateChildViewsDuringAnimation(
GetPreferredWidgetYForState(target_state); GetPreferredWidgetYForState(target_state);
} }
bool AppListView::ShouldHideRoundedCorners(const gfx::Rect& bounds) const {
// When the virtual keyboard shows, the AppListView is moved upward to avoid
// the overlapping area with the virtual keyboard. As a result, its bottom
// side may be on the display edge. Stop showing the rounded corners under
// this circumstance.
return (app_list_state_ == ash::AppListViewState::kPeeking ||
app_list_state_ == ash::AppListViewState::kHalf) &&
bounds.y() == 0;
}
void AppListView::OnStateTransitionAnimationCompleted() { void AppListView::OnStateTransitionAnimationCompleted() {
delegate_->OnStateTransitionAnimationCompleted(app_list_state_); delegate_->OnStateTransitionAnimationCompleted(app_list_state_);
} }
......
...@@ -437,18 +437,14 @@ class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView, ...@@ -437,18 +437,14 @@ class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView,
gfx::Rect GetPreferredWidgetBoundsForState(ash::AppListViewState state); gfx::Rect GetPreferredWidgetBoundsForState(ash::AppListViewState state);
// Updates y position of |app_list_background_shield_| based on the // Updates y position of |app_list_background_shield_| based on the
// |app_list_state_| and |is_in_drag_|. // |state| and |is_in_drag_|.
void UpdateAppListBackgroundYPosition(); void UpdateAppListBackgroundYPosition(ash::AppListViewState state);
// Returns whether it should update child views' position and opacity in each // Returns whether it should update child views' position and opacity in each
// animation frame. // animation frame.
bool ShouldUpdateChildViewsDuringAnimation( bool ShouldUpdateChildViewsDuringAnimation(
ash::AppListViewState target_state) const; ash::AppListViewState target_state) const;
// Returns whether AppList's rounded corners should be hidden based on
// |bounds|.
bool ShouldHideRoundedCorners(const gfx::Rect& bounds) const;
AppListViewDelegate* delegate_; // Weak. Owned by AppListService. AppListViewDelegate* delegate_; // Weak. Owned by AppListService.
AppListModel* const model_; // Not Owned. AppListModel* const model_; // Not Owned.
SearchModel* const search_model_; // Not Owned. SearchModel* const search_model_; // Not Owned.
......
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