hotword_service.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/search/hotword_service.h"
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/i18n/case_conversion.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/field_trial.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/browser_process.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/chrome_notification_types.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMaxTimesToShowOptInPopup = 10;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Allowed languages for hotwording.
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic const char* kSupportedLocales[] = {
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "en",
29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  "en_us"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the state of the hotword preference.
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordEnabled {
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UNSET = 0,  // The hotword preference has not been set.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ENABLED,    // The hotword preference is enabled.
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISABLED,   // The hotword preference is disabled.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NUM_HOTWORD_ENABLED_METRICS
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the availability state of the hotword extension.
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end.
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordExtensionAvailability {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UNAVAILABLE = 0,
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AVAILABLE,
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PENDING_DOWNLOAD,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISABLED_EXTENSION,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordAvailabilityMetrics(
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ExtensionService* service,
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const extensions::Extension* extension) {
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HotwordExtensionAvailability availability_state = UNAVAILABLE;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (extension) {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    availability_state = AVAILABLE;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (service->pending_extension_manager() &&
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             service->pending_extension_manager()->IsIdPending(
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 extension_misc::kHotwordExtensionId)) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    availability_state = PENDING_DOWNLOAD;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (!service->IsExtensionEnabled(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension_misc::kHotwordExtensionId)) {
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    availability_state = DISABLED_EXTENSION;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability",
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            availability_state,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid RecordLoggingMetrics(Profile* profile) {
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the user is not opted in to hotword voice search, the audio logging
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // metric is not valid so it is not recorded.
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_BOOLEAN(
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "Hotword.HotwordAudioLogging",
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      profile->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled));
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)ExtensionService* GetExtensionService(Profile* profile) {
8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  extensions::ExtensionSystem* extension_system =
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile);
8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (extension_system)
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return extension_system->extension_service();
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return NULL;
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace hotword_internal {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Constants for the hotword field trial.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialName[] = "VoiceTrigger";
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialDisabledGroupName[] = "Disabled";
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Old preference constant.
100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kHotwordUnusablePrefName[] = "hotword.search_enabled";
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace hotword_internal
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) {
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string locale =
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // On ChromeOS locale is per-profile.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile->GetPrefs()->GetString(prefs::kApplicationLocale);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_browser_process->GetApplicationLocale();
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string normalized_locale = l10n_util::NormalizeLocale(locale);
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  StringToLowerASCII(&normalized_locale);
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (size_t i = 0; i < arraysize(kSupportedLocales); i++) {
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (kSupportedLocales[i] == normalized_locale)
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return true;
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return false;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::HotwordService(Profile* profile)
1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : profile_(profile) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This will be called during profile initialization which is a good time
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to check the user's hotword state.
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HotwordEnabled enabled_state = UNSET;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      enabled_state = ENABLED;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      enabled_state = DISABLED;
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  } else {
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // If the preference has not been set the hotword extension should
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // not be running. However, this should only be done if auto-install
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // is enabled which is gated through the IsHotwordAllowed check.
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (IsHotwordAllowed())
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DisableHotwordExtension(GetExtensionService(profile_));
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Hotword.Enabled", enabled_state,
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            NUM_HOTWORD_ENABLED_METRICS);
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  pref_registrar_.Init(profile_->GetPrefs());
14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  pref_registrar_.Add(
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      prefs::kHotwordSearchEnabled,
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      base::Bind(&HotwordService::OnHotwordSearchEnabledChanged,
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                 base::Unretained(this)));
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  registrar_.Add(this,
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 chrome::NOTIFICATION_EXTENSION_INSTALLED,
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 content::Source<Profile>(profile_));
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Clear the old user pref because it became unusable.
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // TODO(rlp): Remove this code per crbug.com/358789.
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (profile_->GetPrefs()->HasPrefPath(
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          hotword_internal::kHotwordUnusablePrefName)) {
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    profile_->GetPrefs()->ClearPref(hotword_internal::kHotwordUnusablePrefName);
157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::~HotwordService() {
1618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid HotwordService::Observe(int type,
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                             const content::NotificationSource& source,
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                             const content::NotificationDetails& details) {
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (type == chrome::NOTIFICATION_EXTENSION_INSTALLED) {
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const extensions::Extension* extension =
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        content::Details<const extensions::InstalledExtensionInfo>(details)
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              ->extension;
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Disabling the extension automatically on install should only occur
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // if the user is in the field trial for auto-install which is gated
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // by the IsHotwordAllowed check.
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (IsHotwordAllowed() &&
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        extension->id() == extension_misc::kHotwordExtensionId &&
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        !profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) {
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      DisableHotwordExtension(GetExtensionService(profile_));
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // Once the extension is disabled, it will not be enabled until the
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // user opts in at which point the pref registrar will take over
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // enabling and disabling.
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      registrar_.Remove(this,
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        chrome::NOTIFICATION_EXTENSION_INSTALLED,
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        content::Source<Profile>(profile_));
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::ShouldShowOptInPopup() {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (profile_->IsOffTheRecord())
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Profile is not off the record.
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled))
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;  // Already opted in or opted out;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int number_shown = profile_->GetPrefs()->GetInteger(
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prefs::kHotwordOptInPopupTimesShown);
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return number_shown < MaxNumberTimesToShowOptInPopup();
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int HotwordService::MaxNumberTimesToShowOptInPopup() {
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return kMaxTimesToShowOptInPopup;
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HotwordService::ShowOptInPopup() {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int number_shown = profile_->GetPrefs()->GetInteger(
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prefs::kHotwordOptInPopupTimesShown);
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  profile_->GetPrefs()->SetInteger(prefs::kHotwordOptInPopupTimesShown,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   ++number_shown);
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(rlp): actually show opt in popup when linked up to extension.
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsServiceAvailable() {
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ExtensionSystem* system =
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extensions::ExtensionSystem::Get(profile_);
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionService* service = system->extension_service();
21623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Include disabled extensions (true parameter) since it may not be enabled
21723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // if the user opted out.
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const extensions::Extension* extension =
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      service->GetExtensionById(extension_misc::kHotwordExtensionId, true);
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordAvailabilityMetrics(service, extension);
222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RecordLoggingMetrics(profile_);
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return extension && IsHotwordAllowed();
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsHotwordAllowed() {
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string group = base::FieldTrialList::FindFullName(
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      hotword_internal::kHotwordFieldTrialName);
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !group.empty() &&
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      group != hotword_internal::kHotwordFieldTrialDisabledGroupName &&
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DoesHotwordSupportLanguage(profile_);
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool HotwordService::IsOptedIntoAudioLogging() {
236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Do not opt the user in if the preference has not been set.
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      profile_->GetPrefs()->HasPrefPath(prefs::kHotwordAudioLoggingEnabled) &&
239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      profile_->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled);
240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HotwordService::RetryHotwordExtension() {
24323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ExtensionService* extension_service = GetExtensionService(profile_);
24423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!extension_service)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extension_service->ReloadExtension(extension_misc::kHotwordExtensionId);
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
25023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::EnableHotwordExtension(
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    ExtensionService* extension_service) {
25323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (extension_service)
25423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    extension_service->EnableExtension(extension_misc::kHotwordExtensionId);
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
25723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::DisableHotwordExtension(
25823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    ExtensionService* extension_service) {
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (extension_service) {
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    extension_service->DisableExtension(
26123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        extension_misc::kHotwordExtensionId,
26223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        extensions::Extension::DISABLE_USER_ACTION);
26323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
26423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
26523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
26623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::OnHotwordSearchEnabledChanged(
26723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const std::string& pref_name) {
26823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DCHECK_EQ(pref_name, std::string(prefs::kHotwordSearchEnabled));
26923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
27023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ExtensionService* extension_service = GetExtensionService(profile_);
27123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
27223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    EnableHotwordExtension(extension_service);
27323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  else
27423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    DisableHotwordExtension(extension_service);
27523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
276