Commit 43b3f48d authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

TabletModeController refactoring II.

Refactoring of the internal input events blocker in
TabletModeController.

The input events should only be blocked if 1) we're currently in tablet
mode or 2) we're currently in laptop mode but the lid is flipped over,
i.e., we are in laptop mode because of an attached external mouse.

Bug: 887042
Change-Id: I8be03c684265d79ccc3499362a7154eb44c4dec0
Reviewed-on: https://chromium-review.googlesource.com/1237407
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593671}
parent 9c953d1c
...@@ -2330,6 +2330,7 @@ static_library("test_support_common") { ...@@ -2330,6 +2330,7 @@ static_library("test_support_common") {
"//services/ws/public/cpp", "//services/ws/public/cpp",
"//services/ws/public/cpp/host", "//services/ws/public/cpp/host",
"//services/ws/public/cpp/input_devices", "//services/ws/public/cpp/input_devices",
"//services/ws/public/cpp/input_devices:test_support",
"//services/ws/public/mojom", "//services/ws/public/mojom",
"//skia", "//skia",
"//testing/gtest", "//testing/gtest",
......
...@@ -357,7 +357,7 @@ TEST_F(VirtualKeyboardControllerAutoTest, EnabledDuringTabletMode) { ...@@ -357,7 +357,7 @@ TEST_F(VirtualKeyboardControllerAutoTest, EnabledDuringTabletMode) {
TabletModeControllerTestApi().EnterTabletMode(); TabletModeControllerTestApi().EnterTabletMode();
ASSERT_TRUE(keyboard::IsKeyboardEnabled()); ASSERT_TRUE(keyboard::IsKeyboardEnabled());
// Toggle tablet mode off. // Toggle tablet mode off.
TabletModeControllerTestApi().LeaveTabletMode(false); TabletModeControllerTestApi().LeaveTabletMode();
ASSERT_FALSE(keyboard::IsKeyboardEnabled()); ASSERT_FALSE(keyboard::IsKeyboardEnabled());
} }
...@@ -400,7 +400,7 @@ TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInTabletMode) { ...@@ -400,7 +400,7 @@ TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInTabletMode) {
ASSERT_TRUE(notified()); ASSERT_TRUE(notified());
ASSERT_FALSE(IsVirtualKeyboardSuppressed()); ASSERT_FALSE(IsVirtualKeyboardSuppressed());
// Toggle tablet mode oFF. // Toggle tablet mode oFF.
TabletModeControllerTestApi().LeaveTabletMode(false); TabletModeControllerTestApi().LeaveTabletMode();
ASSERT_FALSE(keyboard::IsKeyboardEnabled()); ASSERT_FALSE(keyboard::IsKeyboardEnabled());
} }
......
...@@ -112,7 +112,7 @@ TEST_F(OverviewButtonTrayTest, TabletModeObserverOnTabletModeToggled) { ...@@ -112,7 +112,7 @@ TEST_F(OverviewButtonTrayTest, TabletModeObserverOnTabletModeToggled) {
TabletModeControllerTestApi().EnterTabletMode(); TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(GetTray()->visible()); EXPECT_TRUE(GetTray()->visible());
TabletModeControllerTestApi().LeaveTabletMode(false); TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(GetTray()->visible()); EXPECT_FALSE(GetTray()->visible());
} }
...@@ -302,7 +302,7 @@ TEST_F(OverviewButtonTrayTest, VisibilityChangesForSystemModalWindow) { ...@@ -302,7 +302,7 @@ TEST_F(OverviewButtonTrayTest, VisibilityChangesForSystemModalWindow) {
ASSERT_TRUE(Shell::IsSystemModalWindowOpen()); ASSERT_TRUE(Shell::IsSystemModalWindowOpen());
TabletModeControllerTestApi().EnterTabletMode(); TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(GetTray()->visible()); EXPECT_TRUE(GetTray()->visible());
TabletModeControllerTestApi().LeaveTabletMode(false); TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(GetTray()->visible()); EXPECT_FALSE(GetTray()->visible());
} }
...@@ -364,10 +364,12 @@ TEST_F(OverviewButtonTrayTest, SplitviewModeQuickSwitch) { ...@@ -364,10 +364,12 @@ TEST_F(OverviewButtonTrayTest, SplitviewModeQuickSwitch) {
// Tests that the tray remains visible when leaving tablet mode due to external // Tests that the tray remains visible when leaving tablet mode due to external
// mouse being connected. // mouse being connected.
TEST_F(OverviewButtonTrayTest, LeaveTabletModeBecauseExternalMouse) { TEST_F(OverviewButtonTrayTest, LeaveTabletModeBecauseExternalMouse) {
TabletModeControllerTestApi().EnterTabletMode(); TabletModeControllerTestApi().OpenLidToAngle(315.0f);
EXPECT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
ASSERT_TRUE(GetTray()->visible()); ASSERT_TRUE(GetTray()->visible());
TabletModeControllerTestApi().LeaveTabletMode(true); TabletModeControllerTestApi().AttachExternalMouse();
EXPECT_FALSE(TabletModeControllerTestApi().IsTabletModeStarted());
EXPECT_TRUE(GetTray()->visible()); EXPECT_TRUE(GetTray()->visible());
} }
......
...@@ -201,6 +201,8 @@ void TabletModeController::EnableTabletModeWindowManager(bool should_enable) { ...@@ -201,6 +201,8 @@ void TabletModeController::EnableTabletModeWindowManager(bool should_enable) {
if (client_) // Null at startup and in tests. if (client_) // Null at startup and in tests.
client_->OnTabletModeToggled(false); client_->OnTabletModeToggled(false);
} }
UpdateInternalMouseAndKeyboardEventBlocker();
} }
bool TabletModeController::IsTabletModeWindowManagerEnabled() const { bool TabletModeController::IsTabletModeWindowManagerEnabled() const {
...@@ -262,7 +264,7 @@ void TabletModeController::OnDisplayConfigurationChanged() { ...@@ -262,7 +264,7 @@ void TabletModeController::OnDisplayConfigurationChanged() {
if (!display::Display::HasInternalDisplay() || if (!display::Display::HasInternalDisplay() ||
!Shell::Get()->display_manager()->IsActiveDisplayId( !Shell::Get()->display_manager()->IsActiveDisplayId(
display::Display::InternalDisplayId())) { display::Display::InternalDisplayId())) {
AttemptLeaveTabletMode(false); AttemptLeaveTabletMode();
} else if (tablet_mode_switch_is_on_ && !IsTabletModeWindowManagerEnabled()) { } else if (tablet_mode_switch_is_on_ && !IsTabletModeWindowManagerEnabled()) {
// The internal display has returned, as we are exiting docked mode. // The internal display has returned, as we are exiting docked mode.
// The device is still in tablet mode, so trigger tablet mode, as this // The device is still in tablet mode, so trigger tablet mode, as this
...@@ -342,7 +344,7 @@ void TabletModeController::LidEventReceived( ...@@ -342,7 +344,7 @@ void TabletModeController::LidEventReceived(
lid_is_closed_ = !open; lid_is_closed_ = !open;
if (!tablet_mode_switch_is_on_) if (!tablet_mode_switch_is_on_)
AttemptLeaveTabletMode(false); AttemptLeaveTabletMode();
} }
void TabletModeController::TabletModeEventReceived( void TabletModeController::TabletModeEventReceived(
...@@ -366,7 +368,7 @@ void TabletModeController::TabletModeEventReceived( ...@@ -366,7 +368,7 @@ void TabletModeController::TabletModeEventReceived(
AttemptEnterTabletMode(); AttemptEnterTabletMode();
} else if (!on && IsTabletModeWindowManagerEnabled() && } else if (!on && IsTabletModeWindowManagerEnabled() &&
!can_detect_lid_angle_) { !can_detect_lid_angle_) {
AttemptLeaveTabletMode(false); AttemptLeaveTabletMode();
} }
} }
...@@ -451,7 +453,7 @@ void TabletModeController::HandleHingeRotation( ...@@ -451,7 +453,7 @@ void TabletModeController::HandleHingeRotation(
// Toggle tablet mode on or off when corresponding thresholds are passed. // Toggle tablet mode on or off when corresponding thresholds are passed.
if (is_angle_stable && lid_angle_ <= kExitTabletModeAngle) { if (is_angle_stable && lid_angle_ <= kExitTabletModeAngle) {
AttemptLeaveTabletMode(false); AttemptLeaveTabletMode();
} else if (!lid_is_closed_ && lid_angle_ >= kEnterTabletModeAngle && } else if (!lid_is_closed_ && lid_angle_ >= kEnterTabletModeAngle &&
(is_angle_stable || CanUseUnstableLidAngle())) { (is_angle_stable || CanUseUnstableLidAngle())) {
AttemptEnterTabletMode(); AttemptEnterTabletMode();
...@@ -491,37 +493,19 @@ bool TabletModeController::CanEnterTabletMode() { ...@@ -491,37 +493,19 @@ bool TabletModeController::CanEnterTabletMode() {
} }
void TabletModeController::AttemptEnterTabletMode() { void TabletModeController::AttemptEnterTabletMode() {
event_blocker_.reset(); if (IsTabletModeWindowManagerEnabled() || has_external_mouse_) {
event_blocker_ = CreateScopedDisableInternalMouseAndKeyboard(); UpdateInternalMouseAndKeyboardEventBlocker();
for (auto& observer : tablet_mode_observers_)
observer.OnTabletModeEventsBlockingChanged();
if (IsTabletModeWindowManagerEnabled())
return;
should_enter_tablet_mode_ = true;
if (has_external_mouse_)
return; return;
}
EnableTabletModeWindowManager(true); EnableTabletModeWindowManager(true);
} }
void TabletModeController::AttemptLeaveTabletMode( void TabletModeController::AttemptLeaveTabletMode() {
bool called_by_device_update) { if (!IsTabletModeWindowManagerEnabled()) {
// Do not unlock internal keyboard if we enter clamshell by plugging in an UpdateInternalMouseAndKeyboardEventBlocker();
// external mouse.
if (!called_by_device_update) {
event_blocker_.reset();
for (auto& observer : tablet_mode_observers_)
observer.OnTabletModeEventsBlockingChanged();
}
if (!IsTabletModeWindowManagerEnabled())
return; return;
}
if (!called_by_device_update)
should_enter_tablet_mode_ = false;
EnableTabletModeWindowManager(false); EnableTabletModeWindowManager(false);
} }
...@@ -589,17 +573,46 @@ void TabletModeController::HandleMouseAddedOrRemoved() { ...@@ -589,17 +573,46 @@ void TabletModeController::HandleMouseAddedOrRemoved() {
has_external_mouse_ = has_external_mouse; has_external_mouse_ = has_external_mouse;
// Try to tablet mode if we are already in tablet mode and // Leave tablet mode whenever an external mouse is attached.
// |has_external_mouse| is true.
if (has_external_mouse) { if (has_external_mouse) {
AttemptLeaveTabletMode(true); AttemptLeaveTabletMode();
return; } else if (!can_detect_lid_angle_ || LidAngleIsInTabletModeRange()) {
// If there is no external mouse, only enter tablet mode if 1) the lid angle
// can't be detected, which means the device is a tablet device. (it can't
// be a normal laptop device, since in this case we don't obseve the input
// device events and thus won't call into this function) or 2) the lid angle
// can be detected and is in tablet mode angle range.
AttemptEnterTabletMode();
} }
}
// Try to enter tablet mode if |has_external_mouse| is false and we void TabletModeController::UpdateInternalMouseAndKeyboardEventBlocker() {
// are in an orientation that should be tablet mode. bool should_block_internal_events = false;
if (should_enter_tablet_mode_) if (IsTabletModeWindowManagerEnabled()) {
AttemptEnterTabletMode(); // If we are currently in tablet mode, the internal input events should
// always be blocked.
should_block_internal_events = true;
} else if (LidAngleIsInTabletModeRange()) {
// If we are currently in clamshell mode, the intenral input events should
// only be blocked if the current lid angle belongs to tablet mode angle.
should_block_internal_events = true;
}
if (should_block_internal_events == AreInternalInputDeviceEventsBlocked())
return;
if (should_block_internal_events)
event_blocker_ = CreateScopedDisableInternalMouseAndKeyboard();
else
event_blocker_.reset();
for (auto& observer : tablet_mode_observers_)
observer.OnTabletModeEventsBlockingChanged();
}
bool TabletModeController::LidAngleIsInTabletModeRange() {
return can_detect_lid_angle_ && !lid_is_closed_ &&
lid_angle_ >= kEnterTabletModeAngle;
} }
} // namespace ash } // namespace ash
...@@ -166,12 +166,12 @@ class ASH_EXPORT TabletModeController ...@@ -166,12 +166,12 @@ class ASH_EXPORT TabletModeController
// tablet mode becomes enabled. // tablet mode becomes enabled.
bool CanEnterTabletMode(); bool CanEnterTabletMode();
// Attempts to enter tablet mode and locks the internal keyboard and touchpad. // Attempts to enter tablet mode and update the internal keyboard and
// touchpad.
void AttemptEnterTabletMode(); void AttemptEnterTabletMode();
// Attempts to exit tablet mode and unlocks the internal keyboard and touchpad // Attempts to exit tablet mode and update the internal keyboard and touchpad.
// if |called_by_device_update| is false. void AttemptLeaveTabletMode();
void AttemptLeaveTabletMode(bool called_by_device_update);
// Record UMA stats tracking TabletMode usage. If |type| is // Record UMA stats tracking TabletMode usage. If |type| is
// TABLET_MODE_INTERVAL_INACTIVE, then record that TabletMode has been // TABLET_MODE_INTERVAL_INACTIVE, then record that TabletMode has been
...@@ -200,6 +200,17 @@ class ASH_EXPORT TabletModeController ...@@ -200,6 +200,17 @@ class ASH_EXPORT TabletModeController
// sent from device manager. This will exit tablet mode if needed. // sent from device manager. This will exit tablet mode if needed.
void HandleMouseAddedOrRemoved(); void HandleMouseAddedOrRemoved();
// Update the internal mouse and keyboard event blocker |event_blocker_|
// according to current configuration. The internal input events should be
// blocked if 1) we are currently in tablet mode or 2) we are currently in
// laptop mode but the lid is flipped over (i.e., we are in laptop mode
// because of an external attached mouse).
void UpdateInternalMouseAndKeyboardEventBlocker();
// Returns true if the current lid angle can be detected and is in tablet mode
// angle range.
bool LidAngleIsInTabletModeRange();
// The maximized window manager (if enabled). // The maximized window manager (if enabled).
std::unique_ptr<TabletModeWindowManager> tablet_mode_window_manager_; std::unique_ptr<TabletModeWindowManager> tablet_mode_window_manager_;
...@@ -210,7 +221,11 @@ class ASH_EXPORT TabletModeController ...@@ -210,7 +221,11 @@ class ASH_EXPORT TabletModeController
// Whether we have ever seen accelerometer data. // Whether we have ever seen accelerometer data.
bool have_seen_accelerometer_data_ = false; bool have_seen_accelerometer_data_ = false;
// Whether both accelerometers are available. // Whether the lid angle can be detected. If it's true, the device is a
// convertible device (both screen acclerometer and keyboard acclerometer are
// available, thus lid angle is detectable). And if it's false, the device is
// either a laptop device or a tablet device (only the screen acclerometer is
// available).
bool can_detect_lid_angle_ = false; bool can_detect_lid_angle_ = false;
// Tracks time spent in (and out of) tablet mode. // Tracks time spent in (and out of) tablet mode.
...@@ -242,11 +257,6 @@ class ASH_EXPORT TabletModeController ...@@ -242,11 +257,6 @@ class ASH_EXPORT TabletModeController
// not enter tablet mode if this is true. // not enter tablet mode if this is true.
bool has_external_mouse_ = false; bool has_external_mouse_ = false;
// Tracks if the device would enter tablet mode, but does not because of a
// attached external mouse. If the external mouse is detached and this is
// true, we will enter tablet mode.
bool should_enter_tablet_mode_ = false;
// Tracks smoothed accelerometer data over time. This is done when the hinge // Tracks smoothed accelerometer data over time. This is done when the hinge
// is approaching vertical to remove abrupt acceleration that can lead to // is approaching vertical to remove abrupt acceleration that can lead to
// incorrect calculations of hinge angles. // incorrect calculations of hinge angles.
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/run_loop.h"
#include "base/time/default_tick_clock.h"
#include "services/ws/public/cpp/input_devices/input_device_client_test_api.h"
#include "ui/events/devices/input_device.h"
namespace ash { namespace ash {
...@@ -17,9 +21,67 @@ void TabletModeControllerTestApi::EnterTabletMode() { ...@@ -17,9 +21,67 @@ void TabletModeControllerTestApi::EnterTabletMode() {
tablet_mode_controller_->AttemptEnterTabletMode(); tablet_mode_controller_->AttemptEnterTabletMode();
} }
void TabletModeControllerTestApi::LeaveTabletMode( void TabletModeControllerTestApi::LeaveTabletMode() {
bool called_by_device_update) { tablet_mode_controller_->AttemptLeaveTabletMode();
tablet_mode_controller_->AttemptLeaveTabletMode(called_by_device_update);
} }
} // namespace ash void TabletModeControllerTestApi::AttachExternalMouse() {
\ No newline at end of file ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
base::RunLoop().RunUntilIdle();
tablet_mode_controller_->OnMouseDeviceConfigurationChanged();
}
void TabletModeControllerTestApi::TriggerLidUpdate(const gfx::Vector3dF& lid) {
scoped_refptr<chromeos::AccelerometerUpdate> update(
new chromeos::AccelerometerUpdate());
update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
tablet_mode_controller_->OnAccelerometerUpdated(update);
}
void TabletModeControllerTestApi::TriggerBaseAndLidUpdate(
const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) {
scoped_refptr<chromeos::AccelerometerUpdate> update(
new chromeos::AccelerometerUpdate());
update->Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, base.x(),
base.y(), base.z());
update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
tablet_mode_controller_->OnAccelerometerUpdated(update);
}
void TabletModeControllerTestApi::OpenLidToAngle(float degrees) {
DCHECK(degrees >= 0.0f);
DCHECK(degrees <= 360.0f);
float radians = degrees * kDegreesToRadians;
gfx::Vector3dF base_vector(0.0f, -kMeanGravity, 0.0f);
gfx::Vector3dF lid_vector(0.0f, kMeanGravity * cos(radians),
kMeanGravity * sin(radians));
TriggerBaseAndLidUpdate(base_vector, lid_vector);
}
void TabletModeControllerTestApi::HoldDeviceVertical() {
gfx::Vector3dF base_vector(9.8f, 0.0f, 0.0f);
gfx::Vector3dF lid_vector(9.8f, 0.0f, 0.0f);
TriggerBaseAndLidUpdate(base_vector, lid_vector);
}
void TabletModeControllerTestApi::OpenLid() {
tablet_mode_controller_->LidEventReceived(
chromeos::PowerManagerClient::LidState::OPEN, tick_clock()->NowTicks());
}
void TabletModeControllerTestApi::CloseLid() {
tablet_mode_controller_->LidEventReceived(
chromeos::PowerManagerClient::LidState::CLOSED, tick_clock()->NowTicks());
}
void TabletModeControllerTestApi::SetTabletMode(bool on) {
tablet_mode_controller_->TabletModeEventReceived(
on ? chromeos::PowerManagerClient::TabletMode::ON
: chromeos::PowerManagerClient::TabletMode::OFF,
tick_clock()->NowTicks());
}
} // namespace ash
...@@ -20,13 +20,29 @@ class TabletModeWindowManager; ...@@ -20,13 +20,29 @@ class TabletModeWindowManager;
// Use the api in this class to test TabletModeController. // Use the api in this class to test TabletModeController.
class TabletModeControllerTestApi { class TabletModeControllerTestApi {
public: public:
static constexpr float kDegreesToRadians = 3.1415926f / 180.0f;
static constexpr float kMeanGravity = 9.8066f;
TabletModeControllerTestApi(); TabletModeControllerTestApi();
~TabletModeControllerTestApi(); ~TabletModeControllerTestApi();
// Enters or exits tablet mode. Use these instead when stuff such as tray // Enters or exits tablet mode.
// visibilty depends on the event blocker instead of the actual tablet mode.
void EnterTabletMode(); void EnterTabletMode();
void LeaveTabletMode(bool called_by_device_update); void LeaveTabletMode();
// Called to attach an external mouse. If we're currently in tablet mode,
// tablet mode will be ended because of this.
void AttachExternalMouse();
void TriggerLidUpdate(const gfx::Vector3dF& lid);
void TriggerBaseAndLidUpdate(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid);
void OpenLidToAngle(float degrees);
void HoldDeviceVertical();
void OpenLid();
void CloseLid();
void SetTabletMode(bool on);
// Sets the event blocker on the tablet mode controller. // Sets the event blocker on the tablet mode controller.
void set_event_blocker( void set_event_blocker(
...@@ -58,6 +74,14 @@ class TabletModeControllerTestApi { ...@@ -58,6 +74,14 @@ class TabletModeControllerTestApi {
return tablet_mode_controller_->force_ui_mode_; return tablet_mode_controller_->force_ui_mode_;
} }
bool IsTabletModeStarted() const {
return tablet_mode_controller_->IsTabletModeWindowManagerEnabled();
}
bool AreEventsBlocked() const {
return tablet_mode_controller_->AreInternalInputDeviceEventsBlocked();
}
private: private:
TabletModeController* tablet_mode_controller_; TabletModeController* tablet_mode_controller_;
...@@ -66,4 +90,4 @@ class TabletModeControllerTestApi { ...@@ -66,4 +90,4 @@ class TabletModeControllerTestApi {
} // namespace ash } // namespace ash
#endif // ASH_WM_TABLET_MODE_TABLET_MODE_CONTROLLER_TEST_API_H_ #endif // ASH_WM_TABLET_MODE_TABLET_MODE_CONTROLLER_TEST_API_H_
\ No newline at end of file
...@@ -38,8 +38,7 @@ namespace ash { ...@@ -38,8 +38,7 @@ namespace ash {
namespace { namespace {
constexpr float kDegreesToRadians = 3.1415926f / 180.0f; constexpr float kMeanGravity = TabletModeControllerTestApi::kMeanGravity;
constexpr float kMeanGravity = 9.8066f;
// The strings are "Touchview" as they're already used in metrics. // The strings are "Touchview" as they're already used in metrics.
constexpr char kTabletModeInitiallyDisabled[] = "Touchview_Initially_Disabled"; constexpr char kTabletModeInitiallyDisabled[] = "Touchview_Initially_Disabled";
...@@ -102,27 +101,15 @@ class TabletModeControllerTest : public AshTestBase { ...@@ -102,27 +101,15 @@ class TabletModeControllerTest : public AshTestBase {
} }
void TriggerLidUpdate(const gfx::Vector3dF& lid) { void TriggerLidUpdate(const gfx::Vector3dF& lid) {
scoped_refptr<chromeos::AccelerometerUpdate> update( test_api_->TriggerLidUpdate(lid);
new chromeos::AccelerometerUpdate());
update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(),
lid.z());
tablet_mode_controller()->OnAccelerometerUpdated(update);
} }
void TriggerBaseAndLidUpdate(const gfx::Vector3dF& base, void TriggerBaseAndLidUpdate(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) { const gfx::Vector3dF& lid) {
scoped_refptr<chromeos::AccelerometerUpdate> update( test_api_->TriggerBaseAndLidUpdate(base, lid);
new chromeos::AccelerometerUpdate());
update->Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, base.x(),
base.y(), base.z());
update->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(),
lid.z());
tablet_mode_controller()->OnAccelerometerUpdated(update);
} }
bool IsTabletModeStarted() { bool IsTabletModeStarted() const { return test_api_->IsTabletModeStarted(); }
return tablet_mode_controller()->IsTabletModeWindowManagerEnabled();
}
// Attaches a SimpleTestTickClock to the TabletModeController with a non // Attaches a SimpleTestTickClock to the TabletModeController with a non
// null value initial value. // null value initial value.
...@@ -135,47 +122,15 @@ class TabletModeControllerTest : public AshTestBase { ...@@ -135,47 +122,15 @@ class TabletModeControllerTest : public AshTestBase {
test_tick_clock_.Advance(delta); test_tick_clock_.Advance(delta);
} }
void OpenLidToAngle(float degrees) { void OpenLidToAngle(float degrees) { test_api_->OpenLidToAngle(degrees); }
DCHECK(degrees >= 0.0f); void HoldDeviceVertical() { test_api_->HoldDeviceVertical(); }
DCHECK(degrees <= 360.0f); void OpenLid() { test_api_->OpenLid(); }
void CloseLid() { test_api_->CloseLid(); }
float radians = degrees * kDegreesToRadians;
gfx::Vector3dF base_vector(0.0f, -kMeanGravity, 0.0f);
gfx::Vector3dF lid_vector(0.0f, kMeanGravity * cos(radians),
kMeanGravity * sin(radians));
TriggerBaseAndLidUpdate(base_vector, lid_vector);
}
void HoldDeviceVertical() {
gfx::Vector3dF base_vector(9.8f, 0.0f, 0.0f);
gfx::Vector3dF lid_vector(9.8f, 0.0f, 0.0f);
TriggerBaseAndLidUpdate(base_vector, lid_vector);
}
void OpenLid() {
tablet_mode_controller()->LidEventReceived(
chromeos::PowerManagerClient::LidState::OPEN,
test_api_->tick_clock()->NowTicks());
}
void CloseLid() {
tablet_mode_controller()->LidEventReceived(
chromeos::PowerManagerClient::LidState::CLOSED,
test_api_->tick_clock()->NowTicks());
}
bool CanUseUnstableLidAngle() { return test_api_->CanUseUnstableLidAngle(); } bool CanUseUnstableLidAngle() { return test_api_->CanUseUnstableLidAngle(); }
void SetTabletMode(bool on) { void SetTabletMode(bool on) { test_api_->SetTabletMode(on); }
tablet_mode_controller()->TabletModeEventReceived(
on ? chromeos::PowerManagerClient::TabletMode::ON
: chromeos::PowerManagerClient::TabletMode::OFF,
test_api_->tick_clock()->NowTicks());
}
bool AreEventsBlocked() { bool AreEventsBlocked() const { return test_api_->AreEventsBlocked(); }
return tablet_mode_controller()->AreInternalInputDeviceEventsBlocked();
}
TabletModeController::UiMode forced_ui_mode() const { TabletModeController::UiMode forced_ui_mode() const {
return test_api_->force_ui_mode(); return test_api_->force_ui_mode();
...@@ -585,7 +540,8 @@ TEST_F(TabletModeControllerTest, NoTabletModeWithDisabledInternalDisplay) { ...@@ -585,7 +540,8 @@ TEST_F(TabletModeControllerTest, NoTabletModeWithDisabledInternalDisplay) {
EXPECT_TRUE(IsTabletModeStarted()); EXPECT_TRUE(IsTabletModeStarted());
EXPECT_TRUE(AreEventsBlocked()); EXPECT_TRUE(AreEventsBlocked());
// Deactivate the internal display to simulate Docked Mode. // Close lid and deactivate the internal display to simulate Docked Mode.
CloseLid();
display_manager()->OnNativeDisplaysChanged(secondary_only); display_manager()->OnNativeDisplaysChanged(secondary_only);
ASSERT_FALSE(display_manager()->IsActiveDisplayId(internal_display_id)); ASSERT_FALSE(display_manager()->IsActiveDisplayId(internal_display_id));
EXPECT_FALSE(IsTabletModeStarted()); EXPECT_FALSE(IsTabletModeStarted());
...@@ -844,4 +800,33 @@ TEST_F(TabletModeControllerTest, LeaveTabletModeWhenExternalMouseConnected) { ...@@ -844,4 +800,33 @@ TEST_F(TabletModeControllerTest, LeaveTabletModeWhenExternalMouseConnected) {
EXPECT_TRUE(AreEventsBlocked()); EXPECT_TRUE(AreEventsBlocked());
} }
// Test that plug in or out a mouse in laptop mode will not change current
// laptop mode.
TEST_F(TabletModeControllerTest, ExternalMouseInLaptopMode) {
// Set the current list of devices to empty so that they don't interfere
// with the test.
base::RunLoop().RunUntilIdle();
ws::InputDeviceClientTestApi().SetMouseDevices({});
base::RunLoop().RunUntilIdle();
// Start in laptop mode.
OpenLidToAngle(30.0f);
EXPECT_FALSE(IsTabletModeStarted());
EXPECT_FALSE(AreEventsBlocked());
// Attach external mouse doesn't change the mode.
ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice(
3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")});
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(IsTabletModeStarted());
EXPECT_FALSE(AreEventsBlocked());
// Now remove the external mouse. It still should maintain in laptop mode
// because its lid angle is still in laptop mode.
ws::InputDeviceClientTestApi().SetMouseDevices({});
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(IsTabletModeStarted());
EXPECT_FALSE(AreEventsBlocked());
}
} // namespace ash } // namespace ash
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