Commit 4ebccb50 authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Add a hook to enable login shelf swipe detection

On certain devices, the user will have an option to swipe from the shelf
on the last OOBE/first user run screen to end OOBE and enter the
session.

This adds a hook to login_screen interface that OOBE screen
implementation can use to enable gesture detection on login shelf, and
through which to get notified when the user swipes up.

Also, implements upward fling detection for login shelf (done by
login_shelf_gesture_controller, owned by shelf_widget) - when the
gesture detection is active, login shelf shows a drag handle with a
"contextual nudge" text above it.

Updates DragHandle API to support color/opacity changes, so the drag
handle appearance can be updated to match the login shelf controls on
OOBE and login screen.

BUG=976949

Change-Id: I670358c97de58c3f75ada9103df8098cc5074908
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2073541Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#745463}
parent 4c4cba8a
......@@ -616,6 +616,8 @@ component("ash") {
"shelf/hotseat_transition_animator.h",
"shelf/hotseat_widget.cc",
"shelf/hotseat_widget.h",
"shelf/login_shelf_gesture_controller.cc",
"shelf/login_shelf_gesture_controller.h",
"shelf/login_shelf_view.cc",
"shelf/login_shelf_view.h",
"shelf/overflow_bubble.cc",
......@@ -1885,6 +1887,7 @@ test("ash_unittests") {
"shelf/home_button_unittest.cc",
"shelf/home_to_overview_nudge_controller_unittest.cc",
"shelf/hotseat_widget_unittest.cc",
"shelf/login_shelf_gesture_controller_unittest.cc",
"shelf/login_shelf_view_unittest.cc",
"shelf/scrollable_shelf_view_unittest.cc",
"shelf/shelf_application_menu_model_unittest.cc",
......
......@@ -417,6 +417,21 @@ void LoginScreenController::RequestSecurityTokenPin(
void LoginScreenController::ClearSecurityTokenPinRequest() {
security_token_request_controller_.ClosePinUi();
}
bool LoginScreenController::SetLoginShelfGestureHandler(
const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) {
return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
->shelf_widget()
->SetLoginShelfSwipeHandler(nudge_text, fling_callback,
std::move(exit_callback));
}
void LoginScreenController::ClearLoginShelfGestureHandler() {
return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
->shelf_widget()
->ClearLoginShelfSwipeHandler();
}
void LoginScreenController::ShowLockScreen() {
OnShow();
......
......@@ -131,6 +131,10 @@ class ASH_EXPORT LoginScreenController : public LoginScreen,
base::Time validation_time) override;
void RequestSecurityTokenPin(SecurityTokenPinRequest request) override;
void ClearSecurityTokenPinRequest() override;
bool SetLoginShelfGestureHandler(const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) override;
void ClearLoginShelfGestureHandler() override;
// KioskAppMenu:
void SetKioskApps(
......
......@@ -98,6 +98,30 @@ class ASH_PUBLIC_EXPORT LoginScreen {
// Called to close the UI previously opened with RequestSecurityTokenPin().
virtual void ClearSecurityTokenPinRequest() = 0;
// Sets a handler for login shelf gestures. This will enable gesture detection
// on the login shelf for upward fling from the shelf.
// |message| - The text to be shown above login shelf drag handle.
// |fling_callback| - The callback to be called when a fling is detected.
// |exit_callback| - The callback to be called when the login shelf gesture
// detection stops, for example when the session is unblocked, or the handler
// is cleared.
//
// Returns whether the handler was successfully set. If not, |exit_callback|
// will not be run. The handler will not be set if the current shelf state
// does not support login shelf gestures, e.g. if the session is active, or
// when not in tablet mode.
//
// Note that this does not support more than one handler - if another handler
// is already set, this method will replace it (and the previous handler's
// exit_callback will be run).
virtual bool SetLoginShelfGestureHandler(
const base::string16& message,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) = 0;
// Stops login shelf gesture detection.
virtual void ClearLoginShelfGestureHandler() = 0;
protected:
LoginScreen();
virtual ~LoginScreen();
......
......@@ -38,13 +38,15 @@ views::BubbleBorder::Arrow GetArrowForPosition(
ContextualNudge::ContextualNudge(views::View* anchor,
aura::Window* parent_window,
Position position,
const gfx::Insets& margins,
const base::string16& text,
Position position)
SkColor text_color)
: views::BubbleDialogDelegateView(anchor,
GetArrowForPosition(position),
views::BubbleBorder::NO_ASSETS) {
set_color(SK_ColorTRANSPARENT);
set_margins(gfx::Insets(0, 0));
set_margins(margins);
set_close_on_deactivate(false);
SetCanActivate(false);
set_accept_events(false);
......@@ -66,7 +68,7 @@ ContextualNudge::ContextualNudge(views::View* anchor,
label_->SetPaintToLayer();
label_->layer()->SetFillsBoundsOpaquely(false);
label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
label_->SetEnabledColor(SkColorSetA(gfx::kGoogleGrey200, 0xFF));
label_->SetEnabledColor(text_color);
label_->SetBackgroundColor(SK_ColorTRANSPARENT);
views::BubbleDialogDelegateView::CreateBubble(this);
......
......@@ -27,12 +27,16 @@ class ASH_EXPORT ContextualNudge : public views::BubbleDialogDelegateView {
// |parent_window| - if set, the window that should parent the nudge native
// window. If not set, the shelf container in the anchor view's root
// window will be used.
// |text| - The nudge text.
// |position| - The nudge position relative to the anchor rectangle.
// |margins| - The margins added to the nudge bubble.
// |text| - The nudge text.
// |text_color| - The nudge text label foreground color.
ContextualNudge(views::View* anchor,
aura::Window* parent_window,
Position position,
const gfx::Insets& margins,
const base::string16& text,
Position position);
SkColor text_color);
~ContextualNudge() override;
ContextualNudge(const ContextualNudge&) = delete;
......
......@@ -11,6 +11,7 @@
#include "ash/shelf/shelf_observer.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "base/bind.h"
#include "base/timer/timer.h"
#include "ui/base/l10n/l10n_util.h"
......@@ -67,13 +68,8 @@ class HideNudgeObserver : public ui::ImplicitAnimationObserver {
} // namespace
DragHandle::DragHandle(AshColorProvider::RippleAttributes ripple_attributes,
int drag_handle_corner_radius) {
DragHandle::DragHandle(int drag_handle_corner_radius) {
SetPaintToLayer(ui::LAYER_SOLID_COLOR);
layer()->SetColor(ripple_attributes.base_color);
// TODO(manucornet): Figure out why we need a manual opacity adjustment
// to make this color look the same as the status area highlight.
layer()->SetOpacity(ripple_attributes.inkdrop_opacity + 0.075);
layer()->SetRoundedCornerRadius(
{drag_handle_corner_radius, drag_handle_corner_radius,
drag_handle_corner_radius, drag_handle_corner_radius});
......@@ -109,6 +105,11 @@ void DragHandle::ShowDragHandleNudge(base::TimeDelta nudge_duration) {
}
}
void DragHandle::SetColorAndOpacity(SkColor color, float opacity) {
layer()->SetColor(color);
layer()->SetOpacity(opacity);
}
void DragHandle::HideDragHandleNudge() {
if (!showing_nudge_)
return;
......@@ -128,10 +129,12 @@ void DragHandle::OnGestureEvent(ui::GestureEvent* event) {
void DragHandle::ShowDragHandleTooltip() {
DCHECK(!drag_handle_nudge_);
drag_handle_nudge_ =
new ContextualNudge(this, nullptr /*parent_window*/,
l10n_util::GetStringUTF16(IDS_ASH_DRAG_HANDLE_NUDGE),
ContextualNudge::Position::kTop);
drag_handle_nudge_ = new ContextualNudge(
this, nullptr /*parent_window*/, ContextualNudge::Position::kTop,
gfx::Insets(), l10n_util::GetStringUTF16(IDS_ASH_DRAG_HANDLE_NUDGE),
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextPrimary,
AshColorProvider::AshColorMode::kDark));
drag_handle_nudge_->GetWidget()->Show();
drag_handle_nudge_->label()->layer()->SetOpacity(0.0f);
......
......@@ -8,7 +8,6 @@
#include "ash/ash_export.h"
#include "ash/shelf/contextual_nudge.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/style/ash_color_provider.h"
#include "base/timer/timer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/views/view.h"
......@@ -19,13 +18,14 @@ namespace ash {
class ASH_EXPORT DragHandle : public views::View,
public views::ViewTargeterDelegate {
public:
DragHandle(AshColorProvider::RippleAttributes ripple_attributes,
int drag_handle_corner_radius);
explicit DragHandle(int drag_handle_corner_radius);
DragHandle(const DragHandle&) = delete;
~DragHandle() override;
DragHandle& operator=(const DragHandle&) = delete;
void SetColorAndOpacity(SkColor color, float opacity);
// views::ViewTargeterDelegate:
bool DoesIntersectRect(const views::View* target,
const gfx::Rect& rect) const override;
......
......@@ -12,6 +12,7 @@
#include "ash/shelf/scrollable_shelf_view.h"
#include "ash/shelf/shelf.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/wm/mru_window_tracker.h"
#include "base/bind.h"
#include "base/location.h"
......@@ -161,9 +162,12 @@ void HomeToOverviewNudgeController::ShowNudge() {
// bounds directly - see UpdateNudgeAnchorBounds().
nudge_ = new ContextualNudge(
nullptr, hotseat_widget_->GetNativeWindow()->parent(),
ContextualNudge::Position::kBottom, gfx::Insets(kNudgeMargins),
l10n_util::GetStringUTF16(IDS_ASH_HOME_TO_OVERVIEW_CONTEXTUAL_NUDGE),
ContextualNudge::Position::kBottom);
nudge_->set_margins(gfx::Insets(kNudgeMargins));
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextPrimary,
AshColorProvider::AshColorMode::kDark));
UpdateNudgeAnchorBounds();
widget_observer_.Add(nudge_->GetWidget());
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/shelf/login_shelf_gesture_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/contextual_nudge.h"
#include "ash/shelf/drag_handle.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
// The upward velocity threshold for the swipe up from the login shelf to be
// reported as fling gesture.
constexpr float kVelocityToHomeScreenThreshold = 1000.f;
} // namespace
LoginShelfGestureController::LoginShelfGestureController(
Shelf* shelf,
DragHandle* drag_handle,
const base::string16& gesture_nudge,
const base::RepeatingClosure fling_handler,
base::OnceClosure exit_handler)
: shelf_(shelf),
fling_handler_(fling_handler),
exit_handler_(std::move(exit_handler)) {
DCHECK(fling_handler_);
DCHECK(exit_handler_);
const bool is_oobe = Shell::Get()->session_controller()->GetSessionState() ==
session_manager::SessionState::OOBE;
const SkColor nudge_text_color =
is_oobe ? gfx::kGoogleGrey700 : gfx::kGoogleGrey100;
nudge_ = new ContextualNudge(drag_handle, nullptr /*parent_window*/,
ContextualNudge::Position::kTop, gfx::Insets(4),
gesture_nudge, nudge_text_color);
nudge_->GetWidget()->Show();
nudge_->GetWidget()->AddObserver(this);
}
LoginShelfGestureController::~LoginShelfGestureController() {
if (nudge_) {
nudge_->GetWidget()->RemoveObserver(this);
nudge_->GetWidget()->CloseWithReason(
views::Widget::ClosedReason::kUnspecified);
}
nudge_ = nullptr;
std::move(exit_handler_).Run();
}
bool LoginShelfGestureController::HandleGestureEvent(
const ui::GestureEvent& event_in_screen) {
if (event_in_screen.type() == ui::ET_GESTURE_SCROLL_BEGIN)
return MaybeStartGestureDrag(event_in_screen);
// If the previous events in the gesture sequence did not start handling the
// gesture, try again.
if (event_in_screen.type() == ui::ET_GESTURE_SCROLL_UPDATE)
return active_ || MaybeStartGestureDrag(event_in_screen);
if (!active_)
return false;
if (event_in_screen.type() == ui::ET_SCROLL_FLING_START) {
EndDrag(event_in_screen);
return true;
}
// Ending non-fling gesture, or unexpected event (if different than
// SCROLL_END), mark the controller as inactive, but report the event as
// handled in the former case only.
active_ = false;
return event_in_screen.type() == ui::ET_GESTURE_SCROLL_END;
}
void LoginShelfGestureController::OnWidgetDestroying(views::Widget* widget) {
nudge_ = nullptr;
}
bool LoginShelfGestureController::MaybeStartGestureDrag(
const ui::GestureEvent& event_in_screen) {
DCHECK(event_in_screen.type() == ui::ET_GESTURE_SCROLL_BEGIN ||
event_in_screen.type() == ui::ET_GESTURE_SCROLL_UPDATE);
// Ignore downward swipe for scroll begin.
if (event_in_screen.type() == ui::ET_GESTURE_SCROLL_BEGIN &&
event_in_screen.details().scroll_y_hint() >= 0) {
return false;
}
// Ignore downward swipe for scroll update.
if (event_in_screen.type() == ui::ET_GESTURE_SCROLL_UPDATE &&
event_in_screen.details().scroll_y() >= 0) {
return false;
}
// Ignore swipes that are outside of the shelf bounds.
if (event_in_screen.location().y() <
shelf_->shelf_widget()->GetWindowBoundsInScreen().y()) {
return false;
}
active_ = true;
return true;
}
void LoginShelfGestureController::EndDrag(
const ui::GestureEvent& event_in_screen) {
DCHECK_EQ(event_in_screen.type(), ui::ET_SCROLL_FLING_START);
active_ = false;
// If the drag ends below the shelf, do not go to home screen (theoratically
// it may happen in kExtended hotseat case when drag can start and end below
// the shelf).
if (event_in_screen.location().y() >=
shelf_->shelf_widget()->GetWindowBoundsInScreen().y()) {
return;
}
const int velocity_y = event_in_screen.details().velocity_y();
if (velocity_y > -kVelocityToHomeScreenThreshold)
return;
fling_handler_.Run();
}
} // namespace ash
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SHELF_LOGIN_SHELF_GESTURE_CONTROLLER_H_
#define ASH_SHELF_LOGIN_SHELF_GESTURE_CONTROLLER_H_
#include "ash/ash_export.h"
#include "base/callback.h"
#include "base/strings/string16.h"
#include "ui/views/widget/widget_observer.h"
namespace ui {
class GestureEvent;
} // namespace ui
namespace ash {
class ContextualNudge;
class DragHandle;
class Shelf;
// Handles the swipe up gesture on login shelf. The gesture is enabled only when
// the login screen stack registers a handler for the swipe gesture.
// Currently, the handler may be set during user first run flow on the final
// screen of the flow (where swipe up will finalize user setup flow and start
// the user session).
class ASH_EXPORT LoginShelfGestureController : public views::WidgetObserver {
public:
LoginShelfGestureController(Shelf* shelf,
DragHandle* drag_handle,
const base::string16& gesture_nudge,
const base::RepeatingClosure fling_handler,
base::OnceClosure exit_handler);
LoginShelfGestureController(const LoginShelfGestureController& other) =
delete;
LoginShelfGestureController& operator=(
const LoginShelfGestureController& other) = delete;
~LoginShelfGestureController() override;
// Handles a gesture event on the login shelf.
// Returns whether the controller handled the event.
// The controller will handle SCROLL_BEGIN and SCROLL_UPDATE events if the
// scroll direction changes towards the top of the screen (and is within the
// shelf bounds).
// SCROLL_END and SCROLL_FLING_START will be only handled if a SCROLL_BEGIN or
// SCROLL_UPDATE was handled (i.e. if |active_| is true).
bool HandleGestureEvent(const ui::GestureEvent& event_in_screen);
// views::WidgetObserver:
void OnWidgetDestroying(views::Widget* widget) override;
ContextualNudge* nudge_for_testing() { return nudge_; }
private:
// Starts handling gesture drag if it's a start of upward swipe from the
// shelf.
bool MaybeStartGestureDrag(const ui::GestureEvent& event_in_screen);
// Ends gesture drag, and runs fling_handler_ if the gesture was detected to
// be upward fling from the shelf.
void EndDrag(const ui::GestureEvent& event_in_screen);
// Whether a gesture drag is being handled by the controller.
bool active_ = false;
Shelf* const shelf_;
// The contextual nudge bubble for letting the user know they can swipe up to
// perform an action.
// It's a bubble dialog widget delegate, deleted when its widget is destroyed,
// and the widget is owned by the window hierarchy.
ContextualNudge* nudge_ = nullptr;
// The callback to be run whenever swipe from shelf is detected.
base::RepeatingClosure const fling_handler_;
// Called when the swipe controller gets reset (at which point swipe from the
// login shelf gesture will be disabled).
base::OnceClosure exit_handler_;
};
} // namespace ash
#endif // ASH_SHELF_LOGIN_SHELF_GESTURE_CONTROLLER_H_
This diff is collapsed.
......@@ -30,6 +30,7 @@
#include "ash/tray_action/test_tray_action_client.h"
#include "ash/tray_action/tray_action.h"
#include "ash/wm/lock_state_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/run_loop.h"
......@@ -633,5 +634,26 @@ TEST_F(LoginShelfViewTest, ParentAccessButtonVisibilityChangeOnLockScreen) {
ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kSignOut}));
}
TEST_F(LoginShelfViewTest, TapShutdownWithSwipeDetectionEnabledOnLogin) {
NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
TabletModeControllerTestApi().EnterTabletMode();
Shell::Get()->login_screen_controller()->SetLoginShelfGestureHandler(
base::ASCIIToUTF16("Test swipe"), base::DoNothing(), base::DoNothing());
Click(LoginShelfView::kShutdown);
EXPECT_TRUE(Shell::Get()->lock_state_controller()->ShutdownRequested());
}
TEST_F(LoginShelfViewTest, TapShutdownWithSwipeDetectionEnabledInOobe) {
TabletModeControllerTestApi().EnterTabletMode();
Shell::Get()->login_screen_controller()->SetLoginShelfGestureHandler(
base::ASCIIToUTF16("Test swipe"), base::DoNothing(), base::DoNothing());
Click(LoginShelfView::kShutdown);
EXPECT_TRUE(Shell::Get()->lock_state_controller()->ShutdownRequested());
}
} // namespace
} // namespace ash
......@@ -24,6 +24,7 @@
#include "ash/shelf/home_button.h"
#include "ash/shelf/hotseat_transition_animator.h"
#include "ash/shelf/hotseat_widget.h"
#include "ash/shelf/login_shelf_gesture_controller.h"
#include "ash/shelf/login_shelf_view.h"
#include "ash/shelf/overflow_bubble.h"
#include "ash/shelf/overflow_bubble_view.h"
......@@ -147,7 +148,7 @@ class ShelfWidget::DelegateView : public views::WidgetDelegate,
void UpdateBackgroundBlur();
void UpdateOpaqueBackground();
void UpdateDragHandle();
void UpdateDragHandle(bool update_color);
// This will be called when the parent local bounds change.
void OnBoundsChanged(const gfx::Rect& old_bounds) override;
......@@ -234,8 +235,8 @@ ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf_widget)
AshColorProvider::Get()->GetRippleAttributes(
ShelfConfig::Get()->GetDefaultShelfColor());
drag_handle_ = AddChildView(
std::make_unique<DragHandle>(ripple_attributes, kDragHandleCornerRadius));
drag_handle_ =
AddChildView(std::make_unique<DragHandle>(kDragHandleCornerRadius));
animating_drag_handle_.SetColor(ripple_attributes.base_color);
animating_drag_handle_.SetOpacity(ripple_attributes.inkdrop_opacity + 0.075);
......@@ -285,7 +286,7 @@ void ShelfWidget::DelegateView::HideOpaqueBackground() {
void ShelfWidget::DelegateView::ShowOpaqueBackground() {
hide_background_for_transitions_ = false;
UpdateOpaqueBackground();
UpdateDragHandle();
UpdateDragHandle(false /*update_color*/);
UpdateBackgroundBlur();
}
......@@ -375,12 +376,36 @@ void ShelfWidget::DelegateView::UpdateOpaqueBackground() {
});
}
opaque_background()->SetBounds(opaque_background_bounds);
UpdateDragHandle();
UpdateDragHandle(false /*update_color*/);
UpdateBackgroundBlur();
SchedulePaint();
}
void ShelfWidget::DelegateView::UpdateDragHandle() {
void ShelfWidget::DelegateView::UpdateDragHandle(bool update_color) {
if (update_color) {
if (Shell::Get()->session_controller()->IsUserSessionBlocked()) {
// For login shelf, let the drag handle match control buttons background.
drag_handle_->SetColorAndOpacity(
ShelfConfig::Get()->GetShelfControlButtonColor(), 1.0f);
} else {
const AshColorProvider::RippleAttributes ripple_attributes =
AshColorProvider::Get()->GetRippleAttributes(
ShelfConfig::Get()->GetDefaultShelfColor());
// TODO(manucornet): Figure out why we need a manual opacity adjustment
// to make this color look the same as the status area highlight.
drag_handle_->SetColorAndOpacity(
ripple_attributes.base_color,
ripple_attributes.inkdrop_opacity + 0.075);
}
}
if (shelf_widget_->login_shelf_view_->GetVisible()) {
drag_handle_->SetVisible(
shelf_widget_->login_shelf_gesture_controller_.get());
return;
}
if (!Shell::Get()->IsInTabletMode() || !ShelfConfig::Get()->is_in_app() ||
!chromeos::switches::ShouldShowShelfHotseat() ||
hide_background_for_transitions_) {
......@@ -424,8 +449,15 @@ views::View* ShelfWidget::DelegateView::GetDefaultFocusableChild() {
void ShelfWidget::DelegateView::Layout() {
login_shelf_view_->SetBoundsRect(GetLocalBounds());
// Center drag handle within the expected in-app shelf bounds - it's safe to
// assume bottom shelf, given that the drag handle is only shown within the
// bottom shelf (either in tablet mode, or on login/lock screen)
gfx::Rect drag_handle_bounds = GetLocalBounds();
drag_handle_bounds.Inset(
0, drag_handle_bounds.height() - ShelfConfig::Get()->in_app_shelf_size(),
0, 0);
drag_handle_bounds.ClampToCenteredSize(ShelfConfig::Get()->DragHandleSize());
drag_handle_->SetBoundsRect(drag_handle_bounds);
}
......@@ -480,7 +512,17 @@ bool ShelfWidget::GetHitTestRects(aura::Window* target,
aura::Window::ConvertRectToTarget(source, target->parent(),
&login_view_button_bounds);
*hit_test_rect_mouse = login_view_button_bounds;
*hit_test_rect_touch = login_view_button_bounds;
// If login shelf gesture detection is active, consume touch events on the
// whole shelf, so |login_shelf_gesture_controller_| can receive them.
if (login_shelf_gesture_controller_) {
gfx::Rect shelf_view_bounds = login_shelf_view_->GetLocalBounds();
aura::Window::ConvertRectToTarget(source, target->parent(),
&shelf_view_bounds);
*hit_test_rect_touch = shelf_view_bounds;
} else {
*hit_test_rect_touch = login_view_button_bounds;
}
return true;
}
......@@ -492,6 +534,29 @@ void ShelfWidget::ForceToShowHotseat() {
shelf_layout_manager_->UpdateVisibilityState();
}
bool ShelfWidget::SetLoginShelfSwipeHandler(
const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) {
if (!login_shelf_view_->GetVisible())
return false;
if (!Shell::Get()->IsInTabletMode())
return false;
login_shelf_gesture_controller_ =
std::make_unique<LoginShelfGestureController>(
shelf_, delegate_view_->drag_handle(), nudge_text, fling_callback,
std::move(exit_callback));
delegate_view_->UpdateDragHandle(false /*update_color*/);
return true;
}
void ShelfWidget::ClearLoginShelfSwipeHandler() {
login_shelf_gesture_controller_.reset();
delegate_view_->UpdateDragHandle(false /*update_color*/);
}
ui::Layer* ShelfWidget::GetOpaqueBackground() {
return delegate_view_->opaque_background();
}
......@@ -629,9 +694,14 @@ void ShelfWidget::RegisterHotseatWidget(HotseatWidget* hotseat_widget) {
}
void ShelfWidget::OnTabletModeChanged() {
// Resets |is_hotseat_forced_to_show| when leaving the tablet mode.
if (!Shell::Get()->IsInTabletMode())
if (!Shell::Get()->IsInTabletMode()) {
// Resets |is_hotseat_forced_to_show| when leaving the tablet mode.
is_hotseat_forced_to_show_ = false;
// Disable login shelf gesture controller, if one is set when leacing tablet
// mode.
login_shelf_gesture_controller_.reset();
}
}
void ShelfWidget::PostCreateShelf() {
......@@ -877,10 +947,15 @@ void ShelfWidget::OnSessionStateChanged(session_manager::SessionState state) {
hotseat_transition_animator_->SetAnimationsEnabledInSessionState(
show_hotseat);
login_shelf_view()->SetVisible(!show_hotseat);
delegate_view_->UpdateDragHandle();
if (show_hotseat)
login_shelf_gesture_controller_.reset();
ShowIfHidden();
}
shelf_layout_manager_->SetDimmed(false);
// Depending on session state change, the drag handle visibiliy and color
// might have to be changed.
delegate_view_->UpdateDragHandle(true /*update_color*/);
login_shelf_view_->UpdateAfterSessionChange();
}
......@@ -903,6 +978,14 @@ void ShelfWidget::ShowIfHidden() {
Show();
}
bool ShelfWidget::HandleLoginShelfGestureEvent(
const ui::GestureEvent& event_in_screen) {
if (!login_shelf_gesture_controller_)
return false;
return login_shelf_gesture_controller_->HandleGestureEvent(event_in_screen);
}
void ShelfWidget::OnMouseEvent(ui::MouseEvent* event) {
if (event->IsMouseWheelEvent()) {
ui::MouseWheelEvent* mouse_wheel_event = event->AsMouseWheelEvent();
......@@ -930,6 +1013,12 @@ void ShelfWidget::OnGestureEvent(ui::GestureEvent* event) {
gfx::Point location_in_screen(event->location());
::wm::ConvertPointToScreen(GetNativeWindow(), &location_in_screen);
event_in_screen.set_location(location_in_screen);
if (HandleLoginShelfGestureEvent(event_in_screen)) {
event->StopPropagation();
return;
}
shelf_layout_manager()->ProcessGestureEventFromShelfWidget(&event_in_screen);
if (!event->handled())
views::Widget::OnGestureEvent(event);
......
......@@ -27,6 +27,7 @@ class ApplicationDragAndDropHost;
class FocusCycler;
class HotseatWidget;
class LoginShelfView;
class LoginShelfGestureController;
class Shelf;
class ShelfLayoutManager;
class ShelfNavigationWidget;
......@@ -143,6 +144,15 @@ class ASH_EXPORT ShelfWidget : public AccessibilityObserver,
void ForceToShowHotseat();
void ForceToHideHotseat();
// Creates a login shelf gesture controller (which enabled login shelf gesture
// detection). See ash/public/cpp/login_screen.h for more info.
bool SetLoginShelfSwipeHandler(const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback);
// Resets a previously create login shelf gesture controller, if any.
void ClearLoginShelfSwipeHandler();
bool is_hotseat_forced_to_show() const { return is_hotseat_forced_to_show_; }
// Gets the layer used to draw the shelf background.
......@@ -177,6 +187,10 @@ class ASH_EXPORT ShelfWidget : public AccessibilityObserver,
return &background_animator_;
}
LoginShelfGestureController* login_shelf_gesture_controller_for_testing() {
return login_shelf_gesture_controller_.get();
}
HotseatTransitionAnimator* hotseat_transition_animator() {
return hotseat_transition_animator_.get();
}
......@@ -194,6 +208,11 @@ class ASH_EXPORT ShelfWidget : public AccessibilityObserver,
// Shows shelf widget if IsVisible() returns false.
void ShowIfHidden();
// Handles shelf widget gesture events for login shelf, if login shelf view is
// visible. Returns whether the gesture was handled (the gesture will not be
// handled if the login shelf view is hidden).
bool HandleLoginShelfGestureEvent(const ui::GestureEvent& event_in_screen);
ShelfView* GetShelfView();
const ShelfView* GetShelfView() const;
......@@ -219,6 +238,10 @@ class ASH_EXPORT ShelfWidget : public AccessibilityObserver,
// Owned by the views hierarchy.
LoginShelfView* login_shelf_view_;
// Used to handle gestures on login shelf - created only if
// SetLoginShelfSwipeHandler() gets called.
std::unique_ptr<LoginShelfGestureController> login_shelf_gesture_controller_;
ScopedSessionObserver scoped_session_observer_;
bool is_hotseat_forced_to_show_ = false;
......
......@@ -64,3 +64,12 @@ void TestLoginScreen::RequestSecurityTokenPin(
ash::SecurityTokenPinRequest request) {}
void TestLoginScreen::ClearSecurityTokenPinRequest() {}
bool TestLoginScreen::SetLoginShelfGestureHandler(
const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) {
return false;
}
void TestLoginScreen::ClearLoginShelfGestureHandler() {}
......@@ -44,6 +44,10 @@ class TestLoginScreen : public ash::LoginScreen {
override;
void RequestSecurityTokenPin(ash::SecurityTokenPinRequest request) override;
void ClearSecurityTokenPinRequest() override;
bool SetLoginShelfGestureHandler(const base::string16& nudge_text,
const base::RepeatingClosure& fling_callback,
base::OnceClosure exit_callback) override;
void ClearLoginShelfGestureHandler() override;
private:
TestLoginScreenModel test_screen_model_;
......
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