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) 703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/command_line.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/i18n/case_conversion.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/field_trial.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/path_service.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/browser_process.h" 14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/chrome_notification_types.h" 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/pending_extension_manager.h" 186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/updater/extension_updater.h" 196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/extensions/webstore_startup_installer.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/plugins/plugin_prefs.h" 218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/search/hotword_service_factory.h" 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/extensions/application_launch.h" 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h" 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h" 2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h" 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h" 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/plugin_service.h" 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/common/webplugininfo.h" 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/uninstall_reason.h" 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension.h" 366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/common/one_shot_event.h" 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using extensions::BrowserContextKeyedAPIFactory; 40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)using extensions::HotwordPrivateEventService; 41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Allowed languages for hotwording. 45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstatic const char* kSupportedLocales[] = { 46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch "en", 476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "de", 486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "fr", 496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "ru" 50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}; 51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the state of the hotword preference. 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end. 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordEnabled { 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UNSET = 0, // The hotword preference has not been set. 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ENABLED, // The hotword preference is enabled. 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISABLED, // The hotword preference is disabled. 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_ENABLED_METRICS 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Enum describing the availability state of the hotword extension. 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the end. 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum HotwordExtensionAvailability { 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UNAVAILABLE = 0, 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AVAILABLE, 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PENDING_DOWNLOAD, 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISABLED_EXTENSION, 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Enum describing the types of errors that can arise when determining 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// if hotwording can be used. NO_ERROR is used so it can be seen how often 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// errors arise relative to when they do not. 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This is used for UMA stats -- do not reorder or delete items; only add to 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// the end. 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)enum HotwordError { 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NO_HOTWORD_ERROR = 0, 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GENERIC_HOTWORD_ERROR, 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NACL_HOTWORD_ERROR, 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MICROPHONE_HOTWORD_ERROR, 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NUM_HOTWORD_ERROR_METRICS 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RecordExtensionAvailabilityMetrics( 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionService* service, 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const extensions::Extension* extension) { 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HotwordExtensionAvailability availability_state = UNAVAILABLE; 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (extension) { 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = AVAILABLE; 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (service->pending_extension_manager() && 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) service->pending_extension_manager()->IsIdPending( 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extension_misc::kHotwordExtensionId)) { 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = PENDING_DOWNLOAD; 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (!service->IsExtensionEnabled( 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extension_misc::kHotwordExtensionId)) { 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state = DISABLED_EXTENSION; 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordExtensionAvailability", 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) availability_state, 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_EXTENSION_AVAILABILITY_METRICS); 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid RecordLoggingMetrics(Profile* profile) { 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If the user is not opted in to hotword voice search, the audio logging 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // metric is not valid so it is not recorded. 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!profile->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch UMA_HISTOGRAM_BOOLEAN( 112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch "Hotword.HotwordAudioLogging", 113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled)); 114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void RecordErrorMetrics(int error_message) { 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) HotwordError error = NO_HOTWORD_ERROR; 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (error_message) { 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case IDS_HOTWORD_GENERIC_ERROR_MESSAGE: 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = GENERIC_HOTWORD_ERROR; 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE: 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = NACL_HOTWORD_ERROR; 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case IDS_HOTWORD_MICROPHONE_ERROR_MESSAGE: 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error = MICROPHONE_HOTWORD_ERROR; 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) break; 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error = NO_HOTWORD_ERROR; 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.HotwordError", 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error, 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NUM_HOTWORD_ERROR_METRICS); 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)ExtensionService* GetExtensionService(Profile* profile) { 138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 13923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::ExtensionSystem* extension_system = 14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::ExtensionSystem::Get(profile); 142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return extension_system ? extension_system->extension_service() : NULL; 14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 1456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)std::string GetCurrentLocale(Profile* profile) { 1466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS) 14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) std::string profile_locale = 1486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile->GetPrefs()->GetString(prefs::kApplicationLocale); 14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!profile_locale.empty()) { 15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // On ChromeOS locale is per-profile, but only if set. 15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return profile_locale; 15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif 15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return g_browser_process->GetApplicationLocale(); 1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace hotword_internal { 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Constants for the hotword field trial. 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialName[] = "VoiceTrigger"; 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHotwordFieldTrialDisabledGroupName[] = "Disabled"; 163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Old preference constant. 164c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kHotwordUnusablePrefName[] = "hotword.search_enabled"; 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace hotword_internal 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { 1696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string normalized_locale = 1706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) l10n_util::NormalizeLocale(GetCurrentLocale(profile)); 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::StringToLowerASCII(&normalized_locale); 172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (size_t i = 0; i < arraysize(kSupportedLocales); i++) { 1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (normalized_locale.compare(0, 2, kSupportedLocales[i]) == 0) 175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return true; 176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return false; 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// static 18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool HotwordService::IsExperimentalHotwordingEnabled() { 18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CommandLine* command_line = CommandLine::ForCurrentProcess(); 18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return command_line->HasSwitch(switches::kEnableExperimentalHotwording); 18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::HotwordService(Profile* profile) 187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) : profile_(profile), 1886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_registry_observer_(this), 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_(NULL), 1906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_message_(0), 1916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_(false), 1926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_factory_(this) { 1936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This will be called during profile initialization which is a good time 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // to check the user's hotword state. 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HotwordEnabled enabled_state = UNSET; 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (profile_->GetPrefs()->HasPrefPath(prefs::kHotwordSearchEnabled)) { 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enabled_state = ENABLED; 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enabled_state = DISABLED; 20223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } else { 20323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // If the preference has not been set the hotword extension should 2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // not be running. However, this should only be done if auto-install 2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // is enabled which is gated through the IsHotwordAllowed check. 2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (IsHotwordAllowed()) 2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch DisableHotwordExtension(GetExtensionService(profile_)); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Hotword.Enabled", enabled_state, 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NUM_HOTWORD_ENABLED_METRICS); 21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) pref_registrar_.Init(profile_->GetPrefs()); 21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) pref_registrar_.Add( 21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) prefs::kHotwordSearchEnabled, 21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::Bind(&HotwordService::OnHotwordSearchEnabledChanged, 21623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::Unretained(this))); 217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch registrar_.Add(this, 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chrome::NOTIFICATION_BROWSER_WINDOW_READY, 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) content::NotificationService::AllSources()); 221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 2226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::ExtensionSystem::Get(profile_)->ready().Post( 2236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) FROM_HERE, 2246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind(base::IgnoreResult( 2256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) &HotwordService::MaybeReinstallHotwordExtension), 2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_factory_.GetWeakPtr())); 2276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Clear the old user pref because it became unusable. 229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // TODO(rlp): Remove this code per crbug.com/358789. 230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (profile_->GetPrefs()->HasPrefPath( 231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch hotword_internal::kHotwordUnusablePrefName)) { 232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch profile_->GetPrefs()->ClearPref(hotword_internal::kHotwordUnusablePrefName); 233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)HotwordService::~HotwordService() { 2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid HotwordService::Observe(int type, 240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationSource& source, 241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationDetails& details) { 2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The microphone monitor must be initialized as the page is loading 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // so that the state of the microphone is available when the page 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // loads. The Ok Google Hotword setting will display an error if there 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // is no microphone but this information will not be up-to-date unless 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the monitor had already been started. Furthermore, the pop up to 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // opt in to hotwording won't be available if it thinks there is no 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // microphone. There is no hard guarantee that the monitor will actually 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // be up by the time it's needed, but this is the best we can do without 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // starting it at start up which slows down start up too much. 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The content/media for microphone uses the same observer design and 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // makes use of the same audio device monitor. 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) HotwordServiceFactory::GetInstance()->UpdateMicrophoneState(); 255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 2586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::OnExtensionUninstalled( 2596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const extensions::Extension* extension, 2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UninstallReason reason) { 2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 2636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (extension->id() != extension_misc::kHotwordExtensionId || 2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_ != Profile::FromBrowserContext(browser_context) || 2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) !GetExtensionService(profile_)) 2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the extension wasn't uninstalled due to language change, don't try to 2706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // reinstall it. 2716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!reinstall_pending_) 2726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) InstallHotwordExtensionFromWebstore(); 2756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SetPreviousLanguagePref(); 2766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::InstallHotwordExtensionFromWebstore() { 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)} 2866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::OnExtensionInstalled( 2886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const extensions::Extension* extension, 290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool is_update) { 2916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (extension->id() != extension_misc::kHotwordExtensionId || 2936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_ != Profile::FromBrowserContext(browser_context)) 2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the previous locale pref has never been set, set it now since 2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // the extension has been installed. 2986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage)) 2996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SetPreviousLanguagePref(); 3006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If MaybeReinstallHotwordExtension already triggered an uninstall, we 3026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // don't want to loop and trigger another uninstall-install cycle. 3036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // However, if we arrived here via an uninstall-triggered-install (and in 3046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // that case |reinstall_pending_| will be true) then we know install 3056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // has completed and we can reset |reinstall_pending_|. 3066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!reinstall_pending_) 3076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) MaybeReinstallHotwordExtension(); 3086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) else 3096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = false; 3106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Now that the extension is installed, if the user has not selected 3126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // the preference on, make sure it is turned off. 3136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // 3146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Disabling the extension automatically on install should only occur 3156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // if the user is in the field trial for auto-install which is gated 3166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // by the IsHotwordAllowed check. The check for IsHotwordAllowed() here 3176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // can be removed once it's known that few people have manually 3186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // installed extension. 3196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (IsHotwordAllowed() && 3206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) !profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) { 3216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DisableHotwordExtension(GetExtensionService(profile_)); 3226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 3236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::MaybeReinstallHotwordExtension() { 3266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 3276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ExtensionService* extension_service = GetExtensionService(profile_); 3296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension_service) 3306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const extensions::Extension* extension = extension_service->GetExtensionById( 3336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_misc::kHotwordExtensionId, true); 3346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension) 3356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If the extension is currently pending, return and we'll check again 3386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // after the install is finished. 3396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::PendingExtensionManager* pending_manager = 3406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_service->pending_extension_manager(); 3416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (pending_manager->IsIdPending(extension->id())) 3426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If there is already a pending request from HotwordService, don't try 3456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // to uninstall either. 3466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (reinstall_pending_) 3476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Check if the current locale matches the previous. If they don't match, 3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // uninstall the extension. 3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!ShouldReinstallHotwordExtension()) 3526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Ensure the call to OnExtensionUninstalled was triggered by a language 3556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // change so it's okay to reinstall. 3566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = true; 3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return UninstallHotwordExtension(extension_service); 3596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::UninstallHotwordExtension( 3626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ExtensionService* extension_service) { 3636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::string16 error; 3646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!extension_service->UninstallExtension( 365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_misc::kHotwordExtensionId, 3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UNINSTALL_REASON_INTERNAL_MANAGEMENT, 3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&base::DoNothing), 368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &error)) { 3696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) LOG(WARNING) << "Cannot uninstall extension with id " 3706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << extension_misc::kHotwordExtensionId 3716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << ": " << error; 3726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) reinstall_pending_ = false; 3736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 3746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 3756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return true; 3766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsServiceAvailable() { 379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = 0; 380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine if the extension is available. 3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extensions::ExtensionSystem* system = 3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extensions::ExtensionSystem::Get(profile_); 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionService* service = system->extension_service(); 38523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // Include disabled extensions (true parameter) since it may not be enabled 38623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // if the user opted out. 3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::string extensionId; 3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (IsExperimentalHotwordingEnabled()) { 3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(amistry): Handle reloading on language change as the old extension 3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // does. 3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extensionId = extension_misc::kHotwordSharedModuleId; 3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extensionId = extension_misc::kHotwordExtensionId; 3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const extensions::Extension* extension = 3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci service->GetExtensionById(extensionId, true); 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!extension) 398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = IDS_HOTWORD_GENERIC_ERROR_MESSAGE; 3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RecordExtensionAvailabilityMetrics(service, extension); 401effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RecordLoggingMetrics(profile_); 4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine if NaCl is available. 404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool nacl_enabled = false; 405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::FilePath path; 406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) { 407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebPluginInfo info; 408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get(); 409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (content::PluginService::GetInstance()->GetPluginInfoByPath(path, &info)) 410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) nacl_enabled = plugin_prefs->IsPluginEnabled(info); 411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!nacl_enabled) 413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) error_message_ = IDS_HOTWORD_NACL_DISABLED_ERROR_MESSAGE; 414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RecordErrorMetrics(error_message_); 416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Determine if the proper audio capabilities exist. 418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool audio_capture_allowed = 419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed); 420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!audio_capture_allowed || !HotwordServiceFactory::IsMicrophoneAvailable()) 421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_message_ = IDS_HOTWORD_MICROPHONE_ERROR_MESSAGE; 422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return (error_message_ == 0) && IsHotwordAllowed(); 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HotwordService::IsHotwordAllowed() { 4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string group = base::FieldTrialList::FindFullName( 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hotword_internal::kHotwordFieldTrialName); 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return !group.empty() && 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) group != hotword_internal::kHotwordFieldTrialDisabledGroupName && 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DoesHotwordSupportLanguage(profile_); 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool HotwordService::IsOptedIntoAudioLogging() { 435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Do not opt the user in if the preference has not been set. 436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return 437effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile_->GetPrefs()->HasPrefPath(prefs::kHotwordAudioLoggingEnabled) && 438effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch profile_->GetPrefs()->GetBoolean(prefs::kHotwordAudioLoggingEnabled); 439effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 440effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 44123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::EnableHotwordExtension( 44223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service) { 44323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (extension_service) 44423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_service->EnableExtension(extension_misc::kHotwordExtensionId); 44523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 44623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 44723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::DisableHotwordExtension( 44823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service) { 44923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (extension_service) { 45023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_service->DisableExtension( 45123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extension_misc::kHotwordExtensionId, 45223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) extensions::Extension::DISABLE_USER_ACTION); 45323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 45423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 45523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HotwordService::LaunchHotwordAudioVerificationApp( 4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const LaunchMode& launch_mode) { 4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci hotword_audio_verification_launch_mode_ = launch_mode; 4591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ExtensionService* extension_service = GetExtensionService(profile_); 4611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!extension_service) 4621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 4631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const extensions::Extension* extension = extension_service->GetExtensionById( 4641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extension_misc::kHotwordAudioVerificationAppId, true); 4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!extension) 4661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 4671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci OpenApplication(AppLaunchParams( 4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci profile_, extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); 4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciHotwordService::LaunchMode 4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciHotwordService::GetHotwordAudioVerificationLaunchMode() { 4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return hotword_audio_verification_launch_mode_; 4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 47723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HotwordService::OnHotwordSearchEnabledChanged( 47823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const std::string& pref_name) { 47923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK_EQ(pref_name, std::string(prefs::kHotwordSearchEnabled)); 48023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 48123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) ExtensionService* extension_service = GetExtensionService(profile_); 48223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) 48323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) EnableHotwordExtension(extension_service); 48423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) else 48523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DisableHotwordExtension(extension_service); 48623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 487010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 488010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void HotwordService::RequestHotwordSession(HotwordClient* client) { 48903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!IsServiceAvailable() || (client_ && client_ != client)) 490010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 491010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 492010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) client_ = client; 493010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 494010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HotwordPrivateEventService* event_service = 495010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); 496010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (event_service) 497010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) event_service->OnHotwordSessionRequested(); 498010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 499010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 500010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void HotwordService::StopHotwordSession(HotwordClient* client) { 501010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!IsServiceAvailable()) 502010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 503010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 504010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(client_ == client); 505010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 506010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) client_ = NULL; 507010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HotwordPrivateEventService* event_service = 508010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); 509010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (event_service) 510010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) event_service->OnHotwordSessionStopped(); 511010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 5126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void HotwordService::SetPreviousLanguagePref() { 5146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_->GetPrefs()->SetString(prefs::kHotwordPreviousLanguage, 5156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) GetCurrentLocale(profile_)); 5166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 5176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool HotwordService::ShouldReinstallHotwordExtension() { 5196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If there is no previous locale pref, then this is the first install 5206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // so no need to uninstall first. 5216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage)) 5226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 5236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string previous_locale = 5256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) profile_->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage); 5266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) std::string locale = GetCurrentLocale(profile_); 5276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 5286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // If it's a new locale, then the old extension should be uninstalled. 5296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return locale != previous_locale && 5306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) HotwordService::DoesHotwordSupportLanguage(profile_); 5316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 532