Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / hotword_private / hotword_private_api.cc
blobe268204caf8fd0c70f5c2da24dae3364fe96c629
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h"
7 #include <string>
9 #include "base/lazy_instance.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/search/hotword_audio_history_handler.h"
15 #include "chrome/browser/search/hotword_client.h"
16 #include "chrome/browser/search/hotword_service.h"
17 #include "chrome/browser/search/hotword_service_factory.h"
18 #include "chrome/browser/ui/app_list/app_list_service.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/grit/chromium_strings.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/speech_recognition_session_preamble.h"
24 #include "extensions/browser/event_router.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/webui/web_ui_util.h"
28 #if defined(OS_CHROMEOS)
29 #include "ash/system/chromeos/devicetype_utils.h"
30 #endif
32 namespace extensions {
34 namespace hotword_private_constants {
35 const char kHotwordServiceUnavailable[] = "Hotword Service is unavailable.";
36 const char kHotwordEventServiceUnavailable[] =
37 "Hotword Private Event Service is unavailable.";
38 } // hotword_private_constants
40 namespace OnEnabledChanged =
41 api::hotword_private::OnEnabledChanged;
43 static base::LazyInstance<
44 BrowserContextKeyedAPIFactory<HotwordPrivateEventService> > g_factory =
45 LAZY_INSTANCE_INITIALIZER;
47 HotwordPrivateEventService::HotwordPrivateEventService(
48 content::BrowserContext* context)
49 : profile_(Profile::FromBrowserContext(context)) {
50 pref_change_registrar_.Init(profile_->GetPrefs());
51 pref_change_registrar_.Add(
52 prefs::kHotwordSearchEnabled,
53 base::Bind(&HotwordPrivateEventService::OnEnabledChanged,
54 base::Unretained(this)));
55 pref_change_registrar_.Add(
56 prefs::kHotwordAlwaysOnSearchEnabled,
57 base::Bind(&HotwordPrivateEventService::OnEnabledChanged,
58 base::Unretained(this)));
61 HotwordPrivateEventService::~HotwordPrivateEventService() {
64 void HotwordPrivateEventService::Shutdown() {
67 // static
68 BrowserContextKeyedAPIFactory<HotwordPrivateEventService>*
69 HotwordPrivateEventService::GetFactoryInstance() {
70 return g_factory.Pointer();
73 // static
74 const char* HotwordPrivateEventService::service_name() {
75 return "HotwordPrivateEventService";
78 void HotwordPrivateEventService::OnEnabledChanged(
79 const std::string& pref_name) {
80 DCHECK(pref_name == std::string(prefs::kHotwordSearchEnabled) ||
81 pref_name == std::string(prefs::kHotwordAlwaysOnSearchEnabled) ||
82 pref_name == std::string(
83 hotword_internal::kHotwordTrainingEnabled));
84 SignalEvent(events::HOTWORD_PRIVATE_ON_ENABLED_CHANGED,
85 OnEnabledChanged::kEventName);
88 void HotwordPrivateEventService::OnHotwordSessionRequested() {
89 SignalEvent(events::HOTWORD_PRIVATE_ON_HOTWORD_SESSION_REQUESTED,
90 api::hotword_private::OnHotwordSessionRequested::kEventName);
93 void HotwordPrivateEventService::OnHotwordSessionStopped() {
94 SignalEvent(events::HOTWORD_PRIVATE_ON_HOTWORD_SESSION_STOPPED,
95 api::hotword_private::OnHotwordSessionStopped::kEventName);
98 void HotwordPrivateEventService::OnFinalizeSpeakerModel() {
99 SignalEvent(events::HOTWORD_PRIVATE_ON_FINALIZE_SPEAKER_MODEL,
100 api::hotword_private::OnFinalizeSpeakerModel::kEventName);
103 void HotwordPrivateEventService::OnSpeakerModelSaved() {
104 SignalEvent(events::HOTWORD_PRIVATE_ON_SPEAKER_MODEL_SAVED,
105 api::hotword_private::OnSpeakerModelSaved::kEventName);
108 void HotwordPrivateEventService::OnHotwordTriggered() {
109 SignalEvent(events::HOTWORD_PRIVATE_ON_HOTWORD_TRIGGERED,
110 api::hotword_private::OnHotwordTriggered::kEventName);
113 void HotwordPrivateEventService::OnDeleteSpeakerModel() {
114 SignalEvent(events::HOTWORD_PRIVATE_ON_DELETE_SPEAKER_MODEL,
115 api::hotword_private::OnDeleteSpeakerModel::kEventName);
118 void HotwordPrivateEventService::OnSpeakerModelExists() {
119 SignalEvent(events::HOTWORD_PRIVATE_ON_SPEAKER_MODEL_EXISTS,
120 api::hotword_private::OnSpeakerModelExists::kEventName);
123 void HotwordPrivateEventService::OnMicrophoneStateChanged(bool enabled) {
124 SignalEvent(events::HOTWORD_PRIVATE_ON_MICROPHONE_STATE_CHANGED,
125 api::hotword_private::OnMicrophoneStateChanged::kEventName,
126 api::hotword_private::OnMicrophoneStateChanged::Create(enabled));
129 void HotwordPrivateEventService::SignalEvent(
130 events::HistogramValue histogram_value,
131 const std::string& event_name) {
132 SignalEvent(histogram_value, event_name,
133 make_scoped_ptr(new base::ListValue()));
136 void HotwordPrivateEventService::SignalEvent(
137 events::HistogramValue histogram_value,
138 const std::string& event_name,
139 scoped_ptr<base::ListValue> args) {
140 EventRouter* router = EventRouter::Get(profile_);
141 if (!router || !router->HasEventListener(event_name))
142 return;
144 scoped_ptr<Event> event(new Event(histogram_value, event_name, args.Pass()));
145 router->BroadcastEvent(event.Pass());
148 bool HotwordPrivateSetEnabledFunction::RunSync() {
149 scoped_ptr<api::hotword_private::SetEnabled::Params> params(
150 api::hotword_private::SetEnabled::Params::Create(*args_));
151 EXTENSION_FUNCTION_VALIDATE(params.get());
153 PrefService* prefs = GetProfile()->GetPrefs();
154 prefs->SetBoolean(prefs::kHotwordSearchEnabled, params->state);
155 return true;
158 bool HotwordPrivateSetAudioLoggingEnabledFunction::RunSync() {
159 scoped_ptr<api::hotword_private::SetAudioLoggingEnabled::Params> params(
160 api::hotword_private::SetAudioLoggingEnabled::Params::Create(*args_));
161 EXTENSION_FUNCTION_VALIDATE(params.get());
163 // TODO(kcarattini): Sync the chrome pref with the account-level
164 // Audio History setting.
165 PrefService* prefs = GetProfile()->GetPrefs();
166 prefs->SetBoolean(prefs::kHotwordAudioLoggingEnabled, params->state);
167 return true;
170 bool HotwordPrivateSetHotwordAlwaysOnSearchEnabledFunction::RunSync() {
171 scoped_ptr<api::hotword_private::SetHotwordAlwaysOnSearchEnabled::Params>
172 params(api::hotword_private::SetHotwordAlwaysOnSearchEnabled::Params::
173 Create(*args_));
174 EXTENSION_FUNCTION_VALIDATE(params.get());
176 PrefService* prefs = GetProfile()->GetPrefs();
177 prefs->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, params->state);
178 return true;
181 bool HotwordPrivateGetStatusFunction::RunSync() {
182 scoped_ptr<api::hotword_private::GetStatus::Params> params(
183 api::hotword_private::GetStatus::Params::Create(*args_));
184 EXTENSION_FUNCTION_VALIDATE(params.get());
186 api::hotword_private::StatusDetails result;
188 HotwordService* hotword_service =
189 HotwordServiceFactory::GetForProfile(GetProfile());
190 if (!hotword_service) {
191 result.available = false;
192 result.always_on_available = false;
193 result.enabled = false;
194 result.audio_logging_enabled = false;
195 result.always_on_enabled = false;
196 result.user_is_active = false;
197 result.hotword_hardware_available = false;
198 } else {
199 result.available = false;
200 result.always_on_available = false;
201 if (params->get_optional_fields && *params->get_optional_fields) {
202 result.available = hotword_service->IsServiceAvailable();
203 result.always_on_available =
204 HotwordServiceFactory::IsAlwaysOnAvailable();
206 result.enabled = hotword_service->IsSometimesOnEnabled();
207 result.audio_logging_enabled = hotword_service->IsOptedIntoAudioLogging();
208 result.training_enabled = hotword_service->IsTraining();
209 result.always_on_enabled = hotword_service->IsAlwaysOnEnabled();
210 result.user_is_active = hotword_service->UserIsActive();
211 result.hotword_hardware_available =
212 HotwordService::IsHotwordHardwareAvailable();
215 PrefService* prefs = GetProfile()->GetPrefs();
216 result.enabled_set = prefs->HasPrefPath(prefs::kHotwordSearchEnabled);
218 SetResult(result.ToValue().release());
219 return true;
222 bool HotwordPrivateSetHotwordSessionStateFunction::RunSync() {
223 scoped_ptr<api::hotword_private::SetHotwordSessionState::Params> params(
224 api::hotword_private::SetHotwordSessionState::Params::Create(*args_));
225 EXTENSION_FUNCTION_VALIDATE(params.get());
227 HotwordService* hotword_service =
228 HotwordServiceFactory::GetForProfile(GetProfile());
229 if (hotword_service &&
230 hotword_service->client() &&
231 !hotword_service->IsTraining())
232 hotword_service->client()->OnHotwordStateChanged(params->started);
233 return true;
236 bool HotwordPrivateNotifyHotwordRecognitionFunction::RunSync() {
237 scoped_ptr<api::hotword_private::NotifyHotwordRecognition::Params> params(
238 api::hotword_private::NotifyHotwordRecognition::Params::Create(*args_));
239 EXTENSION_FUNCTION_VALIDATE(params.get());
241 scoped_refptr<content::SpeechRecognitionSessionPreamble> preamble;
242 if (params->log.get() &&
243 !params->log->buffer.empty() &&
244 params->log->channels == 1) {
245 // TODO(amistry): Convert multi-channel preamble log into mono.
246 preamble = new content::SpeechRecognitionSessionPreamble();
247 preamble->sample_rate = params->log->sample_rate;
248 preamble->sample_depth = params->log->bytes_per_sample;
249 preamble->sample_data.swap(params->log->buffer);
252 HotwordService* hotword_service =
253 HotwordServiceFactory::GetForProfile(GetProfile());
254 if (hotword_service) {
255 if (hotword_service->IsTraining()) {
256 hotword_service->NotifyHotwordTriggered();
257 } else if (hotword_service->client()) {
258 hotword_service->client()->OnHotwordRecognized(preamble);
259 } else if (hotword_service->IsAlwaysOnEnabled()) {
260 Browser* browser = GetCurrentBrowser();
261 // If a Browser does not exist, fall back to the universally available,
262 // but not recommended, way.
263 AppListService* app_list_service = AppListService::Get(
264 browser ? browser->host_desktop_type() : chrome::GetActiveDesktop());
265 CHECK(app_list_service);
266 app_list_service->ShowForVoiceSearch(GetProfile(), preamble);
269 return true;
272 bool HotwordPrivateGetLaunchStateFunction::RunSync() {
273 HotwordService* hotword_service =
274 HotwordServiceFactory::GetForProfile(GetProfile());
275 if (!hotword_service) {
276 error_ = hotword_private_constants::kHotwordServiceUnavailable;
277 return false;
280 api::hotword_private::LaunchState result;
281 result.launch_mode =
282 hotword_service->GetHotwordAudioVerificationLaunchMode();
283 SetResult(result.ToValue().release());
284 return true;
287 bool HotwordPrivateStartTrainingFunction::RunSync() {
288 HotwordService* hotword_service =
289 HotwordServiceFactory::GetForProfile(GetProfile());
290 if (!hotword_service) {
291 error_ = hotword_private_constants::kHotwordServiceUnavailable;
292 return false;
295 hotword_service->StartTraining();
296 return true;
299 bool HotwordPrivateFinalizeSpeakerModelFunction::RunSync() {
300 HotwordService* hotword_service =
301 HotwordServiceFactory::GetForProfile(GetProfile());
302 if (!hotword_service) {
303 error_ = hotword_private_constants::kHotwordServiceUnavailable;
304 return false;
307 hotword_service->FinalizeSpeakerModel();
308 return true;
311 bool HotwordPrivateNotifySpeakerModelSavedFunction::RunSync() {
312 HotwordPrivateEventService* event_service =
313 BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(
314 GetProfile());
315 if (!event_service) {
316 error_ = hotword_private_constants::kHotwordEventServiceUnavailable;
317 return false;
320 event_service->OnSpeakerModelSaved();
321 return true;
324 bool HotwordPrivateStopTrainingFunction::RunSync() {
325 HotwordService* hotword_service =
326 HotwordServiceFactory::GetForProfile(GetProfile());
327 if (!hotword_service) {
328 error_ = hotword_private_constants::kHotwordServiceUnavailable;
329 return false;
332 hotword_service->StopTraining();
333 return true;
336 bool HotwordPrivateGetLocalizedStringsFunction::RunSync() {
337 #if defined(OS_CHROMEOS)
338 base::string16 device_type = ash::GetChromeOSDeviceName();
339 #else
340 base::string16 product_name =
341 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
342 base::string16 device_type =
343 l10n_util::GetStringFUTF16(IDS_HOTWORD_BROWSER_NAME, product_name);
344 #endif
346 base::DictionaryValue* localized_strings = new base::DictionaryValue();
348 localized_strings->SetString(
349 "close",
350 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_CLOSE));
351 localized_strings->SetString(
352 "cancel",
353 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_CANCEL));
354 localized_strings->SetString(
355 "introTitle",
356 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_INTRO_TITLE));
357 localized_strings->SetString(
358 "introSubtitle",
359 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_INTRO_SUBTITLE));
360 localized_strings->SetString(
361 "introDescription",
362 l10n_util::GetStringFUTF16(IDS_HOTWORD_OPT_IN_INTRO_DESCRIPTION,
363 device_type));
364 localized_strings->SetString(
365 "introDescriptionAudioHistoryEnabled",
366 l10n_util::GetStringFUTF16(
367 IDS_HOTWORD_OPT_IN_INTRO_DESCRIPTION_AUDIO_HISTORY_ENABLED,
368 device_type));
369 localized_strings->SetString(
370 "introStart",
371 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_INTRO_START));
372 localized_strings->SetString(
373 "audioHistoryTitle",
374 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_TITLE));
375 localized_strings->SetString(
376 "audioHistoryDescription1",
377 l10n_util::GetStringUTF16(
378 IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_DESCRIPTION_1));
379 localized_strings->SetString(
380 "audioHistoryDescription2",
381 l10n_util::GetStringUTF16(
382 IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_DESCRIPTION_2));
383 localized_strings->SetString(
384 "audioHistoryDescription3",
385 l10n_util::GetStringUTF16(
386 IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_DESCRIPTION_3));
387 localized_strings->SetString(
388 "audioHistoryAgree",
389 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_AGREE));
390 localized_strings->SetString(
391 "audioHistoryWait",
392 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_AUDIO_HISTORY_WAIT));
393 localized_strings->SetString(
394 "error",
395 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_ERROR));
396 localized_strings->SetString(
397 "trainingTitle", l10n_util::GetStringFUTF16(
398 IDS_HOTWORD_OPT_IN_TRAINING_TITLE, device_type));
399 localized_strings->SetString(
400 "trainingDescription",
401 l10n_util::GetStringFUTF16(IDS_HOTWORD_OPT_IN_TRAINING_DESCRIPTION,
402 device_type));
403 localized_strings->SetString(
404 "trainingSpeak",
405 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_SPEAK));
406 localized_strings->SetString(
407 "trainingFirstPrompt",
408 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_FIRST_PROMPT));
409 localized_strings->SetString(
410 "trainingMiddlePrompt",
411 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_MIDDLE_PROMPT));
412 localized_strings->SetString(
413 "trainingLastPrompt",
414 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_LAST_PROMPT));
415 localized_strings->SetString(
416 "trainingRecorded",
417 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_RECORDED));
418 localized_strings->SetString(
419 "trainingTimeout",
420 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_TIMEOUT));
421 localized_strings->SetString(
422 "trainingRetry",
423 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_TRAINING_RETRY));
424 localized_strings->SetString(
425 "finishedTitle",
426 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISHED_TITLE));
427 localized_strings->SetString(
428 "finishedListIntro",
429 l10n_util::GetStringFUTF16(IDS_HOTWORD_OPT_IN_FINISHED_LIST_INTRO,
430 device_type));
431 localized_strings->SetString(
432 "finishedListItem1",
433 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISHED_LIST_ITEM_1));
434 localized_strings->SetString(
435 "finishedListItem2",
436 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISHED_LIST_ITEM_2));
437 localized_strings->SetString(
438 "finishedSettings",
439 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISHED_SETTINGS));
440 localized_strings->SetString(
441 "finishedAudioHistory",
442 l10n_util::GetStringUTF16(
443 IDS_HOTWORD_OPT_IN_FINISHED_AUDIO_HISTORY));
444 localized_strings->SetString(
445 "finish",
446 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISH));
447 localized_strings->SetString(
448 "finishedWait",
449 l10n_util::GetStringUTF16(IDS_HOTWORD_OPT_IN_FINISHED_WAIT));
451 const std::string& app_locale = g_browser_process->GetApplicationLocale();
452 webui::SetLoadTimeDataDefaults(app_locale, localized_strings);
454 SetResult(localized_strings);
455 return true;
458 bool HotwordPrivateSetAudioHistoryEnabledFunction::RunAsync() {
459 scoped_ptr<api::hotword_private::SetAudioHistoryEnabled::Params> params(
460 api::hotword_private::SetAudioHistoryEnabled::Params::Create(*args_));
461 EXTENSION_FUNCTION_VALIDATE(params.get());
463 HotwordService* hotword_service =
464 HotwordServiceFactory::GetForProfile(GetProfile());
465 if (!hotword_service || !hotword_service->GetAudioHistoryHandler()) {
466 error_ = hotword_private_constants::kHotwordServiceUnavailable;
467 return false;
470 hotword_service->GetAudioHistoryHandler()->SetAudioHistoryEnabled(
471 params->enabled,
472 base::Bind(
473 &HotwordPrivateSetAudioHistoryEnabledFunction::SetResultAndSendResponse,
474 this));
475 return true;
478 void HotwordPrivateSetAudioHistoryEnabledFunction::SetResultAndSendResponse(
479 bool success, bool new_enabled_value) {
480 api::hotword_private::AudioHistoryState result;
481 result.success = success;
482 result.enabled = new_enabled_value;
483 SetResult(result.ToValue().release());
484 SendResponse(true);
487 bool HotwordPrivateGetAudioHistoryEnabledFunction::RunAsync() {
488 HotwordService* hotword_service =
489 HotwordServiceFactory::GetForProfile(GetProfile());
490 if (!hotword_service || !hotword_service->GetAudioHistoryHandler()) {
491 error_ = hotword_private_constants::kHotwordServiceUnavailable;
492 return false;
495 hotword_service->GetAudioHistoryHandler()->GetAudioHistoryEnabled(base::Bind(
496 &HotwordPrivateGetAudioHistoryEnabledFunction::SetResultAndSendResponse,
497 this));
499 return true;
502 void HotwordPrivateGetAudioHistoryEnabledFunction::SetResultAndSendResponse(
503 bool success, bool new_enabled_value) {
504 api::hotword_private::AudioHistoryState result;
505 result.success = success;
506 result.enabled = new_enabled_value;
507 SetResult(result.ToValue().release());
508 SendResponse(true);
511 bool HotwordPrivateSpeakerModelExistsResultFunction::RunSync() {
512 scoped_ptr<api::hotword_private::SpeakerModelExistsResult::Params> params(
513 api::hotword_private::SpeakerModelExistsResult::Params::Create(*args_));
514 EXTENSION_FUNCTION_VALIDATE(params.get());
516 HotwordService* hotword_service =
517 HotwordServiceFactory::GetForProfile(GetProfile());
518 if (!hotword_service)
519 return false;
521 hotword_service->SpeakerModelExistsComplete(params->exists);
522 return true;
525 } // namespace extensions