Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/search/hotword_service.h" | 5 #include "chrome/browser/search/hotword_service.h" |
| 6 | 6 |
| 7 #include "base/i18n/case_conversion.h" | 7 #include "base/i18n/case_conversion.h" |
| 8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/path_service.h" | |
| 10 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
| 11 #include "chrome/browser/browser_process.h" | 12 #include "chrome/browser/browser_process.h" |
| 12 #include "chrome/browser/chrome_notification_types.h" | 13 #include "chrome/browser/chrome_notification_types.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 14 #include "chrome/browser/extensions/extension_service.h" |
| 15 #include "chrome/browser/plugins/plugin_prefs.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/search/hotword_service_factory.h" | |
| 18 #include "chrome/common/chrome_paths.h" | |
| 15 #include "chrome/common/extensions/extension_constants.h" | 19 #include "chrome/common/extensions/extension_constants.h" |
| 16 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 17 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 18 #include "content/public/browser/notification_service.h" | 22 #include "content/public/browser/notification_service.h" |
| 23 #include "content/public/browser/plugin_service.h" | |
| 24 #include "content/public/common/webplugininfo.h" | |
| 19 #include "extensions/browser/extension_system.h" | 25 #include "extensions/browser/extension_system.h" |
| 20 #include "extensions/common/extension.h" | 26 #include "extensions/common/extension.h" |
| 27 #include "grit/generated_resources.h" | |
| 21 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
| 22 | 29 |
| 23 // The whole file relies on the extension systems but this file is built on | 30 // The whole file relies on the extension systems but this file is built on |
| 24 // some non-extension supported platforms and including an API header will cause | 31 // some non-extension supported platforms and including an API header will cause |
| 25 // a compile error since it depends on header files generated by .idl. | 32 // a compile error since it depends on header files generated by .idl. |
| 26 // TODO(mukai): clean up file dependencies and remove this clause. | 33 // TODO(mukai): clean up file dependencies and remove this clause. |
| 27 #if defined(ENABLE_EXTENSIONS) | 34 #if defined(ENABLE_EXTENSIONS) |
| 28 #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" | 35 #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" |
| 29 #endif | 36 #endif |
| 30 | 37 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 58 // This is used for UMA stats -- do not reorder or delete items; only add to | 65 // This is used for UMA stats -- do not reorder or delete items; only add to |
| 59 // the end. | 66 // the end. |
| 60 enum HotwordExtensionAvailability { | 67 enum HotwordExtensionAvailability { |
| 61 UNAVAILABLE = 0, | 68 UNAVAILABLE = 0, |
| 62 AVAILABLE, | 69 AVAILABLE, |
| 63 PENDING_DOWNLOAD, | 70 PENDING_DOWNLOAD, |
| 64 DISABLED_EXTENSION, | 71 DISABLED_EXTENSION, |
| 65 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS | 72 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS |
| 66 }; | 73 }; |
| 67 | 74 |
| 68 void RecordAvailabilityMetrics( | 75 // Enum describing the types of errors that can arise when determining |
| 76 // if hotwording can be used. NO_ERROR is used so it can be seen how often | |
| 77 // errors arise relative to when they do not. | |
| 78 // This is used for UMA stats -- do not reorder or delete items; only add to | |
| 79 // the end. | |
| 80 enum HotwordError { | |
| 81 NO_ERROR = 0, | |
| 82 GENERIC_ERROR, | |
| 83 NACL_ERROR, | |
| 84 MICROPHONE_ERROR, | |
| 85 NUM_HOTWORD_ERROR_METRICS | |
| 86 }; | |
| 87 | |
| 88 void RecordExtensionAvailabilityMetrics( | |
| 69 ExtensionService* service, | 89 ExtensionService* service, |
| 70 const extensions::Extension* extension) { | 90 const extensions::Extension* extension) { |
| 71 HotwordExtensionAvailability availability_state = UNAVAILABLE; | 91 HotwordExtensionAvailability availability_state = UNAVAILABLE; |
| 72 if (extension) { | 92 if (extension) { |
| 73 availability_state = AVAILABLE; | 93 availability_state = AVAILABLE; |
| 74 } else if (service->pending_extension_manager() && | 94 } else if (service->pending_extension_manager() && |
| 75 service->pending_extension_manager()->IsIdPending( | 95 service->pending_extension_manager()->IsIdPending( |
| 76 extension_misc::kHotwordExtensionId)) { | 96 extension_misc::kHotwordExtensionId)) { |
| 77 availability_state = PENDING_DOWNLOAD; | 97 availability_state = PENDING_DOWNLOAD; |
| 78 } else if (!service->IsExtensionEnabled( | 98 } else if (!service->IsExtensionEnabled( |
| 79 extension_misc::kHotwordExtensionId)) { | 99 extension_misc::kHotwordExtensionId)) { |
| 80 availability_state = DISABLED_EXTENSION; | 100 availability_state = DISABLED_EXTENSION; |
| 81 } | 101 } |
| 82 UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability", | 102 UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability", |
| 83 availability_state, | 103 availability_state, |
| 84 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS); | 104 NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS); |
| 85 } | 105 } |
| 86 | 106 |
| 87 void RecordLoggingMetrics(Profile* profile) { | 107 void RecordLoggingMetrics(Profile* profile) { |
| 88 // If the user is not opted in to hotword voice search, the audio logging | 108 // If the user is not opted in to hotword voice search, the audio logging |
| 89 // metric is not valid so it is not recorded. | 109 // metric is not valid so it is not recorded. |
| 90 if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) | 110 if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) |
| 91 return; | 111 return; |
| 92 | 112 |
| 93 UMA_HISTOGRAM_BOOLEAN( | 113 UMA_HISTOGRAM_BOOLEAN( |
| 94 "Hotword.HotwordAudioLogging", | 114 "Hotword.HotwordAudioLogging", |
| 95 profile->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled)); | 115 profile->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled)); |
| 96 } | 116 } |
| 97 | 117 |
| 118 void RecordErrorMetrics(int error_message) { | |
| 119 HotwordError error = NO_ERROR; | |
| 120 switch (error_message) { | |
| 121 case IDS_HOTWORD_GENERIC_ERROR_MESSAGE: | |
| 122 error = GENERIC_ERROR; | |
| 123 break; | |
| 124 case IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE: | |
| 125 error = NACL_ERROR; | |
| 126 break; | |
| 127 default: | |
|
Jered
2014/05/19 20:47:34
You should probably hook up the other two errors,
rpetterson
2014/05/19 21:04:17
There's only one other error right now -- the micr
Mark P
2014/05/19 22:01:31
This is a fine answer if you're pretty sure the ne
rpetterson
2014/05/19 22:04:19
It will be soon, probably this week. The CL is mos
| |
| 128 error = NO_ERROR; | |
| 129 } | |
| 130 | |
| 131 UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordError", | |
| 132 error, | |
| 133 NUM_HOTWORD_ERROR_METRICS); | |
| 134 } | |
| 135 | |
| 98 ExtensionService* GetExtensionService(Profile* profile) { | 136 ExtensionService* GetExtensionService(Profile* profile) { |
| 99 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 137 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 100 | 138 |
| 101 extensions::ExtensionSystem* extension_system = | 139 extensions::ExtensionSystem* extension_system = |
| 102 extensions::ExtensionSystem::Get(profile); | 140 extensions::ExtensionSystem::Get(profile); |
| 103 if (extension_system) | 141 if (extension_system) |
| 104 return extension_system->extension_service(); | 142 return extension_system->extension_service(); |
| 105 return NULL; | 143 return NULL; |
| 106 } | 144 } |
| 107 | 145 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 129 | 167 |
| 130 for (size_t i = 0; i < arraysize(kSupportedLocales); i++) { | 168 for (size_t i = 0; i < arraysize(kSupportedLocales); i++) { |
| 131 if (normalized_locale.compare(0, 2, kSupportedLocales[i]) == 0) | 169 if (normalized_locale.compare(0, 2, kSupportedLocales[i]) == 0) |
| 132 return true; | 170 return true; |
| 133 } | 171 } |
| 134 return false; | 172 return false; |
| 135 } | 173 } |
| 136 | 174 |
| 137 HotwordService::HotwordService(Profile* profile) | 175 HotwordService::HotwordService(Profile* profile) |
| 138 : profile_(profile), | 176 : profile_(profile), |
| 139 client_(NULL) { | 177 client_(NULL), |
| 178 error_message_(0) { | |
| 140 // This will be called during profile initialization which is a good time | 179 // This will be called during profile initialization which is a good time |
| 141 // to check the user's hotword state. | 180 // to check the user's hotword state. |
| 142 HotwordEnabled enabled_state = UNSET; | 181 HotwordEnabled enabled_state = UNSET; |
| 143 if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) { | 182 if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) { |
| 144 if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) | 183 if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) |
| 145 enabled_state = ENABLED; | 184 enabled_state = ENABLED; |
| 146 else | 185 else |
| 147 enabled_state = DISABLED; | 186 enabled_state = DISABLED; |
| 148 } else { | 187 } else { |
| 149 // If the preference has not been set the hotword extension should | 188 // If the preference has not been set the hotword extension should |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 | 258 |
| 220 void HotwordService::ShowOptInPopup() { | 259 void HotwordService::ShowOptInPopup() { |
| 221 int number_shown = profile_->GetPrefs()->GetInteger( | 260 int number_shown = profile_->GetPrefs()->GetInteger( |
| 222 prefs::kHotwordOptInPopupTimesShown); | 261 prefs::kHotwordOptInPopupTimesShown); |
| 223 profile_->GetPrefs()->SetInteger(prefs::kHotwordOptInPopupTimesShown, | 262 profile_->GetPrefs()->SetInteger(prefs::kHotwordOptInPopupTimesShown, |
| 224 ++number_shown); | 263 ++number_shown); |
| 225 // TODO(rlp): actually show opt in popup when linked up to extension. | 264 // TODO(rlp): actually show opt in popup when linked up to extension. |
| 226 } | 265 } |
| 227 | 266 |
| 228 bool HotwordService::IsServiceAvailable() { | 267 bool HotwordService::IsServiceAvailable() { |
| 268 error_message_ = 0; | |
| 269 | |
| 270 // Determine if the extension is available. | |
| 229 extensions::ExtensionSystem* system = | 271 extensions::ExtensionSystem* system = |
| 230 extensions::ExtensionSystem::Get(profile_); | 272 extensions::ExtensionSystem::Get(profile_); |
| 231 ExtensionService* service = system->extension_service(); | 273 ExtensionService* service = system->extension_service(); |
| 232 // Include disabled extensions (true parameter) since it may not be enabled | 274 // Include disabled extensions (true parameter) since it may not be enabled |
| 233 // if the user opted out. | 275 // if the user opted out. |
| 234 const extensions::Extension* extension = | 276 const extensions::Extension* extension = |
| 235 service->GetExtensionById(extension_misc::kHotwordExtensionId, true); | 277 service->GetExtensionById(extension_misc::kHotwordExtensionId, true); |
| 278 if (!extension) | |
| 279 error_message_ = IDS_HOTWORD_GENERIC_ERROR_MESSAGE; | |
| 236 | 280 |
| 237 RecordAvailabilityMetrics(service, extension); | 281 RecordExtensionAvailabilityMetrics(service, extension); |
| 238 RecordLoggingMetrics(profile_); | 282 RecordLoggingMetrics(profile_); |
| 239 | 283 |
| 240 return extension && IsHotwordAllowed(); | 284 // Determine if NaCl is available. |
| 285 bool nacl_enabled = false; | |
| 286 base::FilePath path; | |
| 287 if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) { | |
| 288 content::WebPluginInfo info; | |
| 289 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get(); | |
| 290 if (content::PluginService::GetInstance()->GetPluginInfoByPath(path, &info)) | |
| 291 nacl_enabled = plugin_prefs->IsPluginEnabled(info); | |
| 292 } | |
| 293 if (!nacl_enabled) | |
| 294 error_message_ = IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE; | |
| 295 | |
| 296 RecordErrorMetrics(error_message_); | |
| 297 | |
| 298 return (error_message_ == 0) && IsHotwordAllowed(); | |
| 241 } | 299 } |
| 242 | 300 |
| 243 bool HotwordService::IsHotwordAllowed() { | 301 bool HotwordService::IsHotwordAllowed() { |
| 244 std::string group = base::FieldTrialList::FindFullName( | 302 std::string group = base::FieldTrialList::FindFullName( |
| 245 hotword_internal::kHotwordFieldTrialName); | 303 hotword_internal::kHotwordFieldTrialName); |
| 246 return !group.empty() && | 304 return !group.empty() && |
| 247 group != hotword_internal::kHotwordFieldTrialDisabledGroupName && | 305 group != hotword_internal::kHotwordFieldTrialDisabledGroupName && |
| 248 DoesHotwordSupportLanguage(profile_); | 306 DoesHotwordSupportLanguage(profile_); |
| 249 } | 307 } |
| 250 | 308 |
| 251 bool HotwordService::IsOptedIntoAudioLogging() { | 309 bool HotwordService::IsOptedIntoAudioLogging() { |
| 252 // Do not opt the user in if the preference has not been set. | 310 // Do not opt the user in if the preference has not been set. |
| 253 return | 311 return |
| 254 profile_->GetPrefs()->HasPrefPath(prefs::kHotwordAudioLoggingEnabled) && | 312 profile_->GetPrefs()->HasPrefPath(prefs::kHotwordAudioLoggingEnabled) && |
| 255 profile_->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled); | 313 profile_->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled); |
| 256 } | 314 } |
| 257 | 315 |
| 258 bool HotwordService::RetryHotwordExtension() { | |
| 259 ExtensionService* extension_service = GetExtensionService(profile_); | |
| 260 if (!extension_service) | |
| 261 return false; | |
| 262 | |
| 263 extension_service->ReloadExtension(extension_misc::kHotwordExtensionId); | |
| 264 return true; | |
| 265 } | |
| 266 | |
| 267 void HotwordService::EnableHotwordExtension( | 316 void HotwordService::EnableHotwordExtension( |
| 268 ExtensionService* extension_service) { | 317 ExtensionService* extension_service) { |
| 269 if (extension_service) | 318 if (extension_service) |
| 270 extension_service->EnableExtension(extension_misc::kHotwordExtensionId); | 319 extension_service->EnableExtension(extension_misc::kHotwordExtensionId); |
| 271 } | 320 } |
| 272 | 321 |
| 273 void HotwordService::DisableHotwordExtension( | 322 void HotwordService::DisableHotwordExtension( |
| 274 ExtensionService* extension_service) { | 323 ExtensionService* extension_service) { |
| 275 if (extension_service) { | 324 if (extension_service) { |
| 276 extension_service->DisableExtension( | 325 extension_service->DisableExtension( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 311 | 360 |
| 312 DCHECK(client_ == client); | 361 DCHECK(client_ == client); |
| 313 | 362 |
| 314 client_ = NULL; | 363 client_ = NULL; |
| 315 HotwordPrivateEventService* event_service = | 364 HotwordPrivateEventService* event_service = |
| 316 BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); | 365 BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); |
| 317 if (event_service) | 366 if (event_service) |
| 318 event_service->OnHotwordSessionStopped(); | 367 event_service->OnHotwordSessionStopped(); |
| 319 #endif | 368 #endif |
| 320 } | 369 } |
| OLD | NEW |