Commit a81383e6 authored by Yue Li's avatar Yue Li Committed by Commit Bot

Add Assistant Voice Match screen

Bug: b/116166191
Test: Manual Test
Change-Id: Ia9270ce57d2fd4c2b1f563612c892877ee08e251
Reviewed-on: https://chromium-review.googlesource.com/c/1310913
Commit-Queue: Yue Li <updowndota@chromium.org>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604752}
parent f9e2773c
......@@ -3181,6 +3181,39 @@
<message name="IDS_ASSISTANT_ACTIVITY_CONTROL_POPUP_LINK" desc="Link text for activity control details popup.">
Learn more
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_TITLE" desc="Title for assistant voice match screen.">
Access your Assistant with Voice Match
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_MESSAGE" desc="Message for assistant voice match screen.">
Your Assisatant uses these recordings to create your voice model, which is stored in your device. Delete or retrain the model in assistant settings. View or delete voice commands in your Google activity controls.
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_RECORDING" desc="Title for recording in assistant voice match screen.">
Teach Assistant to recognize your voice
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_COMPLETED" desc="Title for completed assistant voice match screen.">
Ok Google is all set
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_FOOTER" desc="Footer message for assistant voice match screen.">
Recording "Ok Google" 3 times creates your voice model, which is stored on your device. Delete or retrain the model in assistant settings. View or delete voice commands in your Google activity controls.
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION0" desc="Instruction message for assistant voice match recording.">
Say "Ok Google"
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION1" desc="Instruction message for assistant voice match recording.">
Say "Ok Google" again
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION2" desc="Instruction message for assistant voice match recording.">
Now say "Hey Google"
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION3" desc="Instruction message for assistant voice match recording.">
Say "Hey Google" again
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_COMPLETE" desc="Complete message for assistant voice match recording.">
Complete
</message>
<message name="IDS_ASSISTANT_VOICE_MATCH_UPLOADING" desc="Uploading message for assistant voice match recording.">
Uploading...
</message>
<!-- Print Job Notification -->
<message name="IDS_PRINT_JOB_NOTIFICATION_DISPLAY_SOURCE" desc="The context title of printing notification.">
......
......@@ -11,11 +11,12 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/html/util.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<include src="../login/hd-iron-icon.html">
<include src="../login/oobe_buttons.html">
......
......@@ -44,6 +44,14 @@ cr.define('login.AssistantOptInFlowScreen', function() {
$('assistant-optin-flow-card').showNextScreen();
},
/**
* Called when the Voice match state is updated.
* @param {string} state the voice match state.
*/
onVoiceMatchUpdate: function(state) {
$('assistant-optin-flow-card').onVoiceMatchUpdate(state);
},
closeDialog: function() {
chrome.send('dialogClose');
},
......
......@@ -7,7 +7,9 @@
<include src="assistant_ready.html">
<include src="assistant_third_party.html">
<include src="assistant_value_prop.html">
<include src="assistant_voice_match.html">
<include src="setting_zippy.html">
<include src="voice_match_entry.html">
<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
......@@ -21,10 +23,10 @@
</assistant-loading>
<assistant-value-prop id="value-prop">
</assistant-value-prop>
<assistant-confirm-reject id="confirm-reject" hidden>
</assistant-confirm-reject>
<assistant-third-party id="third-party" hidden>
</assistant-third-party>
<assistant-voice-match id="voice-match" hidden>
</assistant-voice-match>
<assistant-get-more id="get-more" hidden>
</assistant-get-more>
<assistant-ready id="ready" hidden>
......
......@@ -4,11 +4,13 @@
// <include src="utils.js">
// <include src="setting_zippy.js">
// <include src="voice_match_entry.js">
// <include src="assistant_get_more.js">
// <include src="assistant_loading.js">
// <include src="assistant_ready.js">
// <include src="assistant_third_party.js">
// <include src="assistant_value_prop.js">
// <include src="assistant_voice_match.js">
/**
* @fileoverview Polymer element for displaying material design assistant
......@@ -78,6 +80,9 @@ Polymer({
this.showScreen(this.$['third-party']);
break;
case this.$['third-party']:
this.showScreen(this.$['voice-match']);
break;
case this.$['voice-match']:
this.showScreen(this.$['get-more']);
break;
case this.$['get-more']:
......@@ -89,6 +94,29 @@ Polymer({
}
},
/**
* Called when the Voice match state is updated.
* @param {string} state the voice match state.
*/
onVoiceMatchUpdate: function(state) {
if (!this.currentScreen == this.$['voice-match']) {
return;
}
switch (state) {
case 'listen':
this.$['voice-match'].listenForHotword();
break;
case 'process':
this.$['voice-match'].processingHotword();
break;
case 'done':
this.$['voice-match'].voiceMatchDone();
break;
default:
break;
}
},
/**
* Show the given screen.
*
......
/* Copyright 2018 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. */
.content {
padding-right: 8px;
}
#title-recording,
#title-completed {
padding-bottom: 36px;
}
#footer-text {
color: #757575;
padding-top: 48px;
}
#voice-match-img {
padding: 48px 0 0 48px;
}
#done-button-text {
padding: 0 8px 0 8px;
}
.intro #recording-container,
.recording #intro-container,
.completed #intro-container {
position: absolute;
visibility: hidden;
}
.recording #title-completed,
.completed #title-recording {
display: none;
}
.intro #skip-button,
.intro #next-button,
.recording #later-button,
.completed #done-button {
display: block;
}
oobe-text-button {
display: none;
}
<!-- Copyright 2018 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. -->
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<dom-module id="assistant-voice-match">
<template>
<link rel="stylesheet" href="../login/oobe_flex_layout.css">
<link rel="stylesheet" href="assistant_shared_styles.css">
<link rel="stylesheet" href="assistant_voice_match.css">
<oobe-dialog id="voice-match-dialog" role="dialog" has-buttons hide-shadow
no-footer-padding no-header class="intro">
<div slot="footer">
<div class="container">
<img id="logo" src="assistant_logo.png">
<div id="intro-container">
<div class="title" i18n-content="assistantVoiceMatchTitle"></div>
<div class="content" i18n-content="assistantVoiceMatchMessage">
</div>
<img id="voice-match-img" src="assistant_voice_match.png">
</div>
<div id="recording-container">
<div class="title" id="title-recording"
i18n-content="assistantVoiceMatchRecording"></div>
<div class="title" id="title-completed"
i18n-content="assistantVoiceMatchCompleted"></div>
<voice-match-entry id="voice-entry-0">
<div class="entry-content"
i18n-content="assistantVoiceMatchInstruction0"></div>
</voice-match-entry>
<voice-match-entry id="voice-entry-1">
<div class="entry-content"
i18n-content="assistantVoiceMatchInstruction1"></div>
</voice-match-entry>
<voice-match-entry id="voice-entry-2">
<div class="entry-content"
i18n-content="assistantVoiceMatchInstruction2"></div>
</voice-match-entry>
<voice-match-entry id="voice-entry-3">
<div class="entry-content"
i18n-content="assistantVoiceMatchInstruction3"></div>
</voice-match-entry>
<voice-match-entry id="voice-uploading">
<div class="entry-content"
i18n-content="assistantVoiceMatchUploading"></div>
</voice-match-entry>
<div class="content" id="footer-text"
i18n-content="assistantVoiceMatchFooter"></div>
</div>
</div>
</div>
<div slot="bottom-buttons" class="flex layout horizontal">
<div class="flex"></div>
<oobe-text-button id="skip-button" on-tap="onSkipTap_"
disabled="[[buttonsDisabled]]">
<div id="skip-button-text">No thanks</div>
</oobe-text-button>
<oobe-text-button id="later-button" on-tap="onSkipTap_"
disabled="[[buttonsDisabled]]">
<div id="skip-button-text">Do it later</div>
</oobe-text-button>
<oobe-text-button id="next-button" inverse on-tap="onNextTap_"
disabled="[[buttonsDisabled]]">
<div id="next-button-text">I agree</div>
</oobe-text-button>
<oobe-text-button id="done-button" inverse on-tap="onDoneTap_"
disabled="[[buttonsDisabled]]">
<div id="done-button-text">Save</div>
</oobe-text-button>
</div>
</oobe-dialog>
</template>
</dom-module>
// Copyright 2018 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.
/**
* @fileoverview Polymer element for displaying material design assistant
* voice match screen.
*
*/
Polymer({
is: 'assistant-voice-match',
behaviors: [OobeDialogHostBehavior],
/**
* Current recording index.
* @type {number}
* @private
*/
currentIndex_: 0,
/**
* On-tap event handler for skip button.
*
* @private
*/
onSkipTap_: function() {
chrome.send(
'login.AssistantOptInFlowScreen.VoiceMatchScreen.userActed',
['skip-pressed']);
},
/**
* On-tap event handler for next button.
*
* @private
*/
onNextTap_: function() {
this.removeClass_('intro');
this.addClass_('recording');
chrome.send(
'login.AssistantOptInFlowScreen.VoiceMatchScreen.userActed',
['record-pressed']);
},
/**
* On-tap event handler for next button.
*
* @private
*/
onDoneTap_: function() {
chrome.send(
'login.AssistantOptInFlowScreen.VoiceMatchScreen.userActed',
['next-pressed']);
},
/**
* Add class to the list of classes of root elements.
* @param {string} className class to add
*
* @private
*/
addClass_: function(className) {
this.$['voice-match-dialog'].classList.add(className);
},
/**
* Remove class to the list of classes of root elements.
* @param {string} className class to remove
*
* @private
*/
removeClass_: function(className) {
this.$['voice-match-dialog'].classList.remove(className);
},
/**
* Called when the server is ready to listening for hotword.
*/
listenForHotword: function() {
var currentEntry = this.$['voice-entry-' + this.currentIndex_];
currentEntry.setAttribute('active', true);
},
/**
* Called when the server has detected and processing hotword.
*/
processingHotword: function() {
var currentEntry = this.$['voice-entry-' + this.currentIndex_];
currentEntry.removeAttribute('active');
currentEntry.setAttribute('completed', true);
this.currentIndex_++;
if (this.currentIndex_ == 4) {
this.$['voice-uploading'].setAttribute('active', true);
}
},
voiceMatchDone: function() {
this.$['voice-uploading'].removeAttribute('active');
this.$['voice-uploading'].setAttribute('completed', true);
this.removeClass_('recording');
this.addClass_('completed');
},
/**
* Signal from host to show the screen.
*/
onShow: function() {
this.$['next-button'].focus();
},
});
/* Copyright 2018 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. */
#container {
align-items: center;
height: 56px;
}
.icon {
min-width: 48px;
}
.dot {
background-color: var(--google-grey-500);
border-radius: 50%;
height: 8px;
margin-left: 8px;
width: 8px;
}
#active-icon {
height: 24px;
width: 24px;
}
#completed-icon {
color: var(--google-blue-600);
}
#default-icon[active],
#default-icon[completed],
#active-icon,
#completed-icon {
display: none;
}
#active-icon[active],
#completed-icon[completed] {
display: block;
}
#entry-text {
font-size: 15px;
}
#active-text {
color: black;
}
#active-text,
#completed-text {
display: none;
}
#active-text[active],
#completed-text[completed] {
display: block;
}
<!-- Copyright 2018 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. -->
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<dom-module id="voice-match-entry">
<template>
<link rel="stylesheet" href="../login/oobe_flex_layout.css">
<link rel="stylesheet" href="assistant_shared_styles.css">
<link rel="stylesheet" href="voice_match_entry.css">
<div class="flex layout horizontal center" id="container">
<div class="icon">
<div id="default-icon" class="dot" active$="[[active]]"
completed$="[[completed]]"></div>
<paper-spinner-lite id="active-icon" active$="[[active]]">
</paper-spinner-lite>
<iron-icon id="completed-icon" icon="cr:check"
completed$="[[completed]]"></iron-icon>
</div>
<div id="entry-text" class="content">
<div id="active-text" active$="[[active]]">
<content select=".entry-content"></content>
</div>
<div id="completed-text" completed$="[[completed]]"
i18n-content=assistantVoiceMatchComplete></div>
</div>
</div>
</template>
</dom-module>
// Copyright 2018 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.
Polymer({
is: 'voice-match-entry',
properties: {
active: {
type: Boolean,
value: false,
},
completed: {
type: Boolean,
value: false,
},
},
});
......@@ -9,7 +9,10 @@
login.createScreen(
'AssistantOptInFlowScreen', 'assistant-optin-flow', function() {
return {
EXTERNAL_API: ['reloadContent', 'addSettingZippy', 'showNextScreen'],
EXTERNAL_API: [
'reloadContent', 'addSettingZippy', 'showNextScreen',
'onVoiceMatchUpdate'
],
/** @Override */
onBeforeShow: function(data) {
......@@ -40,5 +43,13 @@ login.createScreen(
showNextScreen: function() {
$('assistant-optin-flow-card').showNextScreen();
},
/**
* Called when the Voice match state is updated.
* @param {string} state the voice match state.
*/
onVoiceMatchUpdate: function(state) {
$('assistant-optin-flow-card').onVoiceMatchUpdate(state);
},
};
});
......@@ -1722,6 +1722,7 @@ jumbo_split_static_library("ui") {
"//chromeos/components/proximity_auth/webui",
"//chromeos/components/tether",
"//chromeos/resources:resources_grit",
"//chromeos/services/assistant/public:feature_flags",
"//chromeos/services/assistant/public/mojom",
"//chromeos/services/assistant/public/proto:proto",
"//chromeos/services/multidevice_setup/public/cpp:cpp",
......
......@@ -12,6 +12,7 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/services/assistant/public/features.h"
#include "chromeos/services/assistant/public/mojom/constants.mojom.h"
#include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
#include "components/arc/arc_prefs.h"
......@@ -26,13 +27,14 @@ namespace {
constexpr char kJsScreenPath[] = "login.AssistantOptInFlowScreen";
constexpr char kSkipPressed[] = "skip-pressed";
constexpr char kNextPressed[] = "next-pressed";
constexpr char kRecordPressed[] = "record-pressed";
constexpr char kFlowFinished[] = "flow-finished";
constexpr char kReloadRequested[] = "reload-requested";
} // namespace
AssistantOptInFlowScreenHandler::AssistantOptInFlowScreenHandler()
: BaseScreenHandler(kScreenId), weak_factory_(this) {
: BaseScreenHandler(kScreenId), client_binding_(this), weak_factory_(this) {
set_call_js_prefix(kJsScreenPath);
}
......@@ -58,6 +60,25 @@ void AssistantOptInFlowScreenHandler::DeclareLocalizedValues(
IDS_VOICE_INTERACTION_VALUE_PROP_SKIP_BUTTON);
builder->Add("assistantOptinRetryButton",
IDS_VOICE_INTERACTION_VALUE_PROP_RETRY_BUTTON);
builder->Add("assistantVoiceMatchTitle", IDS_ASSISTANT_VOICE_MATCH_TITLE);
builder->Add("assistantVoiceMatchMessage", IDS_ASSISTANT_VOICE_MATCH_MESSAGE);
builder->Add("assistantVoiceMatchRecording",
IDS_ASSISTANT_VOICE_MATCH_RECORDING);
builder->Add("assistantVoiceMatchCompleted",
IDS_ASSISTANT_VOICE_MATCH_COMPLETED);
builder->Add("assistantVoiceMatchFooter", IDS_ASSISTANT_VOICE_MATCH_FOOTER);
builder->Add("assistantVoiceMatchInstruction0",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION0);
builder->Add("assistantVoiceMatchInstruction1",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION1);
builder->Add("assistantVoiceMatchInstruction2",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION2);
builder->Add("assistantVoiceMatchInstruction3",
IDS_ASSISTANT_VOICE_MATCH_INSTRUCTION3);
builder->Add("assistantVoiceMatchComplete",
IDS_ASSISTANT_VOICE_MATCH_COMPLETE);
builder->Add("assistantVoiceMatchUploading",
IDS_ASSISTANT_VOICE_MATCH_UPLOADING);
builder->Add("assistantOptinOKButton", IDS_OOBE_OK_BUTTON_TEXT);
builder->Add("assistantReadyTitle", IDS_ASSISTANT_READY_SCREEN_TITLE);
builder->Add("assistantReadyMessage", IDS_ASSISTANT_READY_SCREEN_MESSAGE);
......@@ -73,6 +94,9 @@ void AssistantOptInFlowScreenHandler::RegisterMessages() {
AddPrefixedCallback(
"ThirdPartyScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleThirdPartyScreenUserAction);
AddPrefixedCallback(
"VoiceMatchScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenUserAction);
AddPrefixedCallback(
"GetMoreScreen.userActed",
&AssistantOptInFlowScreenHandler::HandleGetMoreScreenUserAction);
......@@ -133,6 +157,23 @@ void AssistantOptInFlowScreenHandler::Initialize() {
show_on_init_ = false;
}
void AssistantOptInFlowScreenHandler::OnListeningHotword() {
CallJS("onVoiceMatchUpdate", base::Value("listen"));
}
void AssistantOptInFlowScreenHandler::OnProcessingHotword() {
CallJS("onVoiceMatchUpdate", base::Value("process"));
}
void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentDone() {
CallJS("onVoiceMatchUpdate", base::Value("done"));
}
void AssistantOptInFlowScreenHandler::OnSpeakerIdEnrollmentFailure() {
// TODO(updowndota): Show an error message to user, and add an UMA metric.
LOG(ERROR) << "Speaker ID enrollmend failure.";
}
void AssistantOptInFlowScreenHandler::SetupAssistantConnection() {
// Make sure enable Assistant service since we need it during the flow.
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
......@@ -201,6 +242,7 @@ void AssistantOptInFlowScreenHandler::BindAssistantSettingsManager() {
ProfileManager::GetActiveUserProfile());
connector->BindInterface(assistant::mojom::kServiceName,
mojo::MakeRequest(&settings_manager_));
client_binding_.Bind(mojo::MakeRequest(&client_ptr_));
SendGetSettingsRequest();
}
......@@ -353,6 +395,24 @@ void AssistantOptInFlowScreenHandler::HandleThirdPartyScreenUserAction(
if (action == kNextPressed) {
RecordAssistantOptInStatus(THIRD_PARTY_CONTINUED);
ShowNextScreen();
if (!base::FeatureList::IsEnabled(
assistant::features::kAssistantVoiceMatch)) {
// Skip the voice match enrollment if feature is disabled.
ShowNextScreen();
}
}
}
void AssistantOptInFlowScreenHandler::HandleVoiceMatchScreenUserAction(
const std::string& action) {
if (!base::FeatureList::IsEnabled(
assistant::features::kAssistantVoiceMatch)) {
return;
}
if (action == kNextPressed || action == kSkipPressed) {
ShowNextScreen();
} else if (action == kRecordPressed) {
settings_manager_->StartSpeakerIdEnrollment(true, std::move(client_ptr_));
}
}
......
......@@ -13,6 +13,7 @@
#include "chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_view.h"
#include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
#include "chromeos/services/assistant/public/mojom/settings.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
namespace chromeos {
......@@ -20,7 +21,8 @@ namespace chromeos {
class AssistantOptInFlowScreenHandler
: public BaseScreenHandler,
public AssistantOptInFlowScreenView,
public arc::VoiceInteractionControllerClient::Observer {
public arc::VoiceInteractionControllerClient::Observer,
assistant::mojom::SpeakerIdEnrollmentClient {
public:
AssistantOptInFlowScreenHandler();
~AssistantOptInFlowScreenHandler() override;
......@@ -36,6 +38,12 @@ class AssistantOptInFlowScreenHandler
void Show() override;
void Hide() override;
// assistant::mojom::SpeakerIdEnrollmentClient:
void OnListeningHotword() override;
void OnProcessingHotword() override;
void OnSpeakerIdEnrollmentDone() override;
void OnSpeakerIdEnrollmentFailure() override;
// Setup Assistant settings manager connection.
void SetupAssistantConnection();
......@@ -70,11 +78,13 @@ class AssistantOptInFlowScreenHandler
// Handler for JS WebUI message.
void HandleValuePropScreenUserAction(const std::string& action);
void HandleThirdPartyScreenUserAction(const std::string& action);
void HandleVoiceMatchScreenUserAction(const std::string& action);
void HandleGetMoreScreenUserAction(const bool screen_context,
const bool email_opted_in);
void HandleReadyScreenUserAction(const std::string& action);
void HandleValuePropScreenShown();
void HandleThirdPartyScreenShown();
void HandleVoiceMatchScreenShown();
void HandleGetMoreScreenShown();
void HandleReadyScreenShown();
void HandleLoadingTimeout();
......@@ -108,6 +118,8 @@ class AssistantOptInFlowScreenHandler
// Counter for the number of loading timeout happens.
int loading_timeout_counter_ = 0;
mojo::Binding<assistant::mojom::SpeakerIdEnrollmentClient> client_binding_;
assistant::mojom::SpeakerIdEnrollmentClientPtr client_ptr_;
assistant::mojom::AssistantSettingsManagerPtr settings_manager_;
base::WeakPtrFactory<AssistantOptInFlowScreenHandler> weak_factory_;
......
# Copyright 2018 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.
source_set("feature_flags") {
sources = [
"features.cc",
"features.h",
]
deps = [
"//base",
]
}
// Copyright 2018 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 "chromeos/services/assistant/public/features.h"
namespace chromeos {
namespace assistant {
namespace features {
// Enables Assistant voice match enrollment.
const base::Feature kAssistantVoiceMatch{"AssistantVoiceMatch",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace assistant
} // namespace chromeos
// Copyright 2018 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 CHROMEOS_SERVICES_ASSISTANT_PUBLIC_FEATURES_H_
#define CHROMEOS_SERVICES_ASSISTANT_PUBLIC_FEATURES_H_
#include "base/feature_list.h"
namespace chromeos {
namespace assistant {
namespace features {
extern const base::Feature kAssistantVoiceMatch;
} // namespace features
} // namespace assistant
} // namespace chromeos
#endif // CHROMEOS_SERVICES_ASSISTANT_PUBLIC_FEATURES_H_
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