Commit be4ea77f authored by Zach Helfinstein's avatar Zach Helfinstein Committed by Commit Bot

Add dictation to SwitchAccess context menu

Bug: 864796
Cq-Include-Trybots: luci.chromium.try:closure_compilation
Change-Id: Ie299534b069a83dc38012468f547810f7b83b0b0
Reviewed-on: https://chromium-review.googlesource.com/c/1227501Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarIstiaque Ahmed <lazyboy@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Commit-Queue: Zach Helfinstein <zhelfins@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596340}
parent 065b3aef
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "ash/new_window_controller.h" #include "ash/new_window_controller.h"
#include "ash/public/cpp/app_list/app_list_constants.h" #include "ash/public/cpp/app_list/app_list_constants.h"
#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_features.h"
#include "ash/public/interfaces/accessibility_controller.mojom.h"
#include "ash/resources/vector_icons/vector_icons.h" #include "ash/resources/vector_icons/vector_icons.h"
#include "ash/root_window_controller.h" #include "ash/root_window_controller.h"
#include "ash/rotator/window_rotation.h" #include "ash/rotator/window_rotation.h"
...@@ -812,9 +813,8 @@ bool CanHandleToggleDictation() { ...@@ -812,9 +813,8 @@ bool CanHandleToggleDictation() {
void HandleToggleDictation() { void HandleToggleDictation() {
base::RecordAction(UserMetricsAction("Accel_Toggle_Dictation")); base::RecordAction(UserMetricsAction("Accel_Toggle_Dictation"));
UserMetricsRecorder::RecordUserToggleDictation( Shell::Get()->accessibility_controller()->ToggleDictationFromSource(
DictationToggleMethod::kToggleByKeyboard); mojom::DictationToggleSource::kKeyboard);
Shell::Get()->accessibility_controller()->ToggleDictation();
} }
bool CanHandleToggleDockedMagnifier() { bool CanHandleToggleDockedMagnifier() {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "ash/system/power/scoped_backlights_forced_off.h" #include "ash/system/power/scoped_backlights_forced_off.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/audio/cras_audio_handler.h"
#include "components/pref_registry/pref_registry_syncable.h" #include "components/pref_registry/pref_registry_syncable.h"
...@@ -648,6 +649,14 @@ void AccessibilityController::ToggleDictation() { ...@@ -648,6 +649,14 @@ void AccessibilityController::ToggleDictation() {
} }
} }
void AccessibilityController::ToggleDictationFromSource(
mojom::DictationToggleSource source) {
base::RecordAction(base::UserMetricsAction("Accel_Toggle_Dictation"));
UserMetricsRecorder::RecordUserToggleDictation(source);
ToggleDictation();
}
void AccessibilityController::SilenceSpokenFeedback() { void AccessibilityController::SilenceSpokenFeedback() {
if (client_) if (client_)
client_->SilenceSpokenFeedback(); client_->SilenceSpokenFeedback();
......
...@@ -167,6 +167,7 @@ class ASH_EXPORT AccessibilityController ...@@ -167,6 +167,7 @@ class ASH_EXPORT AccessibilityController
void SetSelectToSpeakState(mojom::SelectToSpeakState state) override; void SetSelectToSpeakState(mojom::SelectToSpeakState state) override;
void SetSelectToSpeakEventHandlerDelegate( void SetSelectToSpeakEventHandlerDelegate(
mojom::SelectToSpeakEventHandlerDelegatePtr delegate) override; mojom::SelectToSpeakEventHandlerDelegatePtr delegate) override;
void ToggleDictationFromSource(mojom::DictationToggleSource source) override;
// SessionObserver: // SessionObserver:
void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override; void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/public/cpp/shelf_item.h" #include "ash/public/cpp/shelf_item.h"
#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_model.h"
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/interfaces/accessibility_controller.mojom-shared.h"
#include "ash/public/interfaces/window_state_type.mojom.h" #include "ash/public/interfaces/window_state_type.mojom.h"
#include "ash/session/session_controller.h" #include "ash/session/session_controller.h"
#include "ash/shelf/shelf.h" #include "ash/shelf/shelf.h"
...@@ -200,9 +201,9 @@ void UserMetricsRecorder::RecordUserClickOnShelfButton( ...@@ -200,9 +201,9 @@ void UserMetricsRecorder::RecordUserClickOnShelfButton(
// static // static
void UserMetricsRecorder::RecordUserToggleDictation( void UserMetricsRecorder::RecordUserToggleDictation(
DictationToggleMethod method) { mojom::DictationToggleSource source) {
UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosDictation.ToggleDictationMethod", UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosDictation.ToggleDictationMethod",
method); source);
} }
void UserMetricsRecorder::RecordUserMetricsAction(UserMetricsAction action) { void UserMetricsRecorder::RecordUserMetricsAction(UserMetricsAction action) {
......
...@@ -16,19 +16,14 @@ ...@@ -16,19 +16,14 @@
namespace ash { namespace ash {
namespace mojom {
enum class DictationToggleSource;
} // namespace mojom
class DemoSessionMetricsRecorder; class DemoSessionMetricsRecorder;
class DesktopTaskSwitchMetricRecorder; class DesktopTaskSwitchMetricRecorder;
class PointerMetricsRecorder; class PointerMetricsRecorder;
// CrosDictationStartDictationMethod enum values.
// These values are persisted to logs and should not be renumbered or re-used.
// See tools/metrics/histograms/enums.xml.
enum class DictationToggleMethod {
kToggleByKeyboard,
kToggleByButton,
kMaxValue = kToggleByButton
};
// User Metrics Recorder provides a repeating callback (RecordPeriodicMetrics) // User Metrics Recorder provides a repeating callback (RecordPeriodicMetrics)
// on a timer to allow recording of state data over time to the UMA records. // on a timer to allow recording of state data over time to the UMA records.
// Any additional states (in ash) that require monitoring can be added to // Any additional states (in ash) that require monitoring can be added to
...@@ -51,7 +46,7 @@ class ASH_EXPORT UserMetricsRecorder { ...@@ -51,7 +46,7 @@ class ASH_EXPORT UserMetricsRecorder {
LoginMetricsRecorder::ShelfButtonClickTarget target); LoginMetricsRecorder::ShelfButtonClickTarget target);
// Record the method used to activate dictation. // Record the method used to activate dictation.
static void RecordUserToggleDictation(DictationToggleMethod method); static void RecordUserToggleDictation(mojom::DictationToggleSource source);
// Records an Ash owned user action. // Records an Ash owned user action.
void RecordUserMetricsAction(UserMetricsAction action); void RecordUserMetricsAction(UserMetricsAction action);
......
...@@ -48,6 +48,22 @@ enum AccessibilityPanelState { ...@@ -48,6 +48,22 @@ enum AccessibilityPanelState {
FULLSCREEN FULLSCREEN
}; };
// These values are persisted to logs and should not be renumbered or re-used.
// See tools/metrics/histograms/enums.xml.
enum DictationToggleSource {
// Toggled by the keyboard command (Search + D).
kKeyboard,
// Toggled by the dictation button in the tray.
kButton,
// Switch Access context menu button.
kSwitchAccess,
// Chromevox chrome extension.
kChromevox
};
enum SelectToSpeakState { enum SelectToSpeakState {
// Select to Speak is not actively selecting text or speaking. // Select to Speak is not actively selecting text or speaking.
kSelectToSpeakStateInactive, kSelectToSpeakStateInactive,
...@@ -111,6 +127,9 @@ interface AccessibilityController { ...@@ -111,6 +127,9 @@ interface AccessibilityController {
// Set the delegate used by the Select-to-Speak event handler. // Set the delegate used by the Select-to-Speak event handler.
SetSelectToSpeakEventHandlerDelegate( SetSelectToSpeakEventHandlerDelegate(
SelectToSpeakEventHandlerDelegate delegate); SelectToSpeakEventHandlerDelegate delegate);
// Starts or stops dictation. Records metrics for toggling via SwitchAccess.
ToggleDictationFromSource(DictationToggleSource source);
}; };
// Interface for ash to request accessibility service from its client (e.g. // Interface for ash to request accessibility service from its client (e.g.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "ash/accessibility/accessibility_controller.h" #include "ash/accessibility/accessibility_controller.h"
#include "ash/metrics/user_metrics_recorder.h" #include "ash/metrics/user_metrics_recorder.h"
#include "ash/public/interfaces/accessibility_controller.mojom.h"
#include "ash/resources/vector_icons/vector_icons.h" #include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shelf/shelf_constants.h" #include "ash/shelf/shelf_constants.h"
#include "ash/shell.h" #include "ash/shell.h"
...@@ -46,11 +47,9 @@ DictationButtonTray::~DictationButtonTray() { ...@@ -46,11 +47,9 @@ DictationButtonTray::~DictationButtonTray() {
} }
bool DictationButtonTray::PerformAction(const ui::Event& event) { bool DictationButtonTray::PerformAction(const ui::Event& event) {
UserMetricsRecorder::RecordUserToggleDictation( Shell::Get()->accessibility_controller()->ToggleDictationFromSource(
DictationToggleMethod::kToggleByButton); mojom::DictationToggleSource::kButton);
Shell::Get()->accelerator_controller()->PerformActionIfEnabled(
AcceleratorAction::TOGGLE_DICTATION);
CheckDictationStatusAndUpdateIcon(); CheckDictationStatusAndUpdateIcon();
return true; return true;
} }
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ash/public/interfaces/accessibility_controller.mojom.h"
#include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h" #include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h"
#include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/constants.mojom.h"
#include "ash/public/interfaces/event_rewriter_controller.mojom.h" #include "ash/public/interfaces/event_rewriter_controller.mojom.h"
...@@ -53,6 +54,17 @@ namespace { ...@@ -53,6 +54,17 @@ namespace {
const char kErrorNotSupported[] = "This API is not supported on this platform."; const char kErrorNotSupported[] = "This API is not supported on this platform.";
#if defined(OS_CHROMEOS)
ash::mojom::AccessibilityControllerPtr GetAccessibilityController() {
// Connect to the accessibility mojo interface in ash.
ash::mojom::AccessibilityControllerPtr accessibility_controller;
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->BindInterface(ash::mojom::kServiceName, &accessibility_controller);
return accessibility_controller;
}
#endif
} // namespace } // namespace
ExtensionFunction::ResponseAction ExtensionFunction::ResponseAction
...@@ -302,4 +314,20 @@ AccessibilityPrivateOnSelectToSpeakStateChangedFunction::Run() { ...@@ -302,4 +314,20 @@ AccessibilityPrivateOnSelectToSpeakStateChangedFunction::Run() {
return RespondNow(NoArguments()); return RespondNow(NoArguments());
} }
ExtensionFunction::ResponseAction
AccessibilityPrivateToggleDictationFunction::Run() {
ash::mojom::DictationToggleSource source =
ash::mojom::DictationToggleSource::kChromevox;
if (extension()->id() == extension_misc::kSwitchAccessExtensionId)
source = ash::mojom::DictationToggleSource::kSwitchAccess;
else if (extension()->id() == extension_misc::kChromeVoxExtensionId)
source = ash::mojom::DictationToggleSource::kChromevox;
else
NOTREACHED();
GetAccessibilityController()->ToggleDictationFromSource(source);
return RespondNow(NoArguments());
}
#endif // defined (OS_CHROMEOS) #endif // defined (OS_CHROMEOS)
...@@ -97,6 +97,17 @@ class AccessibilityPrivateOnSelectToSpeakStateChangedFunction ...@@ -97,6 +97,17 @@ class AccessibilityPrivateOnSelectToSpeakStateChangedFunction
DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.onSelectToSpeakStateChanged", DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.onSelectToSpeakStateChanged",
ACCESSIBILITY_PRIVATE_ONSELECTTOSPEAKSTATECHANGED) ACCESSIBILITY_PRIVATE_ONSELECTTOSPEAKSTATECHANGED)
}; };
// API function that is called when a SwitchAccess user toggles Dictation from
// the context menu.
class AccessibilityPrivateToggleDictationFunction
: public UIThreadExtensionFunction {
~AccessibilityPrivateToggleDictationFunction() override {}
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.toggleDictation",
ACCESSIBILITY_PRIVATE_TOGGLEDICTATION)
};
#endif // defined (OS_CHROMEOS) #endif // defined (OS_CHROMEOS)
#endif // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_ #endif // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_
...@@ -251,8 +251,9 @@ class AutomationManager { ...@@ -251,8 +251,9 @@ class AutomationManager {
getRelevantMenuActions_() { getRelevantMenuActions_() {
// TODO(crbug/881080): determine relevant actions programmatically. // TODO(crbug/881080): determine relevant actions programmatically.
let actions = [ let actions = [
ContextMenuManager.Action.CLICK, ContextMenuManager.Action.OPTIONS, ContextMenuManager.Action.CLICK, ContextMenuManager.Action.DICTATION,
ContextMenuManager.Action.SCROLL_UP, ContextMenuManager.Action.SCROLL_DOWN ContextMenuManager.Action.OPTIONS, ContextMenuManager.Action.SCROLL_UP,
ContextMenuManager.Action.SCROLL_DOWN
]; ];
return actions; return actions;
} }
......
...@@ -194,6 +194,8 @@ class ContextMenuManager { ...@@ -194,6 +194,8 @@ class ContextMenuManager {
if (event.data === ContextMenuManager.Action.CLICK) if (event.data === ContextMenuManager.Action.CLICK)
this.automationManager_.selectCurrentNode(); this.automationManager_.selectCurrentNode();
else if (event.data === ContextMenuManager.Action.DICTATION)
chrome.accessibilityPrivate.toggleDictation();
else if (event.data === ContextMenuManager.Action.OPTIONS) else if (event.data === ContextMenuManager.Action.OPTIONS)
window.switchAccess.showOptionsPage(); window.switchAccess.showOptionsPage();
else if ( else if (
...@@ -228,6 +230,7 @@ class ContextMenuManager { ...@@ -228,6 +230,7 @@ class ContextMenuManager {
*/ */
ContextMenuManager.Action = { ContextMenuManager.Action = {
CLICK: 'click', CLICK: 'click',
DICTATION: 'dictation',
OPTIONS: 'options', OPTIONS: 'options',
SCROLL_BACKWARD: 'scroll-backward', SCROLL_BACKWARD: 'scroll-backward',
SCROLL_DOWN: 'scroll-down', SCROLL_DOWN: 'scroll-down',
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
<button class="action" id="scroll-up" disabled>Scroll up</button> <button class="action" id="scroll-up" disabled>Scroll up</button>
<button class="action" id="scroll-right" disabled>Scroll right</button> <button class="action" id="scroll-right" disabled>Scroll right</button>
<button class="action" id="scroll-left" disabled>Scroll left</button> <button class="action" id="scroll-left" disabled>Scroll left</button>
<button class="action" id="dictation">Dictation</button>
<button class="action" id="options">Options</button> <button class="action" id="options">Options</button>
</div> </div>
</body> </body>
...@@ -45,6 +45,8 @@ class TestAccessibilityController : ash::mojom::AccessibilityController { ...@@ -45,6 +45,8 @@ class TestAccessibilityController : ash::mojom::AccessibilityController {
void SetSelectToSpeakState(ash::mojom::SelectToSpeakState state) override {} void SetSelectToSpeakState(ash::mojom::SelectToSpeakState state) override {}
void SetSelectToSpeakEventHandlerDelegate( void SetSelectToSpeakEventHandlerDelegate(
ash::mojom::SelectToSpeakEventHandlerDelegatePtr delegate) override {} ash::mojom::SelectToSpeakEventHandlerDelegatePtr delegate) override {}
void ToggleDictationFromSource(
ash::mojom::DictationToggleSource source) override {}
bool was_client_set() const { return was_client_set_; } bool was_client_set() const { return was_client_set_; }
......
...@@ -225,6 +225,13 @@ ...@@ -225,6 +225,13 @@
} }
], ],
"platforms": ["chromeos"] "platforms": ["chromeos"]
},
{
"name": "toggleDictation",
"type": "function",
"description": "Toggles dictation between active and inactive states.",
"parameters": [],
"platforms": ["chromeos"]
} }
], ],
"events": [ "events": [
......
...@@ -1344,6 +1344,7 @@ enum HistogramValue { ...@@ -1344,6 +1344,7 @@ enum HistogramValue {
AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE = 1281, AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE = 1281,
AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER = 1282, AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER = 1282,
AUTOTESTPRIVATE_TAKESCREENSHOT = 1283, AUTOTESTPRIVATE_TAKESCREENSHOT = 1283,
ACCESSIBILITY_PRIVATE_TOGGLEDICTATION = 1284,
// Last entry: Add new entries above, then run: // Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py // python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -208,3 +208,8 @@ chrome.accessibilityPrivate.onSelectToSpeakStateChanged = function(state) {}; ...@@ -208,3 +208,8 @@ chrome.accessibilityPrivate.onSelectToSpeakStateChanged = function(state) {};
* @type {!ChromeEvent} * @type {!ChromeEvent}
*/ */
chrome.accessibilityPrivate.onSelectToSpeakStateChangeRequested; chrome.accessibilityPrivate.onSelectToSpeakStateChangeRequested;
/**
* Called when a Switch Access user activates dictation from the context menu.
*/
chrome.accessibilityPrivate.toggleDictation = function() {};
...@@ -8885,6 +8885,8 @@ Called by update_net_error_codes.py.--> ...@@ -8885,6 +8885,8 @@ Called by update_net_error_codes.py.-->
<enum name="CrosDictationToggleDictationMethod"> <enum name="CrosDictationToggleDictationMethod">
<int value="0" label="Search+D"/> <int value="0" label="Search+D"/>
<int value="1" label="Click onscreen button"/> <int value="1" label="Click onscreen button"/>
<int value="2" label="Select the button in the SwitchAccess context menu"/>
<int value="3" label="ChromeVox gesture"/>
</enum> </enum>
<enum name="CrosDisksArchiveType"> <enum name="CrosDisksArchiveType">
...@@ -16913,6 +16915,7 @@ Called by update_net_error_codes.py.--> ...@@ -16913,6 +16915,7 @@ Called by update_net_error_codes.py.-->
<int value="1281" label="AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE"/> <int value="1281" label="AUTOTESTPRIVATE_BOOTSTRAPMACHINELEARNINGSERVICE"/>
<int value="1282" label="AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER"/> <int value="1282" label="AUTOTESTPRIVATE_RUNCROSTINIUNINSTALLER"/>
<int value="1283" label="AUTOTESTPRIVATE_TAKESCREENSHOT"/> <int value="1283" label="AUTOTESTPRIVATE_TAKESCREENSHOT"/>
<int value="1284" label="ACCESSIBILITY_PRIVATE_TOGGLEDICTATION"/>
</enum> </enum>
<enum name="ExtensionIconState"> <enum name="ExtensionIconState">
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