hotword_service.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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" 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/path_service.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/browser_process.h" 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/chrome_notification_types.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/pending_extension_manager.h" 166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/updater/extension_updater.h" 176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/webstore_startup_installer.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/plugins/plugin_prefs.h" 198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/search/hotword_service_factory.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h" 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h" 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h" 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/plugin_service.h" 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/common/webplugininfo.h" 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/uninstall_reason.h" 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension.h" 316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/common/one_shot_event.h" 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "grit/generated_resources.h" 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// The whole file relies on the extension systems but this file is built on 36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// some non-extension supported platforms and including an API header will cause 37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// a compile error since it depends on header files generated by .idl. 38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// TODO(mukai): clean up file dependencies and remove this clause. 39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" 41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif 42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using extensions::BrowserContextKeyedAPIFactory; 45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using extensions::HotwordPrivateEventService; 46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Allowed languages for hotwording. 51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic const char* kSupportedLocales[] = { 52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch "en", 536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "de", 546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "fr", 556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "ru" 56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}; 57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the state of the hotword preference. 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end. 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordEnabled { 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UNSET = 0, // The hotword preference has not been set. 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ENABLED, // The hotword preference is enabled. 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISABLED, // The hotword preference is disabled. 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_ENABLED_METRICS 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the availability state of the hotword extension. 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end. 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordExtensionAvailability { 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UNAVAILABLE = 0, 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AVAILABLE, 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PENDING_DOWNLOAD, 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISABLED_EXTENSION, 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Enum describing the types of errors that can arise when determining 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// if hotwording can be used. NO_ERROR is used so it can be seen how often 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// errors arise relative to when they do not. 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// the end. 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)enum HotwordError { 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NO_HOTWORD_ERROR = 0, 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GENERIC_HOTWORD_ERROR, 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NACL_HOTWORD_ERROR, 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MICROPHONE_HOTWORD_ERROR, 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NUM_HOTWORD_ERROR_METRICS 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RecordExtensionAvailabilityMetrics( 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionService* service, 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const extensions::Extension* extension) { 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HotwordExtensionAvailability availability_state = UNAVAILABLE; 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (extension) { 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = AVAILABLE; 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (service->pending_extension_manager() && 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) service->pending_extension_manager()->IsIdPending( 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extension_misc::kHotwordExtensionId)) { 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = PENDING_DOWNLOAD; 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (!service->IsExtensionEnabled( 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extension_misc::kHotwordExtensionId)) { 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = DISABLED_EXTENSION; 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability", 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state, 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS); 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid RecordLoggingMetrics(Profile* profile) { 112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If the user is not opted in to hotword voice search, the audio logging 113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // metric is not valid so it is not recorded. 114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch UMA_HISTOGRAM_BOOLEAN( 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch "Hotword.HotwordAudioLogging", 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled)); 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RecordErrorMetrics(int error_message) { 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) HotwordError error = NO_HOTWORD_ERROR; 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (error_message) { 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case IDS_HOTWORD_GENERIC_ERROR_MESSAGE: 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = GENERIC_HOTWORD_ERROR; 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE: 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = NACL_HOTWORD_ERROR; 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case IDS_HOTWORD_MICROPHONE_ERROR_MESSAGE: 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error = MICROPHONE_HOTWORD_ERROR; 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = NO_HOTWORD_ERROR; 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordError", 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error, 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NUM_HOTWORD_ERROR_METRICS); 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)ExtensionService* GetExtensionService(Profile* profile) { 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::ExtensionSystem* extension_system = 14723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::ExtensionSystem::Get(profile); 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return extension_system ? extension_system->extension_service() : NULL; 14923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 15023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 1516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)std::string GetCurrentLocale(Profile* profile) { 1526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string locale = 1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS) 1546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // On ChromeOS locale is per-profile. 1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile->GetPrefs()->GetString(prefs::kApplicationLocale); 1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#else 1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) g_browser_process->GetApplicationLocale(); 1586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif 1596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return locale; 1606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 1616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace hotword_internal { 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Constants for the hotword field trial. 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialName[] = "VoiceTrigger"; 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialDisabledGroupName[] = "Disabled"; 168c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Old preference constant. 169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kHotwordUnusablePrefName[] = "hotword.search_enabled"; 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace hotword_internal 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { 1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string normalized_locale = 1756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) l10n_util::NormalizeLocale(GetCurrentLocale(profile)); 176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch StringToLowerASCII(&normalized_locale); 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (size_t i = 0; i < arraysize(kSupportedLocales); i++) { 1796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (normalized_locale.compare(0, 2, kSupportedLocales[i]) == 0) 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::HotwordService(Profile* profile) 186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) : profile_(profile), 1876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_registry_observer_(this), 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_(NULL), 1896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_message_(0), 1906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_(false), 1916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_factory_(this) { 1926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This will be called during profile initialization which is a good time 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // to check the user's hotword state. 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HotwordEnabled enabled_state = UNSET; 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) { 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enabled_state = ENABLED; 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enabled_state = DISABLED; 20123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } else { 20223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // If the preference has not been set the hotword extension should 2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // not be running. However, this should only be done if auto-install 2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // is enabled which is gated through the IsHotwordAllowed check. 2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (IsHotwordAllowed()) 2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch DisableHotwordExtension(GetExtensionService(profile_)); 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.Enabled", enabled_state, 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_ENABLED_METRICS); 21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) pref_registrar_.Init(profile_->GetPrefs()); 21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) pref_registrar_.Add( 21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) prefs::kHotwordSearchEnabled, 21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::Bind(&HotwordService::OnHotwordSearchEnabledChanged, 21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::Unretained(this))); 216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch registrar_.Add(this, 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chrome::NOTIFICATION_BROWSER_WINDOW_READY, 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::NotificationService::AllSources()); 220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 2216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::ExtensionSystem::Get(profile_)->ready().Post( 2226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) FROM_HERE, 2236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind(base::IgnoreResult( 2246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) &HotwordService::MaybeReinstallHotwordExtension), 2256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_factory_.GetWeakPtr())); 2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Clear the old user pref because it became unusable. 228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // TODO(rlp): Remove this code per crbug.com/358789. 229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (profile_->GetPrefs()->HasPrefPath( 230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch hotword_internal::kHotwordUnusablePrefName)) { 231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch profile_->GetPrefs()->ClearPref(hotword_internal::kHotwordUnusablePrefName); 232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::~HotwordService() { 2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid HotwordService::Observe(int type, 239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationSource& source, 240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationDetails& details) { 2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The microphone monitor must be initialized as the page is loading 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // so that the state of the microphone is available when the page 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // loads. The Ok Google Hotword setting will display an error if there 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // is no microphone but this information will not be up-to-date unless 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the monitor had already been started. Furthermore, the pop up to 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // opt in to hotwording won't be available if it thinks there is no 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // microphone. There is no hard guarantee that the monitor will actually 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // be up by the time it's needed, but this is the best we can do without 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // starting it at start up which slows down start up too much. 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The content/media for microphone uses the same observer design and 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // makes use of the same audio device monitor. 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) HotwordServiceFactory::GetInstance()->UpdateMicrophoneState(); 254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 2576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::OnExtensionUninstalled( 2586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const extensions::Extension* extension, 2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UninstallReason reason) { 2616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (extension->id() != extension_misc::kHotwordExtensionId || 2646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_ != Profile::FromBrowserContext(browser_context) || 2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) !GetExtensionService(profile_)) 2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the extension wasn't uninstalled due to language change, don't try to 2696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // reinstall it. 2706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!reinstall_pending_) 2716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) InstallHotwordExtensionFromWebstore(); 2746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SetPreviousLanguagePref(); 2756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::InstallHotwordExtensionFromWebstore() { 2786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 2796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) installer_ = new extensions::WebstoreStartupInstaller( 2806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_misc::kHotwordExtensionId, 2816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_, 2826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) false, 2836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::WebstoreStandaloneInstaller::Callback()); 2846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) installer_->BeginInstall(); 2856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif 2866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::OnExtensionInstalled( 2896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const extensions::Extension* extension, 291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool is_update) { 2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (extension->id() != extension_misc::kHotwordExtensionId || 2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_ != Profile::FromBrowserContext(browser_context)) 2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the previous locale pref has never been set, set it now since 2986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // the extension has been installed. 2996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage)) 3006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SetPreviousLanguagePref(); 3016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If MaybeReinstallHotwordExtension already triggered an uninstall, we 3036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // don't want to loop and trigger another uninstall-install cycle. 3046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // However, if we arrived here via an uninstall-triggered-install (and in 3056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // that case |reinstall_pending_| will be true) then we know install 3066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // has completed and we can reset |reinstall_pending_|. 3076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!reinstall_pending_) 3086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) MaybeReinstallHotwordExtension(); 3096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) else 3106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = false; 3116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Now that the extension is installed, if the user has not selected 3136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // the preference on, make sure it is turned off. 3146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // 3156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Disabling the extension automatically on install should only occur 3166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // if the user is in the field trial for auto-install which is gated 3176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // by the IsHotwordAllowed check. The check for IsHotwordAllowed() here 3186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // can be removed once it's known that few people have manually 3196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // installed extension. 3206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (IsHotwordAllowed() && 3216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) !profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) { 3226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DisableHotwordExtension(GetExtensionService(profile_)); 3236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 3246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::MaybeReinstallHotwordExtension() { 3276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 3286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ExtensionService* extension_service = GetExtensionService(profile_); 3306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension_service) 3316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const extensions::Extension* extension = extension_service->GetExtensionById( 3346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_misc::kHotwordExtensionId, true); 3356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension) 3366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the extension is currently pending, return and we'll check again 3396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // after the install is finished. 3406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::PendingExtensionManager* pending_manager = 3416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_service->pending_extension_manager(); 3426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (pending_manager->IsIdPending(extension->id())) 3436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If there is already a pending request from HotwordService, don't try 3466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // to uninstall either. 3476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (reinstall_pending_) 3486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Check if the current locale matches the previous. If they don't match, 3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // uninstall the extension. 3526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!ShouldReinstallHotwordExtension()) 3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Ensure the call to OnExtensionUninstalled was triggered by a language 3566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // change so it's okay to reinstall. 3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = true; 3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return UninstallHotwordExtension(extension_service); 3606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::UninstallHotwordExtension( 3636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ExtensionService* extension_service) { 3646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::string16 error; 3656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension_service->UninstallExtension( 366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_misc::kHotwordExtensionId, 3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UNINSTALL_REASON_INTERNAL_MANAGEMENT, 3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&base::DoNothing), 369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &error)) { 3706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) LOG(WARNING) << "Cannot uninstall extension with id " 3716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << extension_misc::kHotwordExtensionId 3726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << ": " << error; 3736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = false; 3746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 3766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return true; 3776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsServiceAvailable() { 380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = 0; 381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine if the extension is available. 3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extensions::ExtensionSystem* system = 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extensions::ExtensionSystem::Get(profile_); 3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionService* service = system->extension_service(); 38623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // Include disabled extensions (true parameter) since it may not be enabled 38723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // if the user opted out. 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const extensions::Extension* extension = 38923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) service->GetExtensionById(extension_misc::kHotwordExtensionId, true); 390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!extension) 391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = IDS_HOTWORD_GENERIC_ERROR_MESSAGE; 3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RecordExtensionAvailabilityMetrics(service, extension); 394effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RecordLoggingMetrics(profile_); 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // NaCl and its associated functions are not available on most mobile 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not 398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // allow Hotwording anyways since it is an extension. 399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine if NaCl is available. 401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool nacl_enabled = false; 402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::FilePath path; 403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) { 404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebPluginInfo info; 405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get(); 406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (content::PluginService::GetInstance()->GetPluginInfoByPath(path, &info)) 407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) nacl_enabled = plugin_prefs->IsPluginEnabled(info); 408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!nacl_enabled) 410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE; 411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RecordErrorMetrics(error_message_); 414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Determine if the proper audio capabilities exist. 416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool audio_capture_allowed = 417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed); 418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!audio_capture_allowed || !HotwordServiceFactory::IsMicrophoneAvailable()) 419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_message_ = IDS_HOTWORD_MICROPHONE_ERROR_MESSAGE; 420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return (error_message_ == 0) && IsHotwordAllowed(); 4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsHotwordAllowed() { 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string group = base::FieldTrialList::FindFullName( 4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hotword_internal::kHotwordFieldTrialName); 4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return !group.empty() && 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) group != hotword_internal::kHotwordFieldTrialDisabledGroupName && 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DoesHotwordSupportLanguage(profile_); 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool HotwordService::IsOptedIntoAudioLogging() { 433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Do not opt the user in if the preference has not been set. 434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return 435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile_->GetPrefs()->HasPrefPath(prefs::kHotwordAudioLoggingEnabled) && 436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile_->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled); 437effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 43923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::EnableHotwordExtension( 44023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service) { 44123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (extension_service) 44223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_service->EnableExtension(extension_misc::kHotwordExtensionId); 44323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 44423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 44523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::DisableHotwordExtension( 44623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service) { 44723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (extension_service) { 44823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_service->DisableExtension( 44923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_misc::kHotwordExtensionId, 45023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::Extension::DISABLE_USER_ACTION); 45123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 45223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 45323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 45423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::OnHotwordSearchEnabledChanged( 45523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const std::string& pref_name) { 45623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK_EQ(pref_name, std::string(prefs::kHotwordSearchEnabled)); 45723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 45823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service = GetExtensionService(profile_); 45923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 46023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) EnableHotwordExtension(extension_service); 46123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) else 46223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DisableHotwordExtension(extension_service); 46323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 464010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 465010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void HotwordService::RequestHotwordSession(HotwordClient* client) { 466010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 467010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!IsServiceAvailable() || client_) 468010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 469010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 470010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) client_ = client; 471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HotwordPrivateEventService* event_service = 473010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); 474010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (event_service) 475010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) event_service->OnHotwordSessionRequested(); 476010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif 477010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 478010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 479010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void HotwordService::StopHotwordSession(HotwordClient* client) { 480010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(ENABLE_EXTENSIONS) 481010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!IsServiceAvailable()) 482010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 483010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 484010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(client_ == client); 485010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 486010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) client_ = NULL; 487010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HotwordPrivateEventService* event_service = 488010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); 489010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (event_service) 490010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) event_service->OnHotwordSessionStopped(); 491010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif 492010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 4936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::SetPreviousLanguagePref() { 4956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_->GetPrefs()->SetString(prefs::kHotwordPreviousLanguage, 4966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) GetCurrentLocale(profile_)); 4976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 4986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 4996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::ShouldReinstallHotwordExtension() { 5006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If there is no previous locale pref, then this is the first install 5016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // so no need to uninstall first. 5026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage)) 5036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 5046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string previous_locale = 5066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage); 5076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string locale = GetCurrentLocale(profile_); 5086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If it's a new locale, then the old extension should be uninstalled. 5106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return locale != previous_locale && 5116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) HotwordService::DoesHotwordSupportLanguage(profile_); 5126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 513