Commit 0a733f9c authored by Darren Shen's avatar Darren Shen Committed by Commit Bot

vk: Add swipe up gesture to VK to access shelf gestures.

Right now, when the VK is up, the user cannot perform shelf gestures
to access the hotseat or overview mode. This patch adds the ability
for users to swipe up from the bottom of the VK to perform the normal
shelf gestures.

It does this by detecting SCROLL_BEGIN gesture events and forwarding
them directly to the shelf, so that the rest of the gestures act
directly on the shelf.

Change-Id: I8d409f8242b4b95f061afb86254c99103de38798
Bug: 1030814
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2071678Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Commit-Queue: Darren Shen <shend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749397}
parent d25032f5
......@@ -13,11 +13,16 @@
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "ui/aura/env.h"
#include "ui/aura/window_delegate.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/wm/core/coordinate_conversion.h"
......@@ -252,6 +257,19 @@ aura::Window* KeyboardControllerImpl::GetContainerForDefaultDisplay() {
has_touch_display ? *first_touch_display : screen->GetPrimaryDisplay());
}
void KeyboardControllerImpl::TransferGestureEventToShelf(
const ui::GestureEvent& e) {
ash::Shelf* shelf =
ash::Shelf::ForWindow(keyboard_ui_controller_->GetKeyboardWindow());
if (shelf) {
shelf->ProcessGestureEvent(e);
aura::Env::GetInstance()->gesture_recognizer()->TransferEventsTo(
keyboard_ui_controller_->GetGestureConsumer(), shelf->GetWindow(),
ui::TransferTouchesBehavior::kCancel);
HideKeyboard(HideReason::kUser);
}
}
void KeyboardControllerImpl::OnKeyboardConfigChanged(
const keyboard::KeyboardConfig& config) {
for (auto& observer : observers_)
......
......@@ -84,6 +84,7 @@ class ASH_EXPORT KeyboardControllerImpl
aura::Window* GetContainerForDefaultDisplay() override;
aura::Window* GetContainerForDisplay(
const display::Display& display) override;
void TransferGestureEventToShelf(const ui::GestureEvent& e) override;
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
......
......@@ -13,18 +13,23 @@
#include "ash/keyboard/ui/test/keyboard_test_util.h"
#include "ash/public/cpp/keyboard/keyboard_controller.h"
#include "ash/public/cpp/test/test_keyboard_controller_observer.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/constants/chromeos_features.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/wm/core/window_util.h"
using keyboard::KeyboardConfig;
using keyboard::KeyboardEnableFlag;
......@@ -33,6 +38,10 @@ namespace ash {
namespace {
ShelfLayoutManager* GetShelfLayoutManager() {
return AshTestBase::GetPrimaryShelf()->shelf_layout_manager();
}
class TestContainerBehavior : public keyboard::ContainerBehavior {
public:
TestContainerBehavior() : keyboard::ContainerBehavior(nullptr) {}
......@@ -67,6 +76,10 @@ class TestContainerBehavior : public keyboard::ContainerBehavior {
const display::Display& current_display) override {
return false;
}
bool HandleGestureEvent(const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) override {
return false;
}
keyboard::ContainerType GetType() const override { return type_; }
......@@ -110,6 +123,9 @@ class KeyboardControllerImplTest : public AshTestBase {
~KeyboardControllerImplTest() override = default;
void SetUp() override {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(chromeos::features::kShelfHotseat);
AshTestBase::SetUp();
// Set the initial observer config to the default config.
......@@ -552,4 +568,61 @@ TEST_F(KeyboardControllerImplTest, ShowKeyboardInSecondaryDisplay) {
!keyboard_ui_controller()->GetKeyboardWindow()->bounds().IsEmpty());
}
TEST_F(KeyboardControllerImplTest, SwipeUpToShowHotSeat) {
TabletModeControllerTestApi().EnterTabletMode();
std::unique_ptr<aura::Window> window =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
wm::ActivateWindow(window.get());
keyboard_controller()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
keyboard_ui_controller()->ShowKeyboard(/* lock */ false);
ASSERT_TRUE(keyboard::WaitUntilShown());
gfx::Rect display_bounds =
display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
const gfx::Point start(display_bounds.bottom_center());
const gfx::Point end(start + gfx::Vector2d(0, -80));
const base::TimeDelta time_delta = base::TimeDelta::FromMilliseconds(100);
const int num_scroll_steps = 4;
GetEventGenerator()->GestureScrollSequence(start, end, time_delta,
num_scroll_steps);
// Keyboard should hide and gesture should forward to the shelf.
ASSERT_TRUE(keyboard::WaitUntilHidden());
EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
}
TEST_F(KeyboardControllerImplTest, FlingUpToShowOverviewMode) {
TabletModeControllerTestApi().EnterTabletMode();
std::unique_ptr<aura::Window> window =
AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
wm::ActivateWindow(window.get());
keyboard_controller()->SetEnableFlag(KeyboardEnableFlag::kExtensionEnabled);
keyboard_ui_controller()->ShowKeyboard(/* lock */ false);
ASSERT_TRUE(keyboard::WaitUntilShown());
gfx::Rect display_bounds =
display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
const gfx::Point start(display_bounds.bottom_center());
const gfx::Point end(start + gfx::Vector2d(0, -200));
const int fling_speed =
DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 1;
const int scroll_steps = 20;
base::TimeDelta scroll_time =
GetEventGenerator()->CalculateScrollDurationForFlingVelocity(
start, end, fling_speed, scroll_steps);
GetEventGenerator()->GestureScrollSequence(start, end, scroll_time,
scroll_steps);
// Keyboard should hide and gesture should forward to the shelf.
ASSERT_TRUE(keyboard::WaitUntilHidden());
EXPECT_EQ(HotseatState::kShownHomeLauncher,
GetShelfLayoutManager()->hotseat_state());
}
} // namespace ash
......@@ -40,6 +40,10 @@ aura::Window* TestKeyboardUI::GetKeyboardWindow() const {
return keyboard_window_.get();
}
ui::GestureConsumer* TestKeyboardUI::GetGestureConsumer() const {
return GetKeyboardWindow();
}
ui::InputMethod* TestKeyboardUI::GetInputMethod() {
aura::Window* active_window = window_util::GetActiveWindow();
aura::Window* root_window = active_window ? active_window->GetRootWindow()
......
......@@ -27,6 +27,7 @@ class TestKeyboardUI : public keyboard::KeyboardUI {
// Overridden from KeyboardUI:
aura::Window* LoadKeyboardWindow(LoadCallback callback) override;
aura::Window* GetKeyboardWindow() const override;
ui::GestureConsumer* GetGestureConsumer() const override;
private:
// Overridden from keyboard::KeyboardUI:
......
......@@ -8,6 +8,7 @@
#include "ash/keyboard/ui/keyboard_export.h"
#include "ash/public/cpp/keyboard/keyboard_types.h"
#include "ui/display/display.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
......@@ -38,6 +39,8 @@ class KEYBOARD_EXPORT ContainerBehavior {
virtual void MoveKeyboardWindow(const gfx::Rect& new_bounds) = 0;
virtual void MoveKeyboardWindowToDisplay(const display::Display& display,
const gfx::Rect& new_bounds) = 0;
// Needed for ContainerFullWidthBehavior to forward gestures to the shelf.
virtual void TransferGestureEventToShelf(const ui::GestureEvent& event) = 0;
};
explicit ContainerBehavior(Delegate* delegate);
......@@ -85,6 +88,8 @@ class KEYBOARD_EXPORT ContainerBehavior {
virtual bool HandlePointerEvent(const ui::LocatedEvent& event,
const display::Display& current_display) = 0;
virtual bool HandleGestureEvent(const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) = 0;
virtual ContainerType GetType() const = 0;
......
......@@ -304,6 +304,12 @@ bool ContainerFloatingBehavior::HandlePointerEvent(
return false;
}
bool ContainerFloatingBehavior::HandleGestureEvent(
const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) {
return false;
}
void ContainerFloatingBehavior::SetCanonicalBounds(
aura::Window* container,
const gfx::Rect& display_bounds) {
......
......@@ -42,6 +42,9 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
const gfx::Size& screen_size) override;
bool HandlePointerEvent(const ui::LocatedEvent& event,
const display::Display& current_display) override;
bool HandleGestureEvent(const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
ContainerType GetType() const override;
......
......@@ -14,6 +14,11 @@ namespace keyboard {
// The virtual keyboard show/hide animation duration.
constexpr int kFullWidthKeyboardAnimationDurationMs = 100;
// The height of the area from the bottom of the keyboard where the user can
// swipe up to access the shelf. Manually calculated to be slightly below
// the virtual keyboard's space bar.
constexpr int kSwipeUpGestureAreaHeight = 25;
ContainerFullWidthBehavior::ContainerFullWidthBehavior(Delegate* delegate)
: ContainerBehavior(delegate) {}
......@@ -92,6 +97,23 @@ bool ContainerFullWidthBehavior::HandlePointerEvent(
return false;
}
bool ContainerFullWidthBehavior::HandleGestureEvent(
const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) {
if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) {
// Check that the user is swiping upwards near the bottom of the keyboard.
// The coordinates of the |event| is relative to the window.
const auto details = event.details();
if (std::abs(details.scroll_y_hint()) > std::abs(details.scroll_x_hint()) &&
details.scroll_y_hint() < 0 &&
event.y() > bounds_in_screen.height() - kSwipeUpGestureAreaHeight) {
delegate_->TransferGestureEventToShelf(event);
return true;
}
}
return false;
}
void ContainerFullWidthBehavior::SetCanonicalBounds(
aura::Window* container,
const gfx::Rect& display_bounds) {
......
......@@ -35,6 +35,8 @@ class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior {
const gfx::Size& screen_size) override;
bool HandlePointerEvent(const ui::LocatedEvent& event,
const display::Display& current_display) override;
bool HandleGestureEvent(const ui::GestureEvent& event,
const gfx::Rect& bounds_in_screen) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
ContainerType GetType() const override;
......
......@@ -18,6 +18,9 @@ void KeyboardEventHandler::OnGestureEvent(ui::GestureEvent* event) {
event->StopPropagation();
break;
default:
auto* controller = KeyboardUIController::Get();
if (controller->IsEnabled() && controller->HandleGestureEvent(*event))
event->SetHandled();
break;
}
}
......
......@@ -4,12 +4,17 @@
#include "ash/keyboard/ui/keyboard_event_handler.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
namespace keyboard {
TEST(KeyboardEventHandlerTest, HandleGestureEvents) {
// KeyboardEventHandler needs a KeyboardUIController to be present, otherwise
// handling gesture events will crash.
KeyboardUIController controller;
KeyboardEventHandler filter;
ui::GestureEvent pinch_begin(
15, 15, 0, base::TimeTicks(),
......
......@@ -8,6 +8,7 @@
#include <stdint.h>
#include "ash/keyboard/ui/keyboard_export.h"
#include "ui/events/event.h"
namespace display {
class Display;
......@@ -32,6 +33,11 @@ class KEYBOARD_EXPORT KeyboardLayoutDelegate {
// Get the container window for a particular display. |display| must be valid.
virtual aura::Window* GetContainerForDisplay(
const display::Display& display) = 0;
// Transfer a gesture event to the Ash shelf. Any remaining gestures will be
// sent directly to the shelf. Used for accessing the shelf and the home
// screen even when the virtual keyboard is blocking the shelf.
virtual void TransferGestureEventToShelf(const ui::GestureEvent& e) = 0;
};
} // namespace keyboard
......
......@@ -9,6 +9,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/events/gestures/gesture_types.h"
namespace aura {
class Window;
......@@ -41,6 +42,10 @@ class KEYBOARD_EXPORT KeyboardUI {
// loading.
virtual aura::Window* GetKeyboardWindow() const = 0;
// Get the gesture consumer for the keyboard, which may be different to the
// window itself if there are nested windows.
virtual ui::GestureConsumer* GetGestureConsumer() const = 0;
// Gets the InputMethod that will provide notifications about changes in the
// text input context.
virtual ui::InputMethod* GetInputMethod() = 0;
......
......@@ -28,6 +28,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_observer.h"
......@@ -39,6 +40,7 @@
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/ozone/public/input_controller.h"
......@@ -302,6 +304,10 @@ aura::Window* KeyboardUIController::GetKeyboardWindow() const {
return ui_ ? ui_->GetKeyboardWindow() : nullptr;
}
ui::GestureConsumer* KeyboardUIController::GetGestureConsumer() const {
return ui_ ? ui_->GetGestureConsumer() : nullptr;
}
aura::Window* KeyboardUIController::GetRootWindow() const {
return parent_container_ ? parent_container_->GetRootWindow() : nullptr;
}
......@@ -747,6 +753,11 @@ void KeyboardUIController::MoveKeyboardWindowToDisplay(
HideKeyboardTemporarilyForTransition();
}
void KeyboardUIController::TransferGestureEventToShelf(
const ui::GestureEvent& e) {
layout_delegate_->TransferGestureEventToShelf(e);
}
// aura::WindowObserver overrides
void KeyboardUIController::OnWindowAddedToRootWindow(aura::Window* window) {
......@@ -1026,6 +1037,10 @@ bool KeyboardUIController::HandlePointerEvent(const ui::LocatedEvent& event) {
return container_behavior_->HandlePointerEvent(event, current_display);
}
bool KeyboardUIController::HandleGestureEvent(const ui::GestureEvent& event) {
return container_behavior_->HandleGestureEvent(event, GetBoundsInScreen());
}
void KeyboardUIController::SetContainerType(
ContainerType type,
const base::Optional<gfx::Rect>& target_bounds_in_root,
......
......@@ -32,6 +32,7 @@
#include "ui/base/ime/input_method_observer.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/events/event.h"
#include "ui/events/gestures/gesture_types.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
......@@ -86,6 +87,10 @@ class KEYBOARD_EXPORT KeyboardUIController
// created yet.
aura::Window* GetKeyboardWindow() const;
// Returns the gesture consumer for the keyboard, or null if the keyboard
// window has not been created yet.
ui::GestureConsumer* GetGestureConsumer() const;
// Returns the root window that this keyboard controller is attached to, or
// null if the keyboard has not been attached to any root window.
aura::Window* GetRootWindow() const;
......@@ -215,6 +220,7 @@ class KEYBOARD_EXPORT KeyboardUIController
// Handle mouse and touch events on the keyboard. The effects of this method
// will not stop propagation to the keyboard extension.
bool HandlePointerEvent(const ui::LocatedEvent& event);
bool HandleGestureEvent(const ui::GestureEvent& event);
// Sets the active container type. If the keyboard is currently shown, this
// will trigger a hide animation and a subsequent show animation. Otherwise
......@@ -287,6 +293,7 @@ class KEYBOARD_EXPORT KeyboardUIController
void MoveKeyboardWindow(const gfx::Rect& new_bounds) override;
void MoveKeyboardWindowToDisplay(const display::Display& display,
const gfx::Rect& new_bounds) override;
void TransferGestureEventToShelf(const ui::GestureEvent& e) override;
// aura::WindowObserver overrides
void OnWindowAddedToRootWindow(aura::Window* window) override;
......
......@@ -21,4 +21,7 @@ aura::Window* TestKeyboardLayoutDelegate::GetContainerForDisplay(
return root_window_;
}
void TestKeyboardLayoutDelegate::TransferGestureEventToShelf(
const ui::GestureEvent& e) {}
} // namespace keyboard
......@@ -25,6 +25,7 @@ class TestKeyboardLayoutDelegate : public KeyboardLayoutDelegate {
aura::Window* GetContainerForDefaultDisplay() override;
aura::Window* GetContainerForDisplay(
const display::Display& display) override;
void TransferGestureEventToShelf(const ui::GestureEvent& e) override;
private:
aura::Window* root_window_;
......
......@@ -56,6 +56,11 @@ aura::Window* TestKeyboardUIFactory::TestKeyboardUI::GetKeyboardWindow() const {
return window_.get();
}
ui::GestureConsumer* TestKeyboardUIFactory::TestKeyboardUI::GetGestureConsumer()
const {
return GetKeyboardWindow();
}
ui::InputMethod* TestKeyboardUIFactory::TestKeyboardUI::GetInputMethod() {
return input_method_;
}
......
......@@ -31,6 +31,7 @@ class TestKeyboardUIFactory : public KeyboardUIFactory {
// Overridden from KeyboardUI:
aura::Window* LoadKeyboardWindow(LoadCallback callback) override;
aura::Window* GetKeyboardWindow() const override;
ui::GestureConsumer* GetGestureConsumer() const override;
ui::InputMethod* GetInputMethod() override;
void ReloadKeyboardIfNeeded() override {}
......
......@@ -69,6 +69,12 @@ aura::Window* ChromeKeyboardUI::GetKeyboardWindow() const {
: nullptr;
}
ui::GestureConsumer* ChromeKeyboardUI::GetGestureConsumer() const {
return keyboard_contents_
? keyboard_contents_->web_contents()->GetContentNativeView()
: nullptr;
}
ui::InputMethod* ChromeKeyboardUI::GetInputMethod() {
ui::IMEBridge* bridge = ui::IMEBridge::Get();
if (!bridge || !bridge->GetInputContextHandler()) {
......
......@@ -37,6 +37,7 @@ class ChromeKeyboardUI : public keyboard::KeyboardUI,
// keyboard::KeyboardUI:
aura::Window* LoadKeyboardWindow(LoadCallback callback) override;
aura::Window* GetKeyboardWindow() const override;
ui::GestureConsumer* GetGestureConsumer() const override;
ui::InputMethod* GetInputMethod() override;
void ReloadKeyboardIfNeeded() 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