blob: 03e79a3f80b2c04326b305c2f12a2bd4efefdabb [file] [log] [blame]
// 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() {}