Commit d930d8c3 authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Animate hosted webviews during app list contents animations

Assistant UI and search results page in the app list view may contain
hosted native views (e.g. for answer cards, or assistant card UI
elements). These would not animate with the app list page layers,
causing glitches when app list view was animating after drag to
fullscreen or half position.

This CL updates the app list view contents animations for app list view
state change to animate windows hosted within the app list (i.e. app
list window children that have a host view property).

Along the way, this makes sure that page shadoes are animated together
with the page layers.

BUG=b:147825124

Change-Id: Ic1974b8a6767bbc25fdf96d5d6a67c41eb906fff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2136845
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757119}
parent f403f1d1
......@@ -59,6 +59,17 @@ bool AppListPage::ShouldShowSearchBox() const {
return true;
}
void AppListPage::AnimateOpacity(float current_progress,
AppListViewState target_view_state,
const OpacityAnimator& animator) {
animator.Run(this, target_view_state != AppListViewState::kClosed);
}
void AppListPage::AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) {
animator.Run(layer(), this);
}
gfx::Rect AppListPage::GetAboveContentsOffscreenBounds(
const gfx::Size& size) const {
gfx::Rect rect(size);
......
......@@ -105,6 +105,28 @@ class APP_LIST_EXPORT AppListPage : public views::View {
// Returns true if the search box should be shown in this page.
virtual bool ShouldShowSearchBox() const;
// Called when the app list view state changes to |target_view_state| to
// animate the app list page opacity.
// |current_progress| - the current app list transition progress.
// |animator| - callback that when run starts the opacity animation.
using OpacityAnimator =
base::RepeatingCallback<void(views::View* view, bool target_visibility)>;
virtual void AnimateOpacity(float current_progress,
AppListViewState target_view_state,
const OpacityAnimator& animator);
// Called when the app list view state changes to |target_view_state| to
// animate the app list page vertical offset from the app list view top.
// |animator| - The callback that runs the transform animation to update the
// page's vertical position. (The layer is required argument, while view is
// optional, and should be used with layers associated with views - the
// animator will send out a11y position change notification for the view when
// the animation finishes).
using TransformAnimator =
base::RepeatingCallback<void(ui::Layer* layer, views::View* view)>;
virtual void AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator);
// Returns the area above the contents view, given the desired size of this
// page, in the contents view's coordinate space.
gfx::Rect GetAboveContentsOffscreenBounds(const gfx::Size& size) const;
......
......@@ -212,15 +212,16 @@ void AppsContainerView::AnimateYPosition(AppListViewState target_view_state,
AppListView::GetTransitionProgressForState(target_view_state));
suggestion_chip_container_view_->SetY(target_suggestion_chip_y);
animator.Run(suggestion_chip_container_view_);
animator.Run(suggestion_chip_container_view_->layer(),
suggestion_chip_container_view_);
apps_grid_view_->SetY(suggestion_chip_container_view_->y() +
chip_grid_y_distance_);
animator.Run(apps_grid_view_);
animator.Run(apps_grid_view_->layer(), apps_grid_view_);
page_switcher_->SetY(suggestion_chip_container_view_->y() +
chip_grid_y_distance_);
animator.Run(page_switcher_);
animator.Run(page_switcher_->layer(), page_switcher_);
}
void AppsContainerView::UpdateYPositionAndOpacity(float progress,
......
......@@ -74,7 +74,7 @@ class APP_LIST_EXPORT AppsContainerView : public HorizontalPage {
// |current_progress| - the current app list transition progress.
// |animator| - callback that when run starts the opacity animation.
using OpacityAnimator =
base::RepeatingCallback<void(views::View*, bool target_visibility)>;
base::RepeatingCallback<void(views::View* view, bool target_visibility)>;
void AnimateOpacity(float current_progress,
AppListViewState target_view_state,
const OpacityAnimator& animator);
......@@ -83,7 +83,8 @@ class APP_LIST_EXPORT AppsContainerView : public HorizontalPage {
// |animator| for each of them to run transform animation from current bounds.
// (This assumes that animator knows the offset between current apps container
// bounds and target apps container bounds).
using TransformAnimator = base::RepeatingCallback<void(views::View*)>;
using TransformAnimator =
base::RepeatingCallback<void(ui::Layer*, views::View*)>;
void AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator);
......
......@@ -24,6 +24,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/chromeos/search_box/search_box_constants.h"
#include "ui/compositor_extra/shadow.h"
#include "ui/views/background.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/layout/fill_layout.h"
......@@ -221,6 +222,23 @@ views::View* AssistantPageView::GetLastFocusableView() {
this, GetWidget(), /*reverse=*/true, /*dont_loop=*/false);
}
void AssistantPageView::AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) {
// Assistant page view may host native views for its content. The native view
// hosts use view to widget coordinate conversion to calculate the native view
// bounds, and thus depend on the view transform values.
// Make sure the view is laid out before starting the transform animation so
// native views are not placed according to interim, animated page transform
// value.
layer()->GetAnimator()->StopAnimatingProperty(
ui::LayerAnimationElement::TRANSFORM);
if (needs_layout())
Layout();
animator.Run(layer(), this);
animator.Run(view_shadow_->shadow()->shadow_layer(), nullptr);
}
void AssistantPageView::OnUiVisibilityChanged(
AssistantVisibility new_visibility,
AssistantVisibility old_visibility,
......
......@@ -56,6 +56,8 @@ class APP_LIST_EXPORT AssistantPageView : public AppListPage,
const gfx::Rect& search_box_bounds) const override;
views::View* GetFirstFocusableView() override;
views::View* GetLastFocusableView() override;
void AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) override;
// AssistantUiModelObserver:
void OnUiVisibilityChanged(
......
......@@ -33,6 +33,7 @@
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/view_constants_aura.h"
#include "ui/views/view_model.h"
#include "ui/views/widget/widget.h"
......@@ -833,11 +834,12 @@ void ContentsView::AnimateToViewState(AppListViewState target_view_state,
// Animates layer's vertical position (using transform animation).
// |layer| - The layer to transform.
// |view| - Optional, the view to which the layer belongs (if the layer is a
// view layer).
// |y_offset| - The initial vertical offset - the layer's vertical offset will
// be animated to 0.
auto animate_transform = [](base::TimeDelta duration, float y_offset,
views::View* view) {
ui::Layer* layer = view->layer();
ui::Layer* layer, views::View* view) {
gfx::Transform transform;
transform.Translate(0, y_offset);
layer->SetTransform(transform);
......@@ -849,7 +851,8 @@ void ContentsView::AnimateToViewState(AppListViewState target_view_state,
settings->SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
// Observer will delete itself after animation completes.
settings->AddObserver(new AccessibilityAnimationObserver(view));
if (view)
settings->AddObserver(new AccessibilityAnimationObserver(view));
layer->SetTransform(gfx::Transform());
};
......@@ -900,7 +903,7 @@ void ContentsView::AnimateToViewState(AppListViewState target_view_state,
// For search box, animate the search_box view layer instead of the widget
// layer to avoid conflict with pagination model transitions (which update the
// search box widget layer transform as the transition progresses).
animate_transform(duration, y_offset, search_box);
animate_transform(duration, y_offset, search_box->layer(), search_box);
// Update app list page bounds to their target values. This assumes that
// potential in-progress pagination transition does not directly animate page
......@@ -908,17 +911,23 @@ void ContentsView::AnimateToViewState(AppListViewState target_view_state,
for (AppListPage* page : app_list_pages_) {
page->UpdatePageBoundsForState(target_page, GetContentsBounds(),
target_search_box_bounds);
if (page != horizontal_page_container_) {
animate_opacity(duration, page, closing ? 0.0f : 1.0f);
animate_transform(duration, y_offset, page);
} else {
GetAppsContainerView()->AnimateOpacity(
progress, target_view_state,
base::BindRepeating(animate_opacity, duration));
GetAppsContainerView()->AnimateYPosition(
target_view_state,
base::BindRepeating(animate_transform, duration, y_offset));
}
page->AnimateOpacity(progress, target_view_state,
base::BindRepeating(animate_opacity, duration));
page->AnimateYPosition(
target_view_state,
base::BindRepeating(animate_transform, duration, y_offset));
}
// Assistant page and search results page may host native views (e.g. for
// search result answer cards, or card assistant results). These windows are
// descendants of the app list view window layer rather than the page layers,
// so they have to be animated separately from their associated page.
for (auto* child_window : GetWidget()->GetNativeWindow()->children()) {
View* host_view = child_window->GetProperty(views::kHostViewKey);
if (!host_view)
continue;
animate_transform(duration, y_offset, child_window->layer(), nullptr);
}
last_target_view_state_ = target_view_state;
......@@ -930,7 +939,7 @@ void ContentsView::AnimateToViewState(AppListViewState target_view_state,
animate_transform(
duration,
expand_arrow_view()->CalculateOffsetFromCurrentAppListProgress(progress),
expand_arrow_view());
expand_arrow_view()->layer(), expand_arrow_view());
}
void ContentsView::SetExpandArrowViewVisibility(bool show) {
......
......@@ -168,6 +168,19 @@ bool HorizontalPageContainer::ShouldShowSearchBox() const {
return GetSelectedPage()->ShouldShowSearchBox();
}
void HorizontalPageContainer::AnimateOpacity(float current_progress,
AppListViewState target_view_state,
const OpacityAnimator& animator) {
apps_container_view_->AnimateOpacity(current_progress, target_view_state,
animator);
}
void HorizontalPageContainer::AnimateYPosition(
AppListViewState target_view_state,
const TransformAnimator& animator) {
apps_container_view_->AnimateYPosition(target_view_state, animator);
}
void HorizontalPageContainer::OnTabletModeChanged(bool started) {
pagination_controller_->set_is_tablet_mode(started);
}
......
......@@ -46,6 +46,11 @@ class APP_LIST_EXPORT HorizontalPageContainer : public AppListPage,
views::View* GetFirstFocusableView() override;
views::View* GetLastFocusableView() override;
bool ShouldShowSearchBox() const override;
void AnimateOpacity(float current_progress,
AppListViewState target_view_state,
const OpacityAnimator& animator) override;
void AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) override;
AppsContainerView* apps_container_view() { return apps_container_view_; }
......
......@@ -537,6 +537,23 @@ void SearchResultPageView::OnShown() {
ScheduleResultsChangedA11yNotification();
}
void SearchResultPageView::AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) {
// Search result page view may host a native view to show answer card results.
// The native view hosts use view to widget coordinate conversion to calculate
// the native view bounds, and thus depend on the view transform values.
// Make sure the view is laid out before starting the transform animation so
// native views are not placed according to interim, animated page transform
// value.
layer()->GetAnimator()->StopAnimatingProperty(
ui::LayerAnimationElement::TRANSFORM);
if (needs_layout())
Layout();
animator.Run(layer(), this);
animator.Run(view_shadow_->shadow()->shadow_layer(), nullptr);
}
void SearchResultPageView::OnAnimationStarted(AppListState from_state,
AppListState to_state) {
if (from_state != AppListState::kStateSearchResults &&
......
......@@ -54,6 +54,8 @@ class APP_LIST_EXPORT SearchResultPageView
// AppListPage overrides:
void OnHidden() override;
void OnShown() override;
void AnimateYPosition(AppListViewState target_view_state,
const TransformAnimator& animator) override;
void OnAnimationStarted(AppListState from_state,
AppListState to_state) override;
......
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