Commit a6903f53 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

[Switch Access] Validate settings

Previously, there was a bug in Switch Access where the user could set
two commands to the same key, leading to ambiguity in expected behavior.

This change adds validation, and un-sets any commands previously set to
a key.

Bug: 1056310
Change-Id: I61569cdcdca13a38923db1d34b0577fc02ec1a08
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2075054
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#745251}
parent b09ad1be
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
<template is="dom-if" route-path="/manageAccessibility/switchAccess"> <template is="dom-if" route-path="/manageAccessibility/switchAccess">
<settings-subpage associated-control="[[$$('#subpage-trigger')]]" <settings-subpage associated-control="[[$$('#subpage-trigger')]]"
page-title="$i18n{manageSwitchAccessSettings}"> page-title="$i18n{manageSwitchAccessSettings}">
<settings-switch-access-subpage prefs="{{prefs.settings.a11y}}"> <settings-switch-access-subpage prefs="{{prefs}}">
</settings-switch-access-subpage> </settings-switch-access-subpage>
</settings-subpage> </settings-subpage>
</template> </template>
......
...@@ -23,9 +23,8 @@ ...@@ -23,9 +23,8 @@
$i18n{assignSelectSwitchLabel} $i18n{assignSelectSwitchLabel}
</div> </div>
<settings-dropdown-menu label="$i18n{assignSelectSwitchLabel}" <settings-dropdown-menu label="$i18n{assignSelectSwitchLabel}"
pref="{{prefs.switch_access.select.setting}}" pref="{{prefs.settings.a11y.switch_access.select.setting}}"
menu-options="[[switchAssignOptions_]]" menu-options="[[switchAssignOptions_]]">
on-settings-control-change="onSelectAssigned_">
</settings-dropdown-menu> </settings-dropdown-menu>
</div> </div>
<div class="settings-box continuation list-item"> <div class="settings-box continuation list-item">
...@@ -33,9 +32,8 @@ ...@@ -33,9 +32,8 @@
$i18n{assignNextSwitchLabel} $i18n{assignNextSwitchLabel}
</div> </div>
<settings-dropdown-menu label="$i18n{assignNextSwitchLabel}" <settings-dropdown-menu label="$i18n{assignNextSwitchLabel}"
pref="{{prefs.switch_access.next.setting}}" pref="{{prefs.settings.a11y.switch_access.next.setting}}"
menu-options="[[switchAssignOptions_]]" menu-options="[[switchAssignOptions_]]">
on-settings-control-change="onNextAssigned_">
</settings-dropdown-menu> </settings-dropdown-menu>
</div> </div>
<div class="settings-box continuation list-item"> <div class="settings-box continuation list-item">
...@@ -43,26 +41,25 @@ ...@@ -43,26 +41,25 @@
$i18n{assignPreviousSwitchLabel} $i18n{assignPreviousSwitchLabel}
</div> </div>
<settings-dropdown-menu label="$i18n{assignPreviousSwitchLabel}" <settings-dropdown-menu label="$i18n{assignPreviousSwitchLabel}"
pref="{{prefs.switch_access.previous.setting}}" pref="{{prefs.settings.a11y.switch_access.previous.setting}}"
menu-options="[[switchAssignOptions_]]" menu-options="[[switchAssignOptions_]]">
on-settings-control-change="onPreviousAssigned_">
</settings-dropdown-menu> </settings-dropdown-menu>
</div> </div>
</div> </div>
<h2>$i18n{switchAccessAutoScanHeading}</h2> <h2>$i18n{switchAccessAutoScanHeading}</h2>
<div class="list-frame"> <div class="list-frame">
<settings-toggle-button class="continuation list-item" <settings-toggle-button class="continuation list-item"
pref="{{prefs.switch_access.auto_scan.enabled}}" pref="{{prefs.settings.a11y.switch_access.auto_scan.enabled}}"
label="$i18n{switchAccessAutoScanLabel}"> label="$i18n{switchAccessAutoScanLabel}">
</settings-toggle-button> </settings-toggle-button>
<div class="settings-box continuation list-item" <div class="settings-box continuation list-item"
hidden$="[[!prefs.switch_access.auto_scan.enabled.value]]"> hidden$="[[!prefs.settings.a11y.switch_access.auto_scan.enabled.value]]">
<div class="start sub-item settings-box-text" id="scanSpeed" <div class="start sub-item settings-box-text" id="scanSpeed"
aria-hidden="true"> aria-hidden="true">
$i18n{switchAccessAutoScanSpeedLabel} $i18n{switchAccessAutoScanSpeedLabel}
</div> </div>
<settings-slider id="scanSpeedSlider" <settings-slider id="scanSpeedSlider"
pref="{{prefs.switch_access.auto_scan.speed_ms}}" pref="{{prefs.settings.a11y.switch_access.auto_scan.speed_ms}}"
ticks="[[autoScanSpeedRangeMs_]]" ticks="[[autoScanSpeedRangeMs_]]"
min="[[minScanSpeedMs_]]" min="[[minScanSpeedMs_]]"
max="[[maxScanSpeedMs_]]" max="[[maxScanSpeedMs_]]"
...@@ -73,13 +70,13 @@ ...@@ -73,13 +70,13 @@
</div> </div>
<div class="settings-box continuation list-item" <div class="settings-box continuation list-item"
hidden$="[[!showKeyboardScanSettings_( hidden$="[[!showKeyboardScanSettings_(
prefs.switch_access.auto_scan.enabled.value)]]"> prefs.settings.a11y.switch_access.auto_scan.enabled.value)]]">
<div class="start sub-item settings-box-text" id="keyboardScanSpeed" <div class="start sub-item settings-box-text" id="keyboardScanSpeed"
aria-hidden="true"> aria-hidden="true">
$i18n{switchAccessAutoScanKeyboardSpeedLabel} $i18n{switchAccessAutoScanKeyboardSpeedLabel}
</div> </div>
<settings-slider id="keyboardScanSpeedSlider" <settings-slider id="keyboardScanSpeedSlider"
pref="{{prefs.switch_access.auto_scan.keyboard.speed_ms}}" pref="{{prefs.settings.a11y.switch_access.auto_scan.keyboard.speed_ms}}"
ticks="[[autoScanSpeedRangeMs_]]" ticks="[[autoScanSpeedRangeMs_]]"
min="[[minScanSpeedMs_]]" min="[[minScanSpeedMs_]]"
max="[[maxScanSpeedMs_]]" max="[[maxScanSpeedMs_]]"
......
...@@ -20,6 +20,31 @@ const SwitchAccessAssignmentValue = { ...@@ -20,6 +20,31 @@ const SwitchAccessAssignmentValue = {
ENTER: 2, ENTER: 2,
}; };
/**
* Available commands.
* @const
*/
const SWITCH_ACCESS_COMMANDS = ['next', 'previous', 'select'];
/**
* The portion of the setting name common to all Switch Access preferences.
* @const
*/
const PREFIX = 'settings.a11y.switch_access.';
/**
* The ending of the setting name for all key code preferences.
* @const
*/
const KEY_CODE_SUFFIX = '.key_codes';
/**
* The ending of the setting name for all preferences referring to
* Switch Access command settings.
* @const
*/
const COMMAND_SUFFIX = '.setting';
/** @type {!Array<number>} */ /** @type {!Array<number>} */
const AUTO_SCAN_SPEED_RANGE_MS = [ const AUTO_SCAN_SPEED_RANGE_MS = [
500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
...@@ -27,6 +52,20 @@ const AUTO_SCAN_SPEED_RANGE_MS = [ ...@@ -27,6 +52,20 @@ const AUTO_SCAN_SPEED_RANGE_MS = [
2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000
]; ];
/**
* This function extracts the segment of a preference key after the fixed prefix
* and returns it. In cases where the preference is Switch Access command
* setting preference, it corresponds to the command name.
*
* @param {!chrome.settingsPrivate.PrefObject} pref
* @return {string}
*/
function getCommandNameFromCommandPref(pref) {
const nameStartIndex = PREFIX.length;
const nameEndIndex = pref.key.indexOf('.', nameStartIndex);
return pref.key.substring(nameStartIndex, nameEndIndex);
}
/** /**
* @param {!Array<number>} ticksInMs * @param {!Array<number>} ticksInMs
* @return {!Array<!cr_slider.SliderTick>} * @return {!Array<!cr_slider.SliderTick>}
...@@ -118,12 +157,27 @@ Polymer({ ...@@ -118,12 +157,27 @@ Polymer({
}, },
}, },
/** @override */
created() {
chrome.settingsPrivate.onPrefsChanged.addListener((prefs) => {
for (const pref of prefs) {
if (!pref.key.includes(PREFIX) || !pref.key.includes(COMMAND_SUFFIX)) {
continue;
}
const commandName = getCommandNameFromCommandPref(pref);
if (SWITCH_ACCESS_COMMANDS.includes(commandName)) {
this.onSwitchAssigned_(pref);
}
}
});
},
/** /**
* @return {string} * @return {string}
* @private * @private
*/ */
currentSpeed_() { currentSpeed_() {
const speed = this.get('prefs.switch_access.auto_scan.speed_ms.value'); const speed = this.getPref(PREFIX + 'auto_scan.speed_ms').value;
if (typeof speed != 'number') { if (typeof speed != 'number') {
return ''; return '';
} }
...@@ -139,43 +193,48 @@ Polymer({ ...@@ -139,43 +193,48 @@ Polymer({
const improvedTextInputEnabled = loadTimeData.getBoolean( const improvedTextInputEnabled = loadTimeData.getBoolean(
'showExperimentalAccessibilitySwitchAccessImprovedTextInput'); 'showExperimentalAccessibilitySwitchAccessImprovedTextInput');
const autoScanEnabled = /** @type {boolean} */ const autoScanEnabled = /** @type {boolean} */
(this.getPref('switch_access.auto_scan.enabled').value); (this.getPref(PREFIX + 'auto_scan.enabled').value);
return improvedTextInputEnabled && autoScanEnabled; return improvedTextInputEnabled && autoScanEnabled;
}, },
/** /** @param {!chrome.settingsPrivate.PrefObject} newPref */
* @param {string} command onSwitchAssigned_(newPref) {
*/ const command = getCommandNameFromCommandPref(newPref);
onSwitchAssigned_(command) {
const pref = 'prefs.switch_access.' + command; if (newPref.value !== SwitchAccessAssignmentValue.NONE) {
const keyCodeSuffix = '.key_codes.value'; // When setting to a value, enforce that no other command can have that
const settingSuffix = '.setting.value'; // value.
for (const val of SWITCH_ACCESS_COMMANDS) {
if (val === command) {
continue;
}
if (this.getPref(PREFIX + val + COMMAND_SUFFIX).value ===
newPref.value) {
chrome.settingsPrivate.setPref(
PREFIX + val + COMMAND_SUFFIX, SwitchAccessAssignmentValue.NONE);
}
}
}
switch (this.get(pref + settingSuffix)) { // Because of complexities with mapping a ListPref to a settings-dropdown,
// we instead store two distinct preferences (one for the dropdown selection
// and one with the key codes that Switch Access intercepts). The following
// code sets the key code preference based on the dropdown preference.
switch (newPref.value) {
case SwitchAccessAssignmentValue.NONE: case SwitchAccessAssignmentValue.NONE:
this.set(pref + keyCodeSuffix, []); chrome.settingsPrivate.setPref(PREFIX + command + KEY_CODE_SUFFIX, []);
break; break;
case SwitchAccessAssignmentValue.SPACE: case SwitchAccessAssignmentValue.SPACE:
this.set(pref + keyCodeSuffix, [32]); chrome.settingsPrivate.setPref(
PREFIX + command + KEY_CODE_SUFFIX, [32]);
break; break;
case SwitchAccessAssignmentValue.ENTER: case SwitchAccessAssignmentValue.ENTER:
this.set(pref + keyCodeSuffix, [13]); chrome.settingsPrivate.setPref(
PREFIX + command + KEY_CODE_SUFFIX, [13]);
break; break;
} }
}, },
onNextAssigned_() {
this.onSwitchAssigned_('next');
},
onPreviousAssigned_() {
this.onSwitchAssigned_('previous');
},
onSelectAssigned_() {
this.onSwitchAssigned_('select');
},
/** /**
* @param {number} scanSpeedValueMs * @param {number} scanSpeedValueMs
* @return {string} a string representing the scan speed in seconds. * @return {string} a string representing the scan speed in seconds.
......
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