hotword_service.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2013 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. 4 5#include "chrome/browser/search/hotword_service.h" 6 7#include "base/i18n/case_conversion.h" 8#include "base/metrics/field_trial.h" 9#include "base/metrics/histogram.h" 10#include "base/prefs/pref_service.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/extensions/extension_service.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/extensions/extension_constants.h" 15#include "chrome/common/pref_names.h" 16#include "content/public/browser/browser_thread.h" 17#include "extensions/browser/extension_system.h" 18#include "extensions/common/extension.h" 19#include "ui/base/l10n/l10n_util.h" 20 21namespace { 22const int kMaxTimesToShowOptInPopup = 10; 23 24// Enum describing the state of the hotword preference. 25// This is used for UMA stats -- do not reorder or delete items; only add to 26// the end. 27enum HotwordEnabled { 28 UNSET = 0, // The hotword preference has not been set. 29 ENABLED, // The hotword preference is enabled. 30 DISABLED, // The hotword preference is disabled. 31 NUM_HOTWORD_ENABLED_METRICS 32}; 33 34// Enum describing the availability state of the hotword extension. 35// This is used for UMA stats -- do not reorder or delete items; only add to 36// the end. 37enum HotwordExtensionAvailability { 38 UNAVAILABLE = 0, 39 AVAILABLE, 40 PENDING_DOWNLOAD, 41 DISABLED_EXTENSION, 42 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS 43}; 44 45void RecordAvailabilityMetrics( 46 ExtensionService* service, 47 const extensions::Extension* extension) { 48 HotwordExtensionAvailability availability_state = UNAVAILABLE; 49 if (extension) { 50 availability_state = AVAILABLE; 51 } else if (service->pending_extension_manager() && 52 service->pending_extension_manager()->IsIdPending( 53 extension_misc::kHotwordExtensionId)) { 54 availability_state = PENDING_DOWNLOAD; 55 } else if (!service->IsExtensionEnabled( 56 extension_misc::kHotwordExtensionId)) { 57 availability_state = DISABLED_EXTENSION; 58 } 59 UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability", 60 availability_state, 61 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS); 62} 63 64} // namespace 65 66namespace hotword_internal { 67// Constants for the hotword field trial. 68const char kHotwordFieldTrialName[] = "VoiceTrigger"; 69const char kHotwordFieldTrialDisabledGroupName[] = "Disabled"; 70} // namespace hotword_internal 71 72// static 73bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { 74 std::string locale = 75#if defined(OS_CHROMEOS) 76 // On ChromeOS locale is per-profile. 77 profile->GetPrefs()->GetString(prefs::kApplicationLocale); 78#else 79 g_browser_process->GetApplicationLocale(); 80#endif 81 // Only available for English now. 82 std::string normalized_locale = l10n_util::NormalizeLocale(locale); 83 return normalized_locale == "en" || normalized_locale == "en_us" || 84 normalized_locale =="en_US"; 85} 86 87HotwordService::HotwordService(Profile* profile) 88 : profile_(profile) { 89 // This will be called during profile initialization which is a good time 90 // to check the user's hotword state. 91 HotwordEnabled enabled_state = UNSET; 92 if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) { 93 if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 94 enabled_state = ENABLED; 95 else 96 enabled_state = DISABLED; 97 } 98 UMA_HISTOGRAM_ENUMERATION("Hotword.Enabled", enabled_state, 99 NUM_HOTWORD_ENABLED_METRICS); 100} 101 102HotwordService::~HotwordService() { 103} 104 105bool HotwordService::ShouldShowOptInPopup() { 106 if (profile_->IsOffTheRecord()) 107 return false; 108 109 // Profile is not off the record. 110 if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) 111 return false; // Already opted in or opted out; 112 113 int number_shown = profile_->GetPrefs()->GetInteger( 114 prefs::kHotwordOptInPopupTimesShown); 115 return number_shown < MaxNumberTimesToShowOptInPopup(); 116} 117 118int HotwordService::MaxNumberTimesToShowOptInPopup() { 119 return kMaxTimesToShowOptInPopup; 120} 121 122void HotwordService::ShowOptInPopup() { 123 int number_shown = profile_->GetPrefs()->GetInteger( 124 prefs::kHotwordOptInPopupTimesShown); 125 profile_->GetPrefs()->SetInteger(prefs::kHotwordOptInPopupTimesShown, 126 ++number_shown); 127 // TODO(rlp): actually show opt in popup when linked up to extension. 128} 129 130bool HotwordService::IsServiceAvailable() { 131 extensions::ExtensionSystem* system = 132 extensions::ExtensionSystem::Get(profile_); 133 ExtensionService* service = system->extension_service(); 134 // Do not include disabled extension (false parameter) because if the 135 // extension is disabled, it's not available. 136 const extensions::Extension* extension = 137 service->GetExtensionById(extension_misc::kHotwordExtensionId, false); 138 139 RecordAvailabilityMetrics(service, extension); 140 141 return extension && IsHotwordAllowed(); 142} 143 144bool HotwordService::IsHotwordAllowed() { 145 std::string group = base::FieldTrialList::FindFullName( 146 hotword_internal::kHotwordFieldTrialName); 147 return !group.empty() && 148 group != hotword_internal::kHotwordFieldTrialDisabledGroupName && 149 DoesHotwordSupportLanguage(profile_); 150} 151 152bool HotwordService::RetryHotwordExtension() { 153 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 154 155 extensions::ExtensionSystem* extension_system = 156 extensions::ExtensionSystem::Get(profile_); 157 if (!extension_system || !extension_system->extension_service()) 158 return false; 159 ExtensionService* extension_service = extension_system->extension_service(); 160 161 extension_service->ReloadExtension(extension_misc::kHotwordExtensionId); 162 return true; 163} 164