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