Commit 30a59b17 authored by Alex Newcomer's avatar Alex Newcomer Committed by Commit Bot

cros: Added Launcher Animations

First round of launcher animations.
The launcher now animates from the bottom of the screen when it is
loaded.
The launcher also animates between states.
When the launcher is closed it keeps its old closing animation (for
now).

Round 2 changes:
Linking the launcher animation with the search result animation.
Jank improvements.

** Also in this CL: **

AppListView cleanup
AppListPresenterDelegateUnittest fixes
-Introduced HalfToPeekingByClickorTap to test for this use case.
-Refactored and parameterized TapAndClickOutsideClosesHalfAppList 

BUG=735498

Change-Id: I11bc0324f9b34d0257e6c08642f0bddb512fa4e4
Reviewed-on: https://chromium-review.googlesource.com/576257
Commit-Queue: Alex Newcomer <newcomer@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488513}
parent 194e4851
......@@ -145,7 +145,6 @@ TEST_P(AppListPresenterDelegateTest, HideOnFocusOut) {
std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
wm::ActivateWindow(window.get());
EXPECT_FALSE(app_list_presenter_impl()->GetTargetVisibility());
}
......@@ -171,6 +170,7 @@ TEST_F(AppListPresenterDelegateTest, ClickOutsideBubbleClosesBubble) {
aura::Window* app_window = app_list_presenter_impl()->GetWindow();
ASSERT_TRUE(app_window);
ui::test::EventGenerator& generator = GetEventGenerator();
// Click on the bubble itself. The bubble should remain visible.
generator.MoveMouseToCenterOf(app_window);
generator.ClickLeftButton();
......@@ -189,12 +189,11 @@ TEST_F(AppListPresenterDelegateTest, ClickOutsideBubbleClosesBubble) {
// Tests that tapping outside the app-list bubble closes it.
TEST_F(AppListPresenterDelegateTest, TapOutsideBubbleClosesBubble) {
app_list_presenter_impl()->Show(GetPrimaryDisplayId());
aura::Window* app_window = app_list_presenter_impl()->GetWindow();
ASSERT_TRUE(app_window);
gfx::Rect app_window_bounds = app_window->GetBoundsInRootWindow();
ui::test::EventGenerator& generator = GetEventGenerator();
// Click on the bubble itself. The bubble should remain visible.
generator.GestureTapAt(app_window_bounds.CenterPoint());
EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility());
......@@ -472,6 +471,7 @@ TEST_F(FullscreenAppListPresenterDelegateTest,
app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
EXPECT_EQ(app_list->app_list_state(),
app_list::AppListView::FULLSCREEN_ALL_APPS);
// Type in the search box to transition to |FULLSCREEN_SEARCH|.
ui::test::EventGenerator& generator = GetEventGenerator();
generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
......@@ -558,7 +558,6 @@ TEST_P(FullscreenAppListPresenterDelegateTest,
// Tap outside the search box, the AppListView should transition to Peeking
// and the search box should be inactive.
if (test_mouse_event) {
generator.MoveMouseTo(GetPointOutsideSearchbox());
generator.ClickLeftButton();
......@@ -703,10 +702,9 @@ TEST_F(AppListPresenterDelegateTest,
SHELF_BACKGROUND_DEFAULT);
}
// Tests that the half app list closes if the user taps outside its bounds.
TEST_F(FullscreenAppListPresenterDelegateTest,
TapAndClickOutsideClosesHalfAppList) {
// TODO(newcomer): Investigate mash failures crbug.com/726838
// Tests that the app list in HALF with an active search transitions to PEEKING
// after the body is clicked/tapped.
TEST_P(FullscreenAppListPresenterDelegateTest, HalfToPeekingByClickOrTap) {
app_list_presenter_impl()->Show(GetPrimaryDisplayId());
ui::test::EventGenerator& generator = GetEventGenerator();
......@@ -715,38 +713,46 @@ TEST_F(FullscreenAppListPresenterDelegateTest,
app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
// Grab the bounds of the search box,
// which is guaranteed to be inside the app list.
gfx::Point tap_point = app_list_presenter_impl()
->GetView()
->search_box_widget()
->GetContentsView()
->GetBoundsInScreen()
.CenterPoint();
// Tapping inside the bounds doesn't close the app list.
generator.GestureTapAt(tap_point);
EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility());
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
// Clicking inside the bounds doesn't close the app list.
generator.MoveMouseTo(tap_point);
generator.ClickLeftButton();
EXPECT_TRUE(app_list_presenter_impl()->IsVisible());
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
// Click or Tap the app list view body.
if (TestMouseEventParam()) {
generator.MoveMouseTo(GetPointOutsideSearchbox());
generator.ClickLeftButton();
generator.ReleaseLeftButton();
} else {
generator.GestureTapAt(GetPointOutsideSearchbox());
}
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
// Tapping outside the bounds closes the app list.
generator.GestureTapAt(gfx::Point(10, 10));
EXPECT_FALSE(app_list_presenter_impl()->IsVisible());
// Click or Tap the app list view body again.
if (TestMouseEventParam()) {
generator.MoveMouseTo(GetPointOutsideSearchbox());
generator.ClickLeftButton();
generator.ReleaseLeftButton();
} else {
generator.GestureTapAt(GetPointOutsideSearchbox());
}
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED);
}
// Reset the app list to half state.
// Tests that the half app list closes if the user taps outside its bounds.
TEST_P(FullscreenAppListPresenterDelegateTest,
TapAndClickOutsideClosesHalfAppList) {
// TODO(newcomer): Investigate mash failures crbug.com/726838
app_list_presenter_impl()->Show(GetPrimaryDisplayId());
ui::test::EventGenerator& generator = GetEventGenerator();
// Transition to half app list by entering text.
generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
// Clicking outside the bounds closes the app list.
generator.MoveMouseTo(gfx::Point(10, 10));
generator.ClickLeftButton();
// Clicking/tapping outside the bounds closes the app list.
if (TestMouseEventParam()) {
generator.MoveMouseTo(gfx::Point(10, 10));
generator.ClickLeftButton();
} else {
generator.GestureTapAt(gfx::Point(10, 10));
}
EXPECT_FALSE(app_list_presenter_impl()->IsVisible());
}
......
......@@ -3,6 +3,8 @@
-FullscreenAppListPresenterDelegateTest.AppListViewDragHandlerTabletModeFromSearch
-FullscreenAppListPresenterDelegateTest.BottomShelfAlignmentTextStateTransitions
-FullscreenAppListPresenterDelegateTest.HalfToFullscreenWhenTabletModeIsActive
-FullscreenAppListPresenterDelegateTest.HalfToPeekingByClickOrTap/0
-FullscreenAppListPresenterDelegateTest.HalfToPeekingByClickOrTap/1
-FullscreenAppListPresenterDelegateTest.KeyPressEnablesSearchBox
-FullscreenAppListPresenterDelegateTest.TabletModeTextStateTransitions
-FullscreenAppListPresenterDelegateTest.PeekingToFullscreenWhenTabletModeIsActive
......@@ -12,7 +14,8 @@
-FullscreenAppListPresenterDelegateTest.StateTransitionsByTappingAppListBodyFromFullscreen/0
-FullscreenAppListPresenterDelegateTest.StateTransitionsByTappingAppListBodyFromFullscreen/1
-FullscreenAppListPresenterDelegateTest.TapAndClickEnablesSearchBox
-FullscreenAppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList
-FullscreenAppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList/0
-FullscreenAppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList/1
-FullscreenAppListPresenterDelegateTest.TapAndClickOutsideClosesPeekingAppList
-FullscreenAppListPresenterDelegateTest.WhitespaceQuery
-NativeCursorManagerAshTest.FractionalScale
......
......@@ -30,6 +30,7 @@
#include "ui/base/ui_base_switches.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
......@@ -86,6 +87,9 @@ constexpr float kAppListOpacity = 0.8;
// The vertical position for the appearing animation of the speech UI.
constexpr float kSpeechUIAppearingPosition = 12;
// The animation duration for app list movement.
constexpr float kAppListAnimationDurationMs = 300;
// This view forwards the focus to the search box widget by providing it as a
// FocusTraversable when a focus search is provided.
class SearchBoxFocusHost : public views::View {
......@@ -451,14 +455,14 @@ void AppListView::InitChildWidgets() {
void AppListView::InitializeFullscreen(gfx::NativeView parent,
int initial_apps_page) {
gfx::Rect display_work_area_bounds =
display::Screen::GetScreen()
->GetDisplayNearestView(parent_window())
.work_area();
const display::Display display_nearest_view = GetDisplayNearestView();
const gfx::Rect display_work_area_bounds = display_nearest_view.work_area();
const int bottom_of_screen = display_nearest_view.size().height();
gfx::Rect app_list_overlay_view_bounds(
display_work_area_bounds.x(),
display_work_area_bounds.height() + kShelfSize - kPeekingAppListHeight,
bottom_of_screen, // Set the widget at the bottom of the screen so it can
// animate up when shown.
display_work_area_bounds.width(),
display_work_area_bounds.height() + kShelfSize);
......@@ -543,11 +547,10 @@ void AppListView::EndDrag(const gfx::Point& location) {
// When the SearchBoxView closes the app list, ignore the final event.
if (app_list_state_ == CLOSED)
return;
// Change the app list state based on where the drag ended. If fling velocity
// was over the threshold, snap to the next state in the direction of the
// fling.
int const new_y_position = location.y() - initial_drag_point_.y() +
fullscreen_widget_->GetWindowBoundsInScreen().y();
if (std::abs(last_fling_velocity_) >= kAppListDragVelocityThreshold) {
// If the user releases drag with velocity over the threshold, snap to
// the next state, ignoring the drag release position.
......@@ -584,10 +587,7 @@ void AppListView::EndDrag(const gfx::Point& location) {
}
}
} else {
int display_height = display::Screen::GetScreen()
->GetDisplayNearestView(parent_window())
.size()
.height();
const int display_height = GetDisplayNearestView().size().height();
int app_list_y_for_state = 0;
int app_list_height = 0;
switch (app_list_state_) {
......@@ -609,10 +609,13 @@ void AppListView::EndDrag(const gfx::Point& location) {
break;
}
int app_list_threshold = app_list_height / kAppListThresholdDenominator;
int drag_delta = app_list_y_for_state - new_y_position;
gfx::Point location_in_screen_coordinates = location;
ConvertPointToScreen(this, &location_in_screen_coordinates);
const int new_y_position =
location_in_screen_coordinates.y() - initial_drag_point_.y();
const int app_list_threshold =
app_list_height / kAppListThresholdDenominator;
const int drag_delta = app_list_y_for_state - new_y_position;
switch (app_list_state_) {
case FULLSCREEN_ALL_APPS:
if (std::abs(drag_delta) > app_list_threshold)
......@@ -655,6 +658,10 @@ void AppListView::EndDrag(const gfx::Point& location) {
}
}
display::Display AppListView::GetDisplayNearestView() const {
return display::Screen::GetScreen()->GetDisplayNearestView(parent_window());
}
void AppListView::SetStateFromSearchBoxView(bool search_box_is_empty) {
switch (app_list_state_) {
case PEEKING:
......@@ -888,20 +895,17 @@ void AppListView::SetState(AppListState new_state) {
new_state_override = FULLSCREEN_SEARCH;
}
gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
int display_height = display::Screen::GetScreen()
->GetDisplayNearestView(parent_window())
.size()
.height();
switch (new_state_override) {
case PEEKING: {
switch (app_list_state_) {
case HALF:
case FULLSCREEN_ALL_APPS:
StartAnimationForState(new_state_override);
app_list_main_view_->contents_view()->SetActiveState(
AppListModel::STATE_START);
break;
case PEEKING: {
int peeking_app_list_y = display_height - kPeekingAppListHeight;
new_widget_bounds.set_y(peeking_app_list_y);
StartAnimationForState(new_state_override);
app_list_main_view_->contents_view()->SetActiveState(
AppListModel::STATE_START);
search_box_view()->ClearSearch();
......@@ -918,8 +922,7 @@ void AppListView::SetState(AppListState new_state) {
switch (app_list_state_) {
case PEEKING:
case HALF: {
int half_app_list_y = display_height - kHalfAppListHeight;
new_widget_bounds.set_y(half_app_list_y);
StartAnimationForState(new_state_override);
break;
}
case FULLSCREEN_SEARCH:
......@@ -930,7 +933,7 @@ void AppListView::SetState(AppListState new_state) {
}
break;
case FULLSCREEN_ALL_APPS: {
new_widget_bounds.set_y(0);
StartAnimationForState(new_state_override);
AppsContainerView* apps_container_view =
app_list_main_view_->contents_view()->apps_container_view();
......@@ -942,17 +945,47 @@ void AppListView::SetState(AppListState new_state) {
break;
}
case FULLSCREEN_SEARCH:
new_widget_bounds.set_y(0);
StartAnimationForState(new_state_override);
break;
case CLOSED:
app_list_main_view_->Close();
delegate_->Dismiss();
break;
}
fullscreen_widget_->SetBounds(new_widget_bounds);
app_list_state_ = new_state_override;
}
void AppListView::StartAnimationForState(AppListState target_state) {
const int display_height = GetDisplayNearestView().size().height();
int target_state_y = 0;
switch (target_state) {
case PEEKING:
target_state_y = display_height - kPeekingAppListHeight;
break;
case HALF:
target_state_y = display_height - kHalfAppListHeight;
break;
default:
break;
}
gfx::Rect target_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
target_bounds.set_y(target_state_y);
std::unique_ptr<ui::LayerAnimationElement> animation_element =
ui::LayerAnimationElement::CreateBoundsElement(
target_bounds,
base::TimeDelta::FromMilliseconds(kAppListAnimationDurationMs));
animation_element->set_tween_type(gfx::Tween::EASE_OUT);
ui::LayerAnimator* animator = fullscreen_widget_->GetLayer()->GetAnimator();
animator->set_preemption_strategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
animator->ScheduleAnimation(
new ui::LayerAnimationSequence(std::move(animation_element)));
}
void AppListView::OnWidgetDestroying(views::Widget* widget) {
BubbleDialogDelegateView::OnWidgetDestroying(widget);
if (delegate_ && widget == GetWidget())
......@@ -1029,10 +1062,11 @@ void AppListView::OnSpeechRecognitionStateChanged(
speech_view_->SetVisible(true);
} else {
app_list_main_view_->SetVisible(true);
// Refocus the search box. However, if the app list widget does not have
// focus, it means another window has already taken focus, and we *must
// not* focus the search box (or we would steal focus back into the app
// list).
// Refocus the search box. However, if the app list widget does not
// have focus, it means another window has already taken focus, and we
// *must not* focus the search box (or we would steal focus back into
// the app list).
if (GetWidget()->IsActive())
search_box_view_->search_box()->RequestFocus();
}
......@@ -1044,14 +1078,12 @@ void AppListView::OnDisplayMetricsChanged(const display::Display& display,
return;
// Set the |fullscreen_widget_| size to fit the new display metrics.
gfx::Size size = display::Screen::GetScreen()
->GetDisplayNearestView(parent_window())
.work_area()
.size();
gfx::Size size = GetDisplayNearestView().work_area().size();
size.Enlarge(0, kShelfSize);
fullscreen_widget_->SetSize(size);
// Update the |fullscreen_widget_| bounds to accomodate the new work area.
// Update the |fullscreen_widget_| bounds to accomodate the new work
// area.
SetState(app_list_state_);
}
......
......@@ -94,10 +94,6 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
// hiding the app list when a modal dialog is being shown).
void SetAppListOverlayVisible(bool visible);
views::Widget* search_box_widget() const { return search_box_widget_; }
SearchBoxView* search_box_view() { return search_box_view_; }
// Overridden from views::View:
gfx::Size CalculatePreferredSize() const override;
void OnPaint(gfx::Canvas* canvas) override;
......@@ -109,8 +105,6 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
gfx::NativeView child,
const gfx::Point& location) override;
AppListMainView* app_list_main_view() { return app_list_main_view_; }
// Gets the PaginationModel owned by this view's apps grid.
PaginationModel* GetAppsPaginationModel();
......@@ -122,19 +116,26 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
// Changes the app list state.
void SetState(AppListState new_state);
// Kicks off the proper animation for the state change. If an animation is
// in progress it will be interrupted.
void StartAnimationForState(AppListState new_state);
// Changes the app list state depending on the current |app_list_state_| and
// whether the search box is empty.
void SetStateFromSearchBoxView(bool search_box_is_empty);
// Called when tablet mode starts and ends.
void OnTabletModeChanged(bool started);
bool is_fullscreen() const {
return app_list_state_ == FULLSCREEN_ALL_APPS ||
app_list_state_ == FULLSCREEN_SEARCH;
}
AppListState app_list_state() const { return app_list_state_; }
// Called when tablet mode starts and ends.
void OnTabletModeChanged(bool started);
AppListMainView* app_list_main_view() const { return app_list_main_view_; }
views::Widget* search_box_widget() const { return search_box_widget_; }
SearchBoxView* search_box_view() const { return search_box_view_; }
// Changes |app_list_state_| from |PEEKING| to |FULLSCREEN_ALL_APPS|.
bool HandleScroll(const ui::Event* event);
......@@ -167,6 +168,9 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
// release position and snap to the next state.
void EndDrag(const gfx::Point& location);
// Gets the display nearest to the parent window.
display::Display GetDisplayNearestView() const;
// Overridden from views::BubbleDialogDelegateView:
void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
views::Widget* widget) const override;
......@@ -221,7 +225,6 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
bool processing_scroll_event_series_;
// The state of the app list, controlled via SetState().
AppListState app_list_state_;
// An observer that notifies AppListView when the display has changed.
ScopedObserver<display::Screen, display::DisplayObserver> display_observer_;
......
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