| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/voicesearch_ui.h" |
| |
| #include "base/command_line.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/path_service.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/plugins/plugin_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/hotword_service.h" |
| #include "chrome/browser/search/hotword_service_factory.h" |
| #include "chrome/browser/ui/app_list/start_page_service.h" |
| #include "chrome/browser/ui/webui/version_handler.h" |
| #include "chrome/common/chrome_content_client.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_version_info.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/public/browser/plugin_service.h" |
| #include "content/public/browser/url_data_source.h" |
| #include "content/public/browser/web_ui.h" |
| #include "content/public/browser/web_ui_data_source.h" |
| #include "content/public/browser/web_ui_message_handler.h" |
| #include "content/public/common/user_agent.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/common/extension.h" |
| #include "grit/browser_resources.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/google_chrome_strings.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "v8/include/v8.h" |
| |
| #if defined(OS_WIN) |
| #include "base/win/windows_version.h" |
| #endif |
| |
| using base::ASCIIToUTF16; |
| using content::WebUIMessageHandler; |
| |
| namespace { |
| |
| content::WebUIDataSource* CreateVoiceSearchUiHtmlSource() { |
| content::WebUIDataSource* html_source = |
| content::WebUIDataSource::Create(chrome::kChromeUIVoiceSearchHost); |
| |
| html_source->AddLocalizedString("loadingMessage", |
| IDS_VOICESEARCH_LOADING_MESSAGE); |
| html_source->AddLocalizedString("voiceSearchLongTitle", |
| IDS_VOICESEARCH_TITLE_MESSAGE); |
| |
| html_source->SetUseJsonJSFormatV2(); |
| html_source->SetJsonPath("strings.js"); |
| html_source->AddResourcePath("about_voicesearch.js", |
| IDR_ABOUT_VOICESEARCH_JS); |
| html_source->SetDefaultResource(IDR_ABOUT_VOICESEARCH_HTML); |
| return html_source; |
| } |
| |
| // Helper functions for collecting a list of key-value pairs that will |
| // be displayed. |
| void AddPair(base::ListValue* list, |
| const base::string16& key, |
| const base::string16& value) { |
| scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue()); |
| results->SetString("key", key); |
| results->SetString("value", value); |
| list->Append(results.release()); |
| } |
| |
| // Generate an empty data-pair which acts as a line break. |
| void AddLineBreak(base::ListValue* list) { |
| AddPair(list, ASCIIToUTF16(base::StringPiece()), |
| ASCIIToUTF16(base::StringPiece())); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // VoiceSearchDomHandler |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // The handler for Javascript messages for the about:flags page. |
| class VoiceSearchDomHandler : public WebUIMessageHandler { |
| public: |
| explicit VoiceSearchDomHandler(Profile* profile) : profile_(profile) {} |
| |
| virtual ~VoiceSearchDomHandler() {} |
| |
| // WebUIMessageHandler implementation. |
| virtual void RegisterMessages() OVERRIDE { |
| web_ui()->RegisterMessageCallback( |
| "requestVoiceSearchInfo", |
| base::Bind(&VoiceSearchDomHandler::HandleRequestVoiceSearchInfo, |
| base::Unretained(this))); |
| } |
| |
| private: |
| // Callback for the "requestVoiceSearchInfo" message. No arguments. |
| void HandleRequestVoiceSearchInfo(const base::ListValue* args) { |
| base::DictionaryValue voiceSearchInfo; |
| PopulatePageInformation(&voiceSearchInfo); |
| web_ui()->CallJavascriptFunction("returnVoiceSearchInfo", |
| voiceSearchInfo); |
| } |
| |
| // Fill in the data to be displayed on the page. |
| void PopulatePageInformation(base::DictionaryValue* voiceSearchInfo) { |
| // Store Key-Value pairs of about-information. |
| scoped_ptr<base::ListValue> list(new base::ListValue()); |
| |
| // Populate information. |
| AddOperatingSystemInfo(list.get()); |
| AddAudioInfo(list.get()); |
| AddLanguageInfo(list.get()); |
| AddHotwordInfo(list.get()); |
| AddHotwordExtensionInfo(list.get()); |
| AddAppListInfo(list.get()); |
| |
| // voiceSearchInfo will take ownership of list, and clean it up on |
| // destruction. |
| voiceSearchInfo->Set("voiceSearchInfo", list.release()); |
| } |
| |
| // Adds information regarding the system and chrome version info to list. |
| void AddOperatingSystemInfo(base::ListValue* list) { |
| // Obtain the Chrome version info. |
| chrome::VersionInfo version_info; |
| AddPair(list, |
| l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), |
| ASCIIToUTF16( |
| version_info.Version() + " (" + |
| chrome::VersionInfo::GetVersionStringModifier() + ")")); |
| |
| // OS version information. |
| std::string os_label = version_info.OSType(); |
| #if defined(OS_WIN) |
| base::win::OSInfo* os = base::win::OSInfo::GetInstance(); |
| switch (os->version()) { |
| case base::win::VERSION_XP: |
| os_label += " XP"; |
| break; |
| case base::win::VERSION_SERVER_2003: |
| os_label += " Server 2003 or XP Pro 64 bit"; |
| break; |
| case base::win::VERSION_VISTA: |
| os_label += " Vista or Server 2008"; |
| break; |
| case base::win::VERSION_WIN7: |
| os_label += " 7 or Server 2008 R2"; |
| break; |
| case base::win::VERSION_WIN8: |
| os_label += " 8 or Server 2012"; |
| break; |
| default: |
| os_label += " UNKNOWN"; |
| break; |
| } |
| os_label += " SP" + base::IntToString(os->service_pack().major); |
| |
| if (os->service_pack().minor > 0) |
| os_label += "." + base::IntToString(os->service_pack().minor); |
| |
| if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE) |
| os_label += " 64 bit"; |
| #endif |
| AddPair(list, |
| l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS), |
| ASCIIToUTF16(os_label)); |
| |
| AddLineBreak(list); |
| } |
| |
| // Adds information regarding audio to the list. |
| void AddAudioInfo(base::ListValue* list) { |
| // NaCl and its associated functions are not available on most mobile |
| // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not |
| // allow Hotwording anyways since it is an extension. |
| std::string nacl_enabled = "not available"; |
| #if defined(ENABLE_EXTENSIONS) |
| nacl_enabled = "No"; |
| // Determine if NaCl is available. |
| base::FilePath path; |
| if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) { |
| content::WebPluginInfo info; |
| PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get(); |
| if (content::PluginService::GetInstance()->GetPluginInfoByPath(path, |
| &info) && |
| plugin_prefs->IsPluginEnabled(info)) { |
| nacl_enabled = "Yes"; |
| } |
| } |
| #endif |
| |
| AddPair(list, ASCIIToUTF16("NaCl Enabled"), ASCIIToUTF16(nacl_enabled)); |
| |
| AddPair(list, ASCIIToUTF16("Microphone"), |
| ASCIIToUTF16( |
| HotwordServiceFactory::IsMicrophoneAvailable() ? "Yes" : "No")); |
| |
| std::string audio_capture = "No"; |
| if (profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed)) |
| audio_capture = "Yes"; |
| AddPair(list, ASCIIToUTF16("Audio Capture Allowed"), |
| ASCIIToUTF16(audio_capture)); |
| |
| AddLineBreak(list); |
| } |
| |
| // Adds information regarding languages to the list. |
| void AddLanguageInfo(base::ListValue* list) { |
| std::string locale = |
| #if defined(OS_CHROMEOS) |
| // On ChromeOS locale is per-profile. |
| profile_->GetPrefs()->GetString(prefs::kApplicationLocale); |
| #else |
| g_browser_process->GetApplicationLocale(); |
| #endif |
| AddPair(list, ASCIIToUTF16("Current Language"), ASCIIToUTF16(locale)); |
| |
| AddPair(list, ASCIIToUTF16("Hotword Previous Language"), |
| ASCIIToUTF16(profile_->GetPrefs()->GetString( |
| prefs::kHotwordPreviousLanguage))); |
| |
| AddLineBreak(list); |
| } |
| |
| // Adds information specific to the hotword configuration to the list. |
| void AddHotwordInfo(base::ListValue* list) { |
| std::string search_enabled = "No"; |
| if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) |
| search_enabled = "Yes"; |
| AddPair(list, ASCIIToUTF16("Hotword Search Enabled"), |
| ASCIIToUTF16(search_enabled)); |
| |
| std::string audio_logging_enabled = "No"; |
| HotwordService* hotword_service = |
| HotwordServiceFactory::GetForProfile(profile_); |
| if (hotword_service && hotword_service->IsOptedIntoAudioLogging()) |
| audio_logging_enabled = "Yes"; |
| AddPair(list, ASCIIToUTF16("Hotword Audio Logging Enabled"), |
| ASCIIToUTF16(audio_logging_enabled)); |
| |
| std::string group = base::FieldTrialList::FindFullName( |
| hotword_internal::kHotwordFieldTrialName); |
| AddPair(list, ASCIIToUTF16("Field trial"), ASCIIToUTF16(group)); |
| |
| AddLineBreak(list); |
| } |
| |
| // Adds information specific to the hotword extension to the list. |
| void AddHotwordExtensionInfo(base::ListValue* list) { |
| std::string version("undefined"); |
| std::string id("undefined"); |
| base::FilePath path; |
| |
| extensions::ExtensionSystem* extension_system = |
| extensions::ExtensionSystem::Get(profile_); |
| if (extension_system) { |
| ExtensionService* extension_service = |
| extension_system->extension_service(); |
| const extensions::Extension* extension = |
| extension_service->GetExtensionById( |
| extension_misc::kHotwordExtensionId, true); |
| if (extension) { |
| id = extension->id(); |
| version = extension->VersionString(); |
| path = extension->path(); |
| } |
| } |
| AddPair(list, ASCIIToUTF16("Extension Id"), |
| ASCIIToUTF16(id)); |
| AddPair(list, ASCIIToUTF16("Extension Version"), |
| ASCIIToUTF16(version)); |
| AddPair(list, ASCIIToUTF16("Extension Path"), |
| path.empty() ? ASCIIToUTF16("undefined") : path.LossyDisplayName()); |
| |
| extensions::ExtensionPrefs* extension_prefs = |
| extensions::ExtensionPrefs::Get(profile_); |
| int pref_state = -1; |
| extension_prefs->ReadPrefAsInteger(extension_misc::kHotwordExtensionId, |
| "state", &pref_state); |
| std::string state; |
| switch (pref_state) { |
| case extensions::Extension::DISABLED: |
| state = "DISABLED"; |
| break; |
| case extensions::Extension::ENABLED: |
| state = "ENABLED"; |
| break; |
| case extensions::Extension::EXTERNAL_EXTENSION_UNINSTALLED: |
| state = "EXTERNAL_EXTENSION_UNINSTALLED"; |
| break; |
| default: |
| state = "undefined"; |
| } |
| |
| AddPair(list, ASCIIToUTF16("Extension State"), ASCIIToUTF16(state)); |
| |
| AddLineBreak(list); |
| } |
| |
| // Adds information specific to voice search in the app launcher to the list. |
| void AddAppListInfo(base::ListValue* list) { |
| #if defined (ENABLE_APP_LIST) |
| std::string state = "No Start Page Service"; |
| app_list::StartPageService* start_page_service = |
| app_list::StartPageService::Get(profile_); |
| if (start_page_service) { |
| app_list::SpeechRecognitionState speech_state = |
| start_page_service->state(); |
| switch (speech_state) { |
| case app_list::SPEECH_RECOGNITION_OFF: |
| state = "SPEECH_RECOGNITION_OFF"; |
| break; |
| case app_list::SPEECH_RECOGNITION_READY: |
| state = "SPEECH_RECOGNITION_READY"; |
| break; |
| case app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING: |
| state = "SPEECH_RECOGNITION_HOTWORD_LISTENING"; |
| break; |
| case app_list::SPEECH_RECOGNITION_RECOGNIZING: |
| state = "SPEECH_RECOGNITION_RECOGNIZING"; |
| break; |
| case app_list::SPEECH_RECOGNITION_IN_SPEECH: |
| state = "SPEECH_RECOGNITION_IN_SPEECH"; |
| break; |
| case app_list::SPEECH_RECOGNITION_STOPPING: |
| state = "SPEECH_RECOGNITION_STOPPING"; |
| break; |
| case app_list::SPEECH_RECOGNITION_NETWORK_ERROR: |
| state = "SPEECH_RECOGNITION_NETWORK_ERROR"; |
| break; |
| default: |
| state = "undefined"; |
| } |
| } |
| AddPair(list, ASCIIToUTF16("Start Page State"), ASCIIToUTF16(state)); |
| #endif |
| } |
| |
| Profile* profile_; |
| |
| DISALLOW_COPY_AND_ASSIGN(VoiceSearchDomHandler); |
| }; |
| |
| } // namespace |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // VoiceSearchUI |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| VoiceSearchUI::VoiceSearchUI(content::WebUI* web_ui) |
| : content::WebUIController(web_ui) { |
| Profile* profile = Profile::FromWebUI(web_ui); |
| web_ui->AddMessageHandler(new VoiceSearchDomHandler(profile)); |
| |
| // Set up the about:voicesearch source. |
| content::WebUIDataSource::Add(profile, CreateVoiceSearchUiHtmlSource()); |
| } |
| |
| VoiceSearchUI::~VoiceSearchUI() {} |