Commit d646ae0a authored by MinChen's avatar MinChen Committed by Commit Bot

Swiping up on shelf to show the app list.

If the app list is not opened and shelf is visible, swipe up on the shelf
should show the app list.
If the app list is opened, swipe up on the shelf should keep the app list
opened. Tap anywhere else of shelf should close the app list.

This is the basic one currently. Will add some simple animations followed.
(e.g, change the opacity of the searchbox and apps row by row according
to the dragging amount)

Bug: 735999,742461
Change-Id: I5eb8b6d4d006a50720050b34168849e9d57370f2
Reviewed-on: https://chromium-review.googlesource.com/562739
Commit-Queue: min c <minch@chromium.org>
Reviewed-by: default avatarMustafa Emre Acer <meacer@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488781}
parent a4bb0a79
......@@ -228,7 +228,7 @@ void AppListPresenterDelegate::OnMouseEvent(ui::MouseEvent* event) {
}
void AppListPresenterDelegate::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_TAP_DOWN)
if (event->type() == ui::ET_GESTURE_SHOW_PRESS)
ProcessLocatedEvent(event);
}
......
......@@ -697,10 +697,8 @@ TEST_F(AppListPresenterDelegateTest,
app_list_presenter_impl()->Show(GetPrimaryDisplayId());
EXPECT_TRUE(app_list::features::IsFullscreenAppListEnabled());
EXPECT_FALSE(GetPrimaryShelf()->IsHorizontalAlignment());
// TODO(muyuanli): This should be SHELF_BACKGROUND_OVERLAP but the test
// construction code is not quite correct. See crbug.com/742461.
EXPECT_EQ(GetPrimaryShelf()->shelf_layout_manager()->GetShelfBackgroundType(),
SHELF_BACKGROUND_DEFAULT);
SHELF_BACKGROUND_OVERLAP);
}
// Tests that the half app list closes if the user taps outside its bounds.
......
This diff is collapsed.
......@@ -121,7 +121,7 @@ class ASH_EXPORT ShelfLayoutManager
// Processes a gesture event and updates the status of the shelf when
// appropriate. Returns true if the gesture has been handled and it should not
// be processed any further, false otherwise.
bool ProcessGestureEvent(const ui::GestureEvent& event);
bool ProcessGestureEvent(const ui::GestureEvent& event_in_screen);
// Set an animation duration override for the show / hide animation of the
// shelf. Specifying 0 leads to use the default.
......@@ -291,10 +291,12 @@ class ASH_EXPORT ShelfLayoutManager
bool IsShelfAutoHideForFullscreenMaximized() const;
// Gesture related functions:
void StartGestureDrag(const ui::GestureEvent& gesture);
void UpdateGestureDrag(const ui::GestureEvent& gesture);
void CompleteGestureDrag(const ui::GestureEvent& gesture);
void StartGestureDrag(const ui::GestureEvent& gesture_in_screen);
void UpdateGestureDrag(const ui::GestureEvent& gesture_in_screen);
void CompleteGestureDrag(const ui::GestureEvent& gesture_in_screen);
void CompleteAppListDrag(const ui::GestureEvent& gesture_in_screen);
void CancelGestureDrag();
bool CanStartFullscreenAppListDrag(float scroll_y_hint) const;
// Returns true if the gesture is swiping up on a hidden shelf or swiping down
// on a visible shelf; other gestures should not change shelf visibility.
......@@ -328,21 +330,21 @@ class ASH_EXPORT ShelfLayoutManager
// False when neither the auto hide timer nor the timer task are running.
bool mouse_over_shelf_when_auto_hide_timer_started_;
// Whether the fullscreen app list feature is enabled.
const bool is_fullscreen_app_list_enabled_;
base::ObserverList<ShelfLayoutManagerObserver> observers_;
// The shelf reacts to gesture-drags, and can be set to auto-hide for certain
// gestures. Some shelf behaviour (e.g. visibility state, background color
// etc.) are affected by various stages of the drag. The enum keeps track of
// the present status of the gesture drag.
// gestures. Swiping up from the shelf in tablet mode can open the
// fullscreen app list. Some shelf behaviour (e.g. visibility state,
// background color etc.) are affected by various stages of the drag. The enum
// keeps track of the present status of the gesture drag.
enum GestureDragStatus {
GESTURE_DRAG_NONE,
GESTURE_DRAG_IN_PROGRESS,
GESTURE_DRAG_CANCEL_IN_PROGRESS,
GESTURE_DRAG_COMPLETE_IN_PROGRESS
GESTURE_DRAG_COMPLETE_IN_PROGRESS,
GESTURE_DRAG_APPLIST_IN_PROGRESS,
};
GestureDragStatus gesture_drag_status_;
// Tracks the amount of the drag. The value is only valid when
......
......@@ -25,12 +25,17 @@
#include "ash/system/tray/test_system_tray_item.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/lock_state_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "ui/app_list/app_list_features.h"
#include "ui/app_list/presenter/app_list.h"
#include "ui/app_list/presenter/test/test_app_list_presenter.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/window.h"
......@@ -311,6 +316,80 @@ class ShelfLayoutManagerTest : public AshTestBase {
DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManagerTest);
};
TEST_F(ShelfLayoutManagerTest, SwipingUpOnShelfForFullscreenAppList) {
// TODO: investigate failure in mash, http://crbug.com/695686.
if (Shell::GetAshConfig() == Config::MASH)
return;
// TODO(minch): Add more tests for shelf alignment or mode changed during
// dragging. http://crbug.com/747016.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
app_list::features::kEnableFullscreenAppList);
Shell* shell = Shell::Get();
shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
Shelf* shelf = GetPrimaryShelf();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
// Note: A window must be visible in order to hide the shelf.
CreateTestWidget();
app_list::test::TestAppListPresenter test_app_list_presenter;
shell->app_list()->SetAppListPresenter(
test_app_list_presenter.CreateInterfacePtrAndBind());
ui::test::EventGenerator& generator(GetEventGenerator());
constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
constexpr int kNumScrollSteps = 4;
gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
gfx::Rect work_area_bounds = shelf->GetUserWorkAreaBounds();
gfx::Vector2d delta;
// Swiping up more than one third of the work area's height should show the
// app list.
delta.set_y(work_area_bounds.height() / 2.0);
gfx::Point end = start - delta;
generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
RunAllPendingInMessageLoop();
EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
EXPECT_EQ(1u, test_app_list_presenter.show_count());
EXPECT_EQ(0u, test_app_list_presenter.dismiss_count());
EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
// Swiping up less than one third of the works area's height should begin to
// show, but then ultimately dismiss the app list.
delta.set_y(work_area_bounds.height() / 4.0);
end = start - delta;
// TODO(minch): investigate failure without EnableMaximizeMode again here.
// http://crbug.com/746481.
shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
RunAllPendingInMessageLoop();
EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
EXPECT_EQ(2u, test_app_list_presenter.show_count());
EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
// Swiping down on the shelf should hide it.
end = start + delta;
generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
// Swiping up should show the shelf but not the app list if shelf is hidden.
generator.GestureScrollSequence(end, start, kTimeDelta, kNumScrollSteps);
RunAllPendingInMessageLoop();
EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(2u, test_app_list_presenter.show_count());
EXPECT_EQ(1u, test_app_list_presenter.dismiss_count());
EXPECT_GE(test_app_list_presenter.set_y_position_count(), 1u);
}
void ShelfLayoutManagerTest::RunGestureDragTests(gfx::Vector2d delta) {
Shelf* shelf = GetPrimaryShelf();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
......
......@@ -1487,6 +1487,12 @@ void ShelfView::ViewHierarchyChanged(
}
void ShelfView::OnGestureEvent(ui::GestureEvent* event) {
// Convert the event location from current view to screen, since swiping up on
// the shelf can open the fullscreen app list. Updating the bounds of the app
// list during dragging is based on screen coordinate space.
gfx::Point location_in_screen(event->location());
View::ConvertPointToScreen(this, &location_in_screen);
event->set_location(location_in_screen);
if (shelf_->ProcessGestureEvent(*event))
event->StopPropagation();
}
......
......@@ -492,6 +492,10 @@ void Shell::ShowAppList() {
.id());
}
void Shell::SetAppListYPosition(int y_position_in_screen) {
app_list_->SetYPosition(y_position_in_screen);
}
void Shell::DismissAppList() {
app_list_->Dismiss();
}
......
......@@ -539,6 +539,9 @@ class ASH_EXPORT Shell : public SessionObserver,
// Shows the app list on the active root window.
void ShowAppList();
// Set y position of app list bounds to |y_location_in_screen|.
void SetAppListYPosition(int y_position_in_screen);
// Dismisses the app list.
void DismissAppList();
......
......@@ -68,5 +68,7 @@ void ExampleAppListPresenter::ToggleAppList(int64_t display_id) {
void ExampleAppListPresenter::StartVoiceInteractionSession() {}
void ExampleAppListPresenter::SetYPosition(int new_y_position) {}
} // namespace shell
} // namespace ash
......@@ -27,6 +27,7 @@ class ExampleAppListPresenter : public app_list::mojom::AppListPresenter {
void Dismiss() override;
void ToggleAppList(int64_t display_id) override;
void StartVoiceInteractionSession() override;
void SetYPosition(int new_y_position) override;
private:
mojo::Binding<app_list::mojom::AppListPresenter> binding_;
......
......@@ -104,7 +104,15 @@ void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) {
views::Widget* target_widget =
static_cast<views::View*>(event->target())->GetWidget();
Shelf* shelf = Shelf::ForWindow(target_widget->GetNativeWindow());
if (shelf->ProcessGestureEvent(*event))
// Convert the event location from current view to screen, since swiping up on
// the shelf can open the fullscreen app list. Updating the bounds of the app
// list during dragging is based on screen coordinate space.
ui::GestureEvent event_in_screen(*event);
gfx::Point location_in_screen(event->location());
View::ConvertPointToScreen(this, &location_in_screen);
event_in_screen.set_location(location_in_screen);
if (shelf->ProcessGestureEvent(event_in_screen))
event->StopPropagation();
else
views::AccessiblePaneView::OnGestureEvent(event);
......
......@@ -14,6 +14,11 @@ TrayDragController::TrayDragController(Shelf* shelf) : shelf_(shelf) {}
void TrayDragController::ProcessGestureEvent(ui::GestureEvent* event,
TrayBackgroundView* tray_view) {
if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
Shell::Get()->DismissAppList();
return;
}
if (!Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled() ||
......
......@@ -53,6 +53,10 @@ void AppListPresenterService::StartVoiceInteractionSession() {
service->StartSessionFromUserInteraction(gfx::Rect());
}
void AppListPresenterService::SetYPosition(int y_position_in_screen) {
GetPresenter()->SetYPosition(y_position_in_screen);
}
app_list::AppListPresenterImpl* AppListPresenterService::GetPresenter() {
return AppListServiceAsh::GetInstance()->GetAppListPresenter();
}
......@@ -26,6 +26,7 @@ class AppListPresenterService : public app_list::mojom::AppListPresenter {
void Dismiss() override;
void ToggleAppList(int64_t display_id) override;
void StartVoiceInteractionSession() override;
void SetYPosition(int y_position_in_screen) override;
private:
app_list::AppListPresenterImpl* GetPresenter();
......
......@@ -27,6 +27,11 @@ void AppList::Show(int64_t display_id) {
presenter_->Show(display_id);
}
void AppList::SetYPosition(int y_position_in_screen) {
if (presenter_)
presenter_->SetYPosition(y_position_in_screen);
}
void AppList::Dismiss() {
if (presenter_)
presenter_->Dismiss();
......
......@@ -27,6 +27,8 @@ class APP_LIST_PRESENTER_EXPORT AppList : public mojom::AppList {
// Helper functions to call the underlying functionality on the presenter.
void Show(int64_t display_id);
void SetYPosition(int y_position_in_screen);
void Dismiss();
void ToggleAppList(int64_t display_id);
void StartVoiceInteractionSession();
......
......@@ -36,4 +36,7 @@ interface AppListPresenter {
// Starts a voice interaction session.
StartVoiceInteractionSession();
// Sets y position of the app list bounds to |y_position_in_screen|.
SetYPosition(int32 y_position_in_screen);
};
......@@ -82,6 +82,11 @@ void AppListPresenterImpl::Show(int64_t display_id) {
base::RecordAction(base::UserMetricsAction("Launcher_Show"));
}
void AppListPresenterImpl::SetYPosition(int y_position_in_screen) {
if (view_)
view_->SetYPosition(y_position_in_screen);
}
void AppListPresenterImpl::Dismiss() {
if (!is_visible_)
return;
......
......@@ -57,6 +57,9 @@ class APP_LIST_PRESENTER_EXPORT AppListPresenterImpl
// display (in which the |window| exists) the app list should be shown.
void Show(int64_t display_id);
// Sets y position of the app list bounds to |y_position_in_screen|.
void SetYPosition(int y_position_in_screen);
// Invoked to dismiss app list. This may leave the view open but hidden from
// the user.
void Dismiss();
......
......@@ -34,5 +34,9 @@ void TestAppListPresenter::StartVoiceInteractionSession() {
voice_session_count_++;
}
void TestAppListPresenter::SetYPosition(int y_position_in_screen) {
set_y_position_count_++;
}
} // namespace test
} // namespace app_list
......@@ -26,17 +26,20 @@ class TestAppListPresenter : public app_list::mojom::AppListPresenter {
void Dismiss() override;
void ToggleAppList(int64_t display_id) override;
void StartVoiceInteractionSession() override;
void SetYPosition(int y_position_in_screen) override;
size_t show_count() const { return show_count_; }
size_t dismiss_count() const { return dismiss_count_; }
size_t toggle_count() const { return toggle_count_; }
size_t voice_session_count() const { return voice_session_count_; }
size_t set_y_position_count() const { return set_y_position_count_; }
private:
size_t show_count_ = 0u;
size_t dismiss_count_ = 0u;
size_t toggle_count_ = 0u;
size_t voice_session_count_ = 0u;
size_t set_y_position_count_ = 0u;
mojo::Binding<app_list::mojom::AppListPresenter> binding_;
......
......@@ -527,15 +527,17 @@ void AppListView::UpdateDrag(const gfx::Point& location) {
// Update the bounds of the widget while maintaining the
// relative position of the top of the widget and the mouse/gesture.
// Block drags north of 0 and recalculate the initial_drag_point_.
int const new_y_position = location.y() - initial_drag_point_.y() +
fullscreen_widget_->GetWindowBoundsInScreen().y();
gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
if (new_y_position < 0) {
new_widget_bounds.set_y(0);
int new_y_position = location.y() - initial_drag_point_.y() +
fullscreen_widget_->GetWindowBoundsInScreen().y();
if (new_y_position < 0)
initial_drag_point_ = location;
} else {
new_widget_bounds.set_y(new_y_position);
}
SetYPosition(new_y_position);
}
void AppListView::SetYPosition(int y_position_in_screen) {
gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
new_widget_bounds.set_y(std::max(y_position_in_screen, 0));
fullscreen_widget_->SetBounds(new_widget_bounds);
}
......
......@@ -139,6 +139,9 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDialogDelegateView,
// Changes |app_list_state_| from |PEEKING| to |FULLSCREEN_ALL_APPS|.
bool HandleScroll(const ui::Event* event);
// Sets y position of the app list bounds to |y_position_in_screen|.
void SetYPosition(int y_position_in_screen);
private:
friend class test::AppListViewTestApi;
......
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