blob: 87b3d790fb150f1d3985595dd15c072ad6745fc0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview 'settings-google-assistant-subpage' is the settings page
* containing Google Assistant settings.
*/
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import 'chrome://resources/cr_elements/md_select.css.js';
import 'chrome://resources/cr_elements/policy/cr_policy_pref_indicator.js';
import '/shared/settings/controls/controlled_button.js';
import '/shared/settings/controls/settings_toggle_button.js';
import 'chrome://resources/cr_components/settings_prefs/prefs.js';
import 'chrome://resources/cr_components/settings_prefs/pref_util.js';
import '../../settings_shared.css.js';
import {SettingsToggleButtonElement} from '/shared/settings/controls/settings_toggle_button.js';
import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {cast, castExists} from '../assert_extras.js';
import {DeepLinkingMixin} from '../deep_linking_mixin.js';
import {recordSettingChange} from '../metrics_recorder.js';
import {Setting} from '../mojom-webui/setting.mojom-webui.js';
import {routes} from '../os_settings_routes.js';
import {RouteObserverMixin} from '../route_observer_mixin.js';
import {Route} from '../router.js';
import {GoogleAssistantBrowserProxy, GoogleAssistantBrowserProxyImpl} from './google_assistant_browser_proxy.js';
import {getTemplate} from './google_assistant_subpage.html.js';
/**
* The types of Hotword enable status without Dsp support.
*/
export enum DspHotwordState {
DEFAULT_ON = 0,
ALWAYS_ON = 1,
OFF = 2,
}
/**
* Indicates user's activity control consent status.
*
* Note: This should be kept in sync with ConsentStatus in
* chromeos/ash/services/assistant/public/cpp/assistant_prefs.h
*/
export enum ConsentStatus {
// The status is unknown.
UNKNOWN = 0,
// The user accepted activity control access.
ACTIVITY_CONTROL_ACCEPTED = 1,
// The user is not authorized to give consent.
UNAUTHORIZED = 2,
// The user's consent information is not found. This is typically the case
// when consent from the user has never been requested.
NOT_FOUND = 3,
}
const SettingsGoogleAssistantSubpageElementBase =
DeepLinkingMixin(RouteObserverMixin(
PrefsMixin(WebUiListenerMixin(I18nMixin(PolymerElement)))));
class SettingsGoogleAssistantSubpageElement extends
SettingsGoogleAssistantSubpageElementBase {
static get is() {
return 'settings-google-assistant-subpage';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
shouldShowVoiceMatchSettings_: {
type: Boolean,
value: false,
},
hotwordDspAvailable_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('hotwordDspAvailable');
},
},
hotwordDropdownList_: {
type: Array,
value() {
return [
{
name: loadTimeData.getString(
'googleAssistantEnableHotwordWithoutDspRecommended'),
value: DspHotwordState.DEFAULT_ON,
},
{
name: loadTimeData.getString(
'googleAssistantEnableHotwordWithoutDspAlwaysOn'),
value: DspHotwordState.ALWAYS_ON,
},
{
name: loadTimeData.getString(
'googleAssistantEnableHotwordWithoutDspOff'),
value: DspHotwordState.OFF,
},
];
},
},
hotwordEnforced_: {
type: Boolean,
value: false,
},
hotwordEnforcedForChild_: {
type: Boolean,
value: false,
},
dspHotwordState_: Number,
/**
* Used by DeepLinkingMixin to focus this page's deep links.
*/
supportedSettingIds: {
type: Object,
value: () => new Set<Setting>([
Setting.kAssistantOnOff,
Setting.kAssistantRelatedInfo,
Setting.kAssistantOkGoogle,
Setting.kAssistantNotifications,
Setting.kAssistantVoiceInput,
Setting.kTrainAssistantVoiceModel,
]),
},
};
}
static get observers() {
return [
'onPrefsChanged_(' +
'prefs.settings.voice_interaction.hotword.enabled.value, ' +
'prefs.settings.voice_interaction.hotword.always_on.value, ' +
'prefs.settings.voice_interaction.activity_control.consent_status' +
'.value, ' +
'prefs.settings.assistant.disabled_by_policy.value)',
];
}
private browserProxy_: GoogleAssistantBrowserProxy;
private dspHotwordState_: DspHotwordState;
private hotwordDspAvailable_: boolean;
private hotwordEnforced_: boolean;
private hotwordEnforcedForChild_: boolean;
private shouldShowVoiceMatchSettings_: boolean;
constructor() {
super();
this.browserProxy_ = GoogleAssistantBrowserProxyImpl.getInstance();
}
override ready() {
super.ready();
this.addWebUiListener('hotwordDeviceUpdated', (hasHotword: boolean) => {
this.hotwordDspAvailable_ = hasHotword;
});
chrome.send('initializeGoogleAssistantPage');
}
override currentRouteChanged(route: Route, _oldRoute?: Route) {
// Does not apply to this page.
if (route !== routes.GOOGLE_ASSISTANT) {
return;
}
this.attemptDeepLink();
}
private getAssistantOnOffLabel_(toggleValue: boolean): string {
return this.i18n(
toggleValue ? 'searchGoogleAssistantOn' : 'searchGoogleAssistantOff');
}
private onGoogleAssistantSettingsTapped_() {
this.browserProxy_.showGoogleAssistantSettings();
recordSettingChange();
}
private onRetrainVoiceModelTapped_() {
this.browserProxy_.retrainAssistantVoiceModel();
recordSettingChange();
}
private onEnableHotwordChange_(event: Event) {
const target = cast(event.target, SettingsToggleButtonElement);
if (target.checked) {
this.browserProxy_.syncVoiceModelStatus();
}
}
private onDspHotwordStateChange_() {
const dspHotwordStateEl =
castExists(this.shadowRoot!.querySelector<HTMLSelectElement>(
'#dsp-hotword-state'));
switch (Number(dspHotwordStateEl.value)) {
case DspHotwordState.DEFAULT_ON:
this.setPrefValue('settings.voice_interaction.hotword.enabled', true);
this.setPrefValue(
'settings.voice_interaction.hotword.always_on', false);
this.browserProxy_.syncVoiceModelStatus();
break;
case DspHotwordState.ALWAYS_ON:
this.setPrefValue('settings.voice_interaction.hotword.enabled', true);
this.setPrefValue('settings.voice_interaction.hotword.always_on', true);
this.browserProxy_.syncVoiceModelStatus();
break;
case DspHotwordState.OFF:
this.setPrefValue('settings.voice_interaction.hotword.enabled', false);
this.setPrefValue(
'settings.voice_interaction.hotword.always_on', false);
break;
default:
console.error('Invalid Dsp hotword settings state');
}
}
private isDspHotwordStateMatch_(state: number): boolean {
return state === this.dspHotwordState_;
}
private onPrefsChanged_() {
if (this.getPref('settings.assistant.disabled_by_policy').value) {
this.setPrefValue('settings.voice_interaction.enabled', false);
return;
}
this.refreshDspHotwordState_();
this.shouldShowVoiceMatchSettings_ =
!loadTimeData.getBoolean('voiceMatchDisabled') &&
!!this.getPref('settings.voice_interaction.hotword.enabled').value;
const hotwordEnabled =
this.getPref('settings.voice_interaction.hotword.enabled');
this.hotwordEnforced_ = hotwordEnabled.enforcement ===
chrome.settingsPrivate.Enforcement.ENFORCED;
this.hotwordEnforcedForChild_ = this.hotwordEnforced_ &&
hotwordEnabled.controlledBy ===
chrome.settingsPrivate.ControlledBy.CHILD_RESTRICTION;
}
private refreshDspHotwordState_() {
if (!this.getPref('settings.voice_interaction.hotword.enabled').value) {
this.dspHotwordState_ = DspHotwordState.OFF;
} else if (this.getPref('settings.voice_interaction.hotword.always_on')
.value) {
this.dspHotwordState_ = DspHotwordState.ALWAYS_ON;
} else {
this.dspHotwordState_ = DspHotwordState.DEFAULT_ON;
}
const dspHotwordStateEl =
this.shadowRoot!.querySelector<HTMLSelectElement>('#dsp-hotword-state');
if (dspHotwordStateEl) {
dspHotwordStateEl.value = String(this.dspHotwordState_);
}
}
}
declare global {
interface HTMLElementTagNameMap {
'settings-google-assistant-subpage': SettingsGoogleAssistantSubpageElement;
}
}
customElements.define(
SettingsGoogleAssistantSubpageElement.is,
SettingsGoogleAssistantSubpageElement);