Commit 8003483b authored by Katie D's avatar Katie D Committed by Commit Bot

Show confirmation when disabling automatic clicks.

This keeps users from accidentally disabling automatic clicks and
therefore locking themselves out of their device by making it so
that they need a physical click to re-enable the feature.

Dialog is shown when disabling from the accessibility menu in the
tray and from the settings WebUI page.

Bug: 960526
Change-Id: I681c8bfc1b668e6b290b33d889355b2a6f43500a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1601468Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarTetsui Ohkubo <tetsui@chromium.org>
Reviewed-by: default avatarAnastasia Helfinstein <anastasi@google.com>
Commit-Queue: Katie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659084}
parent c8ba61a2
...@@ -607,6 +607,8 @@ component("ash") { ...@@ -607,6 +607,8 @@ component("ash") {
"sticky_keys/sticky_keys_overlay.cc", "sticky_keys/sticky_keys_overlay.cc",
"sticky_keys/sticky_keys_overlay.h", "sticky_keys/sticky_keys_overlay.h",
"sticky_keys/sticky_keys_state.h", "sticky_keys/sticky_keys_state.h",
"system/accessibility/accessibility_feature_disable_dialog.cc",
"system/accessibility/accessibility_feature_disable_dialog.h",
"system/accessibility/accessibility_feature_pod_controller.cc", "system/accessibility/accessibility_feature_pod_controller.cc",
"system/accessibility/accessibility_feature_pod_controller.h", "system/accessibility/accessibility_feature_pod_controller.h",
"system/accessibility/autoclick_menu_bubble_controller.cc", "system/accessibility/autoclick_menu_bubble_controller.cc",
......
...@@ -905,7 +905,8 @@ void AccessibilityController::UpdateAutoclickFromPref() { ...@@ -905,7 +905,8 @@ void AccessibilityController::UpdateAutoclickFromPref() {
NotifyAccessibilityStatusChanged(); NotifyAccessibilityStatusChanged();
Shell::Get()->autoclick_controller()->SetEnabled(enabled); Shell::Get()->autoclick_controller()->SetEnabled(
enabled, true /* show confirmation dialog */);
} }
void AccessibilityController::UpdateAutoclickDelayFromPref() { void AccessibilityController::UpdateAutoclickDelayFromPref() {
......
...@@ -491,6 +491,12 @@ This file contains the strings for ash. ...@@ -491,6 +491,12 @@ This file contains the strings for ash.
<message name="IDS_ASH_AUTOCLICK_OPTION_CHANGE_POSITION" desc="The tooltip text for a menu option for automatic clicks menu that results in the menu changing position on the screen. The menu will toggle through several pre-set positions."> <message name="IDS_ASH_AUTOCLICK_OPTION_CHANGE_POSITION" desc="The tooltip text for a menu option for automatic clicks menu that results in the menu changing position on the screen. The menu will toggle through several pre-set positions.">
Toggle menu position Toggle menu position
</message> </message>
<message name="IDS_ASH_AUTOCLICK_DISABLE_CONFIRMATION_TITLE" desc="The title for the modal dialog shown when the user disables automatic clicks, to confirm they meant to disable the feature.">
Disable automatic clicks?
</message>
<message name="IDS_ASH_AUTOCLICK_DISABLE_CONFIRMATION_BODY" desc="The message in the modal dialog shown when the user disables automatic clicks, to confirm they meant to disable the feature">
Are you sure you want to disable automatic clicks?
</message>
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD" desc="The label used in the accessibility menu of the system tray to toggle on/off the onscreen keyboard."> <message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD" desc="The label used in the accessibility menu of the system tray to toggle on/off the onscreen keyboard.">
On-screen keyboard On-screen keyboard
</message> </message>
...@@ -1378,6 +1384,10 @@ This file contains the strings for ash. ...@@ -1378,6 +1384,10 @@ This file contains the strings for ash.
<message name="IDS_ASH_CONTINUE_BUTTON" desc="The text for continue button on accessibility confirmation dialogs."> <message name="IDS_ASH_CONTINUE_BUTTON" desc="The text for continue button on accessibility confirmation dialogs.">
Continue Continue
</message> </message>
<message name="IDS_ASH_DISABLE_BUTTON" desc="The text for the button on a dialog to confirm disabling a feature.">
Disable
</message>
<message name="IDS_ASH_IME_MENU_ACCESSIBLE_NAME" desc="The accessible text for opt-in IME menu icon in status tray."> <message name="IDS_ASH_IME_MENU_ACCESSIBLE_NAME" desc="The accessible text for opt-in IME menu icon in status tray.">
IME menu button IME menu button
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "ash/shelf/shelf.h" #include "ash/shelf/shelf.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/accessibility/accessibility_feature_disable_dialog.h"
#include "ash/system/accessibility/autoclick_menu_bubble_controller.h" #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
#include "ash/wm/root_window_finder.h" #include "ash/wm/root_window_finder.h"
#include "base/bind.h" #include "base/bind.h"
...@@ -90,12 +92,12 @@ void AutoclickController::SetTapDownTarget(aura::Window* target) { ...@@ -90,12 +92,12 @@ void AutoclickController::SetTapDownTarget(aura::Window* target) {
tap_down_target_->AddObserver(this); tap_down_target_->AddObserver(this);
} }
void AutoclickController::SetEnabled(bool enabled) { void AutoclickController::SetEnabled(bool enabled,
bool show_confirmation_dialog) {
if (enabled_ == enabled) if (enabled_ == enabled)
return; return;
enabled_ = enabled;
if (enabled_) { if (enabled) {
Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem); Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
// Only create the bubble controller when needed. Most users will not enable // Only create the bubble controller when needed. Most users will not enable
...@@ -107,9 +109,36 @@ void AutoclickController::SetEnabled(bool enabled) { ...@@ -107,9 +109,36 @@ void AutoclickController::SetEnabled(bool enabled) {
std::make_unique<AutoclickMenuBubbleController>(); std::make_unique<AutoclickMenuBubbleController>();
menu_bubble_controller_->ShowBubble(event_type_, menu_position_); menu_bubble_controller_->ShowBubble(event_type_, menu_position_);
} }
enabled_ = enabled;
} else { } else {
Shell::Get()->RemovePreTargetHandler(this); if (show_confirmation_dialog) {
menu_bubble_controller_ = nullptr; // If a dialog exists already, no need to show it again.
if (disable_dialog_)
return;
// Show a confirmation dialog before disabling autoclick.
auto* dialog = new AccessibilityFeatureDisableDialog(
IDS_ASH_AUTOCLICK_DISABLE_CONFIRMATION_TITLE,
IDS_ASH_AUTOCLICK_DISABLE_CONFIRMATION_BODY,
// Callback for if the user accepts the dialog
base::BindOnce([]() {
// If they accept, actually disable autoclick.
Shell::Get()->autoclick_controller()->SetEnabled(
false, false /* do not show the dialog */);
}),
// Callback for if the user cancels the dialog - marks the
// feature as enabled again in prefs.
base::BindOnce([]() {
AccessibilityController* controller =
Shell::Get()->accessibility_controller();
// If they cancel, ensure autoclick is enabled.
controller->SetAutoclickEnabled(true);
}));
disable_dialog_ = dialog->GetWeakPtr();
} else {
Shell::Get()->RemovePreTargetHandler(this);
menu_bubble_controller_ = nullptr;
enabled_ = enabled;
}
} }
CancelAutoclickAction(); CancelAutoclickAction();
......
...@@ -24,6 +24,7 @@ class Widget; ...@@ -24,6 +24,7 @@ class Widget;
namespace ash { namespace ash {
class AccessibilityFeatureDisableDialog;
class AutoclickDragEventRewriter; class AutoclickDragEventRewriter;
class AutoclickRingHandler; class AutoclickRingHandler;
class AutoclickMenuBubbleController; class AutoclickMenuBubbleController;
...@@ -38,8 +39,10 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler, ...@@ -38,8 +39,10 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler,
AutoclickController(); AutoclickController();
~AutoclickController() override; ~AutoclickController() override;
// Set whether autoclicking is enabled. // Set whether autoclicking is enabled. If |show_confirmation_dialog|, a
void SetEnabled(bool enabled); // confirmation dialog will be shown when disabling autoclick to ensure
// the user doesn't accidentally lock themselves out of the feature.
void SetEnabled(bool enabled, bool show_confirmation_dialog);
// Returns true if autoclicking is enabled. // Returns true if autoclicking is enabled.
bool IsEnabled() const; bool IsEnabled() const;
...@@ -85,6 +88,9 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler, ...@@ -85,6 +88,9 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler,
AutoclickMenuBubbleController* GetMenuBubbleControllerForTesting() { AutoclickMenuBubbleController* GetMenuBubbleControllerForTesting() {
return menu_bubble_controller_.get(); return menu_bubble_controller_.get();
} }
AccessibilityFeatureDisableDialog* GetDisableDialogForTesting() {
return disable_dialog_.get();
}
private: private:
void SetTapDownTarget(aura::Window* target); void SetTapDownTarget(aura::Window* target);
...@@ -157,6 +163,9 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler, ...@@ -157,6 +163,9 @@ class ASH_EXPORT AutoclickController : public ui::EventHandler,
std::unique_ptr<AutoclickDragEventRewriter> drag_event_rewriter_; std::unique_ptr<AutoclickDragEventRewriter> drag_event_rewriter_;
std::unique_ptr<AutoclickMenuBubbleController> menu_bubble_controller_; std::unique_ptr<AutoclickMenuBubbleController> menu_bubble_controller_;
// Holds a weak pointer to the dialog shown when autoclick is being disabled.
base::WeakPtr<AccessibilityFeatureDisableDialog> disable_dialog_;
DISALLOW_COPY_AND_ASSIGN(AutoclickController); DISALLOW_COPY_AND_ASSIGN(AutoclickController);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "ash/autoclick/autoclick_controller.h" #include "ash/autoclick/autoclick_controller.h"
#include "ash/shelf/shelf.h" #include "ash/shelf/shelf.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/system/accessibility/accessibility_feature_disable_dialog.h"
#include "ash/system/accessibility/autoclick_menu_bubble_controller.h" #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
#include "ash/system/accessibility/autoclick_menu_view.h" #include "ash/system/accessibility/autoclick_menu_view.h"
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#include "ui/events/event_utils.h" #include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h" #include "ui/events/test/event_generator.h"
#include "ui/views/window/dialog_client_view.h"
namespace ash { namespace ash {
...@@ -176,7 +178,7 @@ TEST_F(AutoclickTest, ToggleEnabled) { ...@@ -176,7 +178,7 @@ TEST_F(AutoclickTest, ToggleEnabled) {
// Enable autoclick, and we should see a mouse pressed and // Enable autoclick, and we should see a mouse pressed and
// a mouse released event, simulating a click. // a mouse released event, simulating a click.
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
GetEventGenerator()->MoveMouseTo(0, 0); GetEventGenerator()->MoveMouseTo(0, 0);
EXPECT_TRUE(GetAutoclickController()->IsEnabled()); EXPECT_TRUE(GetAutoclickController()->IsEnabled());
events = WaitForMouseEvents(); events = WaitForMouseEvents();
...@@ -198,7 +200,7 @@ TEST_F(AutoclickTest, ToggleEnabled) { ...@@ -198,7 +200,7 @@ TEST_F(AutoclickTest, ToggleEnabled) {
EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags()); EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
// Disable autoclick, and we should see the original behaviour. // Disable autoclick, and we should see the original behaviour.
GetAutoclickController()->SetEnabled(false); GetAutoclickController()->SetEnabled(false, false /* do not show dialog */);
EXPECT_FALSE(GetAutoclickController()->IsEnabled()); EXPECT_FALSE(GetAutoclickController()->IsEnabled());
events = WaitForMouseEvents(); events = WaitForMouseEvents();
EXPECT_EQ(0u, events.size()); EXPECT_EQ(0u, events.size());
...@@ -206,7 +208,7 @@ TEST_F(AutoclickTest, ToggleEnabled) { ...@@ -206,7 +208,7 @@ TEST_F(AutoclickTest, ToggleEnabled) {
TEST_F(AutoclickTest, MouseMovement) { TEST_F(AutoclickTest, MouseMovement) {
std::vector<ui::MouseEvent> events; std::vector<ui::MouseEvent> events;
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
gfx::Point p1(0, 0); gfx::Point p1(0, 0);
gfx::Point p2(20, 20); gfx::Point p2(20, 20);
...@@ -255,7 +257,8 @@ TEST_F(AutoclickTest, MovementThreshold) { ...@@ -255,7 +257,8 @@ TEST_F(AutoclickTest, MovementThreshold) {
for (auto* root_window : root_windows) { for (auto* root_window : root_windows) {
gfx::Point center = root_window->GetBoundsInScreen().CenterPoint(); gfx::Point center = root_window->GetBoundsInScreen().CenterPoint();
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true,
false /* do not show dialog */);
GetEventGenerator()->MoveMouseTo(center); GetEventGenerator()->MoveMouseTo(center);
ClearMouseEvents(); ClearMouseEvents();
EXPECT_EQ(2u, WaitForMouseEvents().size()); EXPECT_EQ(2u, WaitForMouseEvents().size());
...@@ -314,7 +317,7 @@ TEST_F(AutoclickTest, MovementThreshold) { ...@@ -314,7 +317,7 @@ TEST_F(AutoclickTest, MovementThreshold) {
} }
TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) { TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
GetAutoclickController()->SetMovementThreshold(20); GetAutoclickController()->SetMovementThreshold(20);
int animation_delay = 5; int animation_delay = 5;
int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay); int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
...@@ -362,7 +365,7 @@ TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) { ...@@ -362,7 +365,7 @@ TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) {
} }
TEST_F(AutoclickTest, SingleKeyModifier) { TEST_F(AutoclickTest, SingleKeyModifier) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN); MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN);
std::vector<ui::MouseEvent> events = WaitForMouseEvents(); std::vector<ui::MouseEvent> events = WaitForMouseEvents();
EXPECT_EQ(2u, events.size()); EXPECT_EQ(2u, events.size());
...@@ -371,7 +374,7 @@ TEST_F(AutoclickTest, SingleKeyModifier) { ...@@ -371,7 +374,7 @@ TEST_F(AutoclickTest, SingleKeyModifier) {
} }
TEST_F(AutoclickTest, MultipleKeyModifiers) { TEST_F(AutoclickTest, MultipleKeyModifiers) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
ui::EventFlags modifier_flags = static_cast<ui::EventFlags>( ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN); ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
MoveMouseWithFlagsTo(30, 30, modifier_flags); MoveMouseWithFlagsTo(30, 30, modifier_flags);
...@@ -382,7 +385,7 @@ TEST_F(AutoclickTest, MultipleKeyModifiers) { ...@@ -382,7 +385,7 @@ TEST_F(AutoclickTest, MultipleKeyModifiers) {
} }
TEST_F(AutoclickTest, KeyModifiersReleased) { TEST_F(AutoclickTest, KeyModifiersReleased) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
ui::EventFlags modifier_flags = static_cast<ui::EventFlags>( ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN); ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
...@@ -403,7 +406,7 @@ TEST_F(AutoclickTest, KeyModifiersReleased) { ...@@ -403,7 +406,7 @@ TEST_F(AutoclickTest, KeyModifiersReleased) {
} }
TEST_F(AutoclickTest, UserInputCancelsAutoclick) { TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
std::vector<ui::MouseEvent> events; std::vector<ui::MouseEvent> events;
// Pressing a normal key should cancel the autoclick. // Pressing a normal key should cancel the autoclick.
...@@ -459,7 +462,7 @@ TEST_F(AutoclickTest, UserInputCancelsAutoclick) { ...@@ -459,7 +462,7 @@ TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
} }
TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) { TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
std::vector<ui::MouseEvent> events; std::vector<ui::MouseEvent> events;
GetEventGenerator()->MoveMouseTo(100, 100); GetEventGenerator()->MoveMouseTo(100, 100);
events = WaitForMouseEvents(); events = WaitForMouseEvents();
...@@ -478,7 +481,7 @@ TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) { ...@@ -478,7 +481,7 @@ TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) {
} }
TEST_F(AutoclickTest, AutoclickChangeEventTypes) { TEST_F(AutoclickTest, AutoclickChangeEventTypes) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
GetAutoclickController()->set_revert_to_left_click(false); GetAutoclickController()->set_revert_to_left_click(false);
GetAutoclickController()->SetAutoclickEventType( GetAutoclickController()->SetAutoclickEventType(
mojom::AutoclickEventType::kRightClick); mojom::AutoclickEventType::kRightClick);
...@@ -542,7 +545,7 @@ TEST_F(AutoclickTest, AutoclickChangeEventTypes) { ...@@ -542,7 +545,7 @@ TEST_F(AutoclickTest, AutoclickChangeEventTypes) {
} }
TEST_F(AutoclickTest, AutoclickDragAndDropEvents) { TEST_F(AutoclickTest, AutoclickDragAndDropEvents) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
GetAutoclickController()->set_revert_to_left_click(false); GetAutoclickController()->set_revert_to_left_click(false);
GetAutoclickController()->SetAutoclickEventType( GetAutoclickController()->SetAutoclickEventType(
mojom::AutoclickEventType::kDragAndDrop); mojom::AutoclickEventType::kDragAndDrop);
...@@ -574,7 +577,7 @@ TEST_F(AutoclickTest, AutoclickDragAndDropEvents) { ...@@ -574,7 +577,7 @@ TEST_F(AutoclickTest, AutoclickDragAndDropEvents) {
} }
TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) { TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) {
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
GetAutoclickController()->set_revert_to_left_click(true); GetAutoclickController()->set_revert_to_left_click(true);
GetAutoclickController()->SetAutoclickEventType( GetAutoclickController()->SetAutoclickEventType(
mojom::AutoclickEventType::kRightClick); mojom::AutoclickEventType::kRightClick);
...@@ -635,7 +638,7 @@ TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) { ...@@ -635,7 +638,7 @@ TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) {
TEST_F(AutoclickTest, WaitsToDrawAnimationAfterDwellBegins) { TEST_F(AutoclickTest, WaitsToDrawAnimationAfterDwellBegins) {
int animation_delay = 5; int animation_delay = 5;
int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay); int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
GetAutoclickController()->SetEnabled(true); GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
std::vector<ui::MouseEvent> events; std::vector<ui::MouseEvent> events;
// Start a dwell at (210, 210). // Start a dwell at (210, 210).
...@@ -788,9 +791,6 @@ TEST_F(AutoclickTest, DoesActionOnBubbleWhenInDifferentModes) { ...@@ -788,9 +791,6 @@ TEST_F(AutoclickTest, DoesActionOnBubbleWhenInDifferentModes) {
EXPECT_EQ(mojom::AutoclickEventType::kLeftClick, EXPECT_EQ(mojom::AutoclickEventType::kLeftClick,
accessibility_controller->GetAutoclickEventType()); accessibility_controller->GetAutoclickEventType());
} }
// Reset state.
accessibility_controller->SetAutoclickEnabled(false);
} }
TEST_F(AutoclickTest, TEST_F(AutoclickTest,
...@@ -834,14 +834,10 @@ TEST_F(AutoclickTest, ...@@ -834,14 +834,10 @@ TEST_F(AutoclickTest,
FastForwardBy(full_delay); FastForwardBy(full_delay);
events = GetMouseEvents(); events = GetMouseEvents();
ASSERT_EQ(0u, events.size()); ASSERT_EQ(0u, events.size());
// Reset state.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
} }
// The autoclick tray shouldn't stop the shelf from auto-hiding. // The autoclick tray shouldn't stop the shelf from auto-hiding.
TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) { TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) {
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
Shelf* shelf = GetPrimaryShelf(); Shelf* shelf = GetPrimaryShelf();
// Create a visible window so auto-hide behavior is enforced. // Create a visible window so auto-hide behavior is enforced.
...@@ -860,9 +856,6 @@ TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) { ...@@ -860,9 +856,6 @@ TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) {
ASSERT_TRUE(menu); ASSERT_TRUE(menu);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
// Reset state.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
} }
TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) { TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) {
...@@ -912,8 +905,43 @@ TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) { ...@@ -912,8 +905,43 @@ TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) {
shelf->GetIdealBounds().width()); shelf->GetIdealBounds().width());
// Reset state. // Reset state.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
} }
TEST_F(AutoclickTest, ConfirmationDialogShownWhenDisablingFeature) {
// Enable and disable with the AccessibilityController to get real use-case
// of the dialog.
// No dialog shown at start-up.
EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
// No dialog shown when enabling the feature.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true);
EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
// A dialog should be shown when disabling the feature.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
AccessibilityFeatureDisableDialog* dialog =
GetAutoclickController()->GetDisableDialogForTesting();
EXPECT_TRUE(dialog);
// Canceling the dialog will cause the feature to continue to be enabled.
dialog->GetDialogClientView()->CancelWindow();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
EXPECT_TRUE(Shell::Get()->accessibility_controller()->autoclick_enabled());
EXPECT_TRUE(GetAutoclickController()->IsEnabled());
// Try to disable it again, and this time accept the dialog to actually
// disable the feature.
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
dialog = GetAutoclickController()->GetDisableDialogForTesting();
EXPECT_TRUE(dialog);
dialog->GetDialogClientView()->AcceptWindow();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
EXPECT_FALSE(Shell::Get()->accessibility_controller()->autoclick_enabled());
EXPECT_FALSE(GetAutoclickController()->IsEnabled());
}
} // namespace ash } // namespace ash
...@@ -13,10 +13,10 @@ enum ViewID { ...@@ -13,10 +13,10 @@ enum ViewID {
// Ash IDs start above the range used in Chrome (c/b/ui/view_ids.h). // Ash IDs start above the range used in Chrome (c/b/ui/view_ids.h).
VIEW_ID_ASH_START = 10000, VIEW_ID_ASH_START = 10000,
// Row for auto click feature in accessibility detailed view. // Row for the virtual keyboard feature in accessibility detailed view.
VIEW_ID_ACCESSIBILITY_AUTOCLICK, VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD,
// Icon that indicates auto click is enabled. // Icon that indicates the virtual keyboard is enabled.
VIEW_ID_ACCESSIBILITY_AUTOCLICK_ENABLED, VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD_ENABLED,
// Accessibility feature pod button in main view. // Accessibility feature pod button in main view.
VIEW_ID_ACCESSIBILITY_TRAY_ITEM, VIEW_ID_ACCESSIBILITY_TRAY_ITEM,
VIEW_ID_BLUETOOTH_DEFAULT_VIEW, VIEW_ID_BLUETOOTH_DEFAULT_VIEW,
......
// Copyright (c) 2019 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/system/accessibility/accessibility_feature_disable_dialog.h"
#include <memory>
#include <utility>
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/border.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/widget/widget.h"
namespace ash {
AccessibilityFeatureDisableDialog::AccessibilityFeatureDisableDialog(
int window_title_text_id,
int dialog_text_id,
base::OnceClosure on_accept_callback,
base::OnceClosure on_cancel_callback)
: window_title_(l10n_util::GetStringUTF16(window_title_text_id)),
on_accept_callback_(std::move(on_accept_callback)),
on_cancel_callback_(std::move(on_cancel_callback)),
weak_ptr_factory_(this) {
SetLayoutManager(std::make_unique<views::FillLayout>());
SetBorder(views::CreateEmptyBorder(
views::LayoutProvider::Get()->GetDialogInsetsForContentType(
views::TEXT, views::TEXT)));
AddChildView(std::make_unique<views::Label>(
l10n_util::GetStringUTF16(dialog_text_id)));
// Parent the dialog widget to the LockSystemModalContainer, or
// OverlayContainer to ensure that it will get displayed on respective
// lock/signin or OOBE screen.
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
int container_id = kShellWindowId_SystemModalContainer;
if (session_controller->GetSessionState() ==
session_manager::SessionState::OOBE) {
container_id = kShellWindowId_OverlayContainer;
} else if (session_controller->IsUserSessionBlocked()) {
container_id = kShellWindowId_LockSystemModalContainer;
}
views::Widget* widget = CreateDialogWidget(
this, nullptr,
Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), container_id));
widget->Show();
}
AccessibilityFeatureDisableDialog::~AccessibilityFeatureDisableDialog() =
default;
bool AccessibilityFeatureDisableDialog::Cancel() {
std::move(on_cancel_callback_).Run();
return true;
}
bool AccessibilityFeatureDisableDialog::Accept() {
std::move(on_accept_callback_).Run();
return true;
}
ui::ModalType AccessibilityFeatureDisableDialog::GetModalType() const {
return ui::MODAL_TYPE_SYSTEM;
}
base::string16 AccessibilityFeatureDisableDialog::GetWindowTitle() const {
return window_title_;
}
base::string16 AccessibilityFeatureDisableDialog::GetDialogButtonLabel(
ui::DialogButton button) const {
if (button == ui::DIALOG_BUTTON_OK)
return l10n_util::GetStringUTF16(IDS_ASH_DISABLE_BUTTON);
return views::DialogDelegateView::GetDialogButtonLabel(button);
}
base::WeakPtr<AccessibilityFeatureDisableDialog>
AccessibilityFeatureDisableDialog::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace ash
\ No newline at end of file
// Copyright (c) 2019 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_SYSTEM_ACCESSIBILITY_ACCESSIBILITY_FEATURE_DISABLE_DIALOG_H_
#define ASH_SYSTEM_ACCESSIBILITY_ACCESSIBILITY_FEATURE_DISABLE_DIALOG_H_
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "ui/views/window/dialog_delegate.h"
namespace ash {
// Defines a dialog for accessibility features that require confirmation from
// users prior to being disabled. For features like automatic clicks and switch
// access, accidentally disabling the feature could cause users to be unable to
// use their devices.
class AccessibilityFeatureDisableDialog : public views::DialogDelegateView {
public:
AccessibilityFeatureDisableDialog(int window_title_text_id,
int dialog_text_id,
base::OnceClosure on_accept_callback,
base::OnceClosure on_cancel_callback);
~AccessibilityFeatureDisableDialog() override;
// views::DialogDelegateView:
bool Cancel() override;
bool Accept() override;
ui::ModalType GetModalType() const override;
base::string16 GetWindowTitle() const override;
base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
base::WeakPtr<AccessibilityFeatureDisableDialog> GetWeakPtr();
private:
const base::string16 window_title_;
base::OnceClosure on_accept_callback_;
base::OnceClosure on_cancel_callback_;
base::WeakPtrFactory<AccessibilityFeatureDisableDialog> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AccessibilityFeatureDisableDialog);
};
} // namespace ash
#endif // ASH_SYSTEM_ACCESSIBILITY_ACCESSIBILITY_FEATURE_DISABLE_DIALOG_H_
\ No newline at end of file
...@@ -74,9 +74,11 @@ TEST_F(AutoclickMenuBubbleControllerTest, ExistsOnlyWhenAutoclickIsRunning) { ...@@ -74,9 +74,11 @@ TEST_F(AutoclickMenuBubbleControllerTest, ExistsOnlyWhenAutoclickIsRunning) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
EXPECT_TRUE(GetBubbleController()); EXPECT_TRUE(GetBubbleController());
EXPECT_TRUE(GetMenuView()); EXPECT_TRUE(GetMenuView());
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false); Shell::Get()->autoclick_controller()->SetEnabled(
false, false /* do not show dialog */);
EXPECT_FALSE(GetBubbleController()); EXPECT_FALSE(GetBubbleController());
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true); Shell::Get()->autoclick_controller()->SetEnabled(
true, false /* do not show dialog */);
} }
} }
......
...@@ -191,9 +191,6 @@ void AccessibilityDetailedView::AppendAccessibilityList() { ...@@ -191,9 +191,6 @@ void AccessibilityDetailedView::AppendAccessibilityList() {
kSystemMenuAccessibilityAutoClickIcon, kSystemMenuAccessibilityAutoClickIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK), l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK),
autoclick_enabled_); autoclick_enabled_);
autoclick_view_->SetID(ash::VIEW_ID_ACCESSIBILITY_AUTOCLICK);
autoclick_view_->right_view()->SetID(
ash::VIEW_ID_ACCESSIBILITY_AUTOCLICK_ENABLED);
virtual_keyboard_enabled_ = controller->virtual_keyboard_enabled(); virtual_keyboard_enabled_ = controller->virtual_keyboard_enabled();
virtual_keyboard_view_ = AddScrollListCheckableItem( virtual_keyboard_view_ = AddScrollListCheckableItem(
...@@ -201,6 +198,9 @@ void AccessibilityDetailedView::AppendAccessibilityList() { ...@@ -201,6 +198,9 @@ void AccessibilityDetailedView::AppendAccessibilityList() {
l10n_util::GetStringUTF16( l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD), IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD),
virtual_keyboard_enabled_); virtual_keyboard_enabled_);
virtual_keyboard_view_->SetID(ash::VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD);
virtual_keyboard_view_->right_view()->SetID(
ash::VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD_ENABLED);
if (base::CommandLine::ForCurrentProcess()->HasSwitch( if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalAccessibilitySwitchAccess)) { switches::kEnableExperimentalAccessibilitySwitchAccess)) {
......
...@@ -194,16 +194,17 @@ class TrayAccessibilityTest ...@@ -194,16 +194,17 @@ class TrayAccessibilityTest
return is_open; return is_open;
} }
void ClickAutoclickOnDetailMenu() { void ClickVirtualKeyboardOnDetailMenu() {
ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get()); ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
wait_for.ClickBubbleView(ash::VIEW_ID_ACCESSIBILITY_AUTOCLICK); wait_for.ClickBubbleView(ash::VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD);
} }
bool IsAutoclickEnabledOnDetailMenu() const { bool IsVirtualKeyboardEnabledOnDetailMenu() const {
ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get()); ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
bool visible = false; bool visible = false;
wait_for.IsBubbleViewVisible(ash::VIEW_ID_ACCESSIBILITY_AUTOCLICK_ENABLED, wait_for.IsBubbleViewVisible(
false /* open_tray */, &visible); ash::VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD_ENABLED,
false /* open_tray */, &visible);
return visible; return visible;
} }
...@@ -497,19 +498,21 @@ IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, KeepMenuVisibilityOnLockScreen) { ...@@ -497,19 +498,21 @@ IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, KeepMenuVisibilityOnLockScreen) {
// Verify that the accessiblity system detailed menu remains open when an item // Verify that the accessiblity system detailed menu remains open when an item
// is selected or deselected. // is selected or deselected.
// Do not use a feature which requires an enable/disable confirmation dialog
// here, as the dialogs change focus and close the detail menu.
IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, DetailMenuRemainsOpen) { IN_PROC_BROWSER_TEST_P(TrayAccessibilityTest, DetailMenuRemainsOpen) {
CreateDetailedMenu(); CreateDetailedMenu();
ClickAutoclickOnDetailMenu(); ClickVirtualKeyboardOnDetailMenu();
EXPECT_TRUE(IsAutoclickEnabledOnDetailMenu()); EXPECT_TRUE(IsVirtualKeyboardEnabledOnDetailMenu());
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
} }
EXPECT_TRUE(IsBubbleOpen()); EXPECT_TRUE(IsBubbleOpen());
ClickAutoclickOnDetailMenu(); ClickVirtualKeyboardOnDetailMenu();
EXPECT_FALSE(IsAutoclickEnabledOnDetailMenu()); EXPECT_FALSE(IsVirtualKeyboardEnabledOnDetailMenu());
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
......
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