Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / webui / voice_search_ui.cc
blob80eaa52abcbf5d66d727683219a9f7830ac0b8bc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/voice_search_ui.h"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/path_service.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/plugins/plugin_prefs.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/search/hotword_service.h"
22 #include "chrome/browser/search/hotword_service_factory.h"
23 #include "chrome/browser/ui/app_list/start_page_service.h"
24 #include "chrome/browser/ui/webui/version_handler.h"
25 #include "chrome/common/channel_info.h"
26 #include "chrome/common/chrome_content_client.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/extensions/extension_constants.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/grit/chromium_strings.h"
32 #include "chrome/grit/generated_resources.h"
33 #include "components/version_info/version_info.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/plugin_service.h"
36 #include "content/public/browser/url_data_source.h"
37 #include "content/public/browser/web_ui.h"
38 #include "content/public/browser/web_ui_data_source.h"
39 #include "content/public/browser/web_ui_message_handler.h"
40 #include "content/public/common/user_agent.h"
41 #include "extensions/browser/extension_prefs.h"
42 #include "extensions/browser/extension_system.h"
43 #include "extensions/common/extension.h"
44 #include "grit/browser_resources.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "v8/include/v8.h"
48 #if defined(OS_WIN)
49 #include "base/win/windows_version.h"
50 #endif
52 using base::ASCIIToUTF16;
53 using content::WebUIMessageHandler;
55 namespace {
57 content::WebUIDataSource* CreateVoiceSearchUiHtmlSource() {
58 content::WebUIDataSource* html_source =
59 content::WebUIDataSource::Create(chrome::kChromeUIVoiceSearchHost);
61 html_source->AddLocalizedString("loadingMessage",
62 IDS_VOICESEARCH_LOADING_MESSAGE);
63 html_source->AddLocalizedString("voiceSearchLongTitle",
64 IDS_VOICESEARCH_TITLE_MESSAGE);
66 html_source->SetJsonPath("strings.js");
67 html_source->AddResourcePath("about_voicesearch.js",
68 IDR_ABOUT_VOICESEARCH_JS);
69 html_source->SetDefaultResource(IDR_ABOUT_VOICESEARCH_HTML);
70 return html_source;
73 // Helper functions for collecting a list of key-value pairs that will
74 // be displayed.
75 void AddPair16(base::ListValue* list,
76 const base::string16& key,
77 const base::string16& value) {
78 scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue());
79 results->SetString("key", key);
80 results->SetString("value", value);
81 list->Append(results.release());
84 void AddPair(base::ListValue* list,
85 const base::StringPiece& key,
86 const base::StringPiece& value) {
87 AddPair16(list, UTF8ToUTF16(key), UTF8ToUTF16(value));
90 void AddPairBool(base::ListValue* list,
91 const base::StringPiece& key,
92 bool value) {
93 AddPair(list, key, value ? "Yes" : "No");
96 // Generate an empty data-pair which acts as a line break.
97 void AddLineBreak(base::ListValue* list) {
98 AddPair(list, "", "");
101 void AddSharedModulePlatformsOnFileThread(base::ListValue* list,
102 const base::FilePath& path,
103 base::Closure callback) {
104 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
106 if (!path.empty()) {
107 // Display available platforms for shared module.
108 base::FilePath platforms_path = path.AppendASCII("_platform_specific");
109 base::FileEnumerator enumerator(
110 platforms_path, false, base::FileEnumerator::DIRECTORIES);
111 base::string16 files;
112 for (base::FilePath name = enumerator.Next();
113 !name.empty();
114 name = enumerator.Next()) {
115 files += name.BaseName().LossyDisplayName() + ASCIIToUTF16(" ");
117 AddPair16(list,
118 ASCIIToUTF16("Shared Module Platforms"),
119 files.empty() ? ASCIIToUTF16("undefined") : files);
120 AddLineBreak(list);
123 content::BrowserThread::PostTask(content::BrowserThread::UI,
124 FROM_HERE,
125 callback);
128 ////////////////////////////////////////////////////////////////////////////////
130 // VoiceSearchDomHandler
132 ////////////////////////////////////////////////////////////////////////////////
134 // The handler for Javascript messages for the about:flags page.
135 class VoiceSearchDomHandler : public WebUIMessageHandler {
136 public:
137 explicit VoiceSearchDomHandler(Profile* profile)
138 : profile_(profile),
139 weak_factory_(this) {}
141 ~VoiceSearchDomHandler() override {}
143 // WebUIMessageHandler implementation.
144 void RegisterMessages() override {
145 web_ui()->RegisterMessageCallback(
146 "requestVoiceSearchInfo",
147 base::Bind(&VoiceSearchDomHandler::HandleRequestVoiceSearchInfo,
148 base::Unretained(this)));
151 private:
152 // Callback for the "requestVoiceSearchInfo" message. No arguments.
153 void HandleRequestVoiceSearchInfo(const base::ListValue* args) {
154 PopulatePageInformation();
157 void ReturnVoiceSearchInfo(scoped_ptr<base::ListValue> info) {
158 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
159 DCHECK(info);
160 base::DictionaryValue voiceSearchInfo;
161 voiceSearchInfo.Set("voiceSearchInfo", info.release());
162 web_ui()->CallJavascriptFunction("returnVoiceSearchInfo", voiceSearchInfo);
165 // Fill in the data to be displayed on the page.
166 void PopulatePageInformation() {
167 // Store Key-Value pairs of about-information.
168 scoped_ptr<base::ListValue> list(new base::ListValue());
170 // Populate information.
171 AddOperatingSystemInfo(list.get());
172 AddAudioInfo(list.get());
173 AddLanguageInfo(list.get());
174 AddHotwordInfo(list.get());
175 AddAppListInfo(list.get());
177 AddExtensionInfo(extension_misc::kHotwordNewExtensionId,
178 "Extension",
179 list.get());
181 AddExtensionInfo(extension_misc::kHotwordSharedModuleId,
182 "Shared Module",
183 list.get());
185 base::FilePath path;
186 extensions::ExtensionSystem* extension_system =
187 extensions::ExtensionSystem::Get(profile_);
188 if (extension_system) {
189 ExtensionService* extension_service =
190 extension_system->extension_service();
191 const extensions::Extension* extension =
192 extension_service->GetExtensionById(
193 extension_misc::kHotwordSharedModuleId, true);
194 if (extension)
195 path = extension->path();
197 base::ListValue* raw_list = list.get();
198 content::BrowserThread::PostTask(
199 content::BrowserThread::FILE,
200 FROM_HERE,
201 base::Bind(
202 &AddSharedModulePlatformsOnFileThread,
203 raw_list,
204 path,
205 base::Bind(&VoiceSearchDomHandler::ReturnVoiceSearchInfo,
206 weak_factory_.GetWeakPtr(),
207 base::Passed(list.Pass()))));
210 // Adds information regarding the system and chrome version info to list.
211 void AddOperatingSystemInfo(base::ListValue* list) {
212 // Obtain the Chrome version info.
213 AddPair(list,
214 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
215 version_info::GetVersionNumber() + " (" +
216 chrome::GetChannelString() + ")");
218 // OS version information.
219 std::string os_label = version_info::GetOSType();
220 #if defined(OS_WIN)
221 base::win::OSInfo* os = base::win::OSInfo::GetInstance();
222 switch (os->version()) {
223 case base::win::VERSION_XP:
224 os_label += " XP";
225 break;
226 case base::win::VERSION_SERVER_2003:
227 os_label += " Server 2003 or XP Pro 64 bit";
228 break;
229 case base::win::VERSION_VISTA:
230 os_label += " Vista or Server 2008";
231 break;
232 case base::win::VERSION_WIN7:
233 os_label += " 7 or Server 2008 R2";
234 break;
235 case base::win::VERSION_WIN8:
236 os_label += " 8 or Server 2012";
237 break;
238 default:
239 os_label += " UNKNOWN";
240 break;
242 os_label += " SP" + base::IntToString(os->service_pack().major);
244 if (os->service_pack().minor > 0)
245 os_label += "." + base::IntToString(os->service_pack().minor);
247 if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE)
248 os_label += " 64 bit";
249 #endif
250 AddPair(list, l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_OS), os_label);
252 AddLineBreak(list);
255 // Adds information regarding audio to the list.
256 void AddAudioInfo(base::ListValue* list) {
257 // NaCl and its associated functions are not available on most mobile
258 // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not
259 // allow Hotwording anyways since it is an extension.
260 std::string nacl_enabled = "not available";
261 #if defined(ENABLE_EXTENSIONS)
262 nacl_enabled = "No";
263 // Determine if NaCl is available.
264 base::FilePath path;
265 if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) {
266 content::WebPluginInfo info;
267 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get();
268 if (content::PluginService::GetInstance()->GetPluginInfoByPath(path,
269 &info) &&
270 plugin_prefs->IsPluginEnabled(info)) {
271 nacl_enabled = "Yes";
274 #endif
276 AddPair(list, "NaCl Enabled", nacl_enabled);
278 HotwordService* hotword_service =
279 HotwordServiceFactory::GetForProfile(profile_);
280 AddPairBool(list, "Microphone Present",
281 hotword_service && hotword_service->microphone_available());
283 AddPairBool(list, "Audio Capture Allowed",
284 profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed));
286 AddLineBreak(list);
289 // Adds information regarding languages to the list.
290 void AddLanguageInfo(base::ListValue* list) {
291 std::string locale =
292 #if defined(OS_CHROMEOS)
293 // On ChromeOS locale is per-profile.
294 profile_->GetPrefs()->GetString(prefs::kApplicationLocale);
295 #else
296 g_browser_process->GetApplicationLocale();
297 #endif
298 AddPair(list, "Current Language", locale);
300 AddPair(list,
301 "Hotword Previous Language",
302 profile_->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
304 AddLineBreak(list);
307 // Adds information specific to the hotword configuration to the list.
308 void AddHotwordInfo(base::ListValue* list) {
309 HotwordService* hotword_service =
310 HotwordServiceFactory::GetForProfile(profile_);
311 AddPairBool(list, "Hotword Module Installable",
312 hotword_service && hotword_service->IsHotwordAllowed());
314 AddPairBool(list, "Hotword Search Enabled",
315 profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled));
317 AddPairBool(
318 list, "Always-on Hotword Search Enabled",
319 profile_->GetPrefs()->GetBoolean(prefs::kHotwordAlwaysOnSearchEnabled));
321 AddPairBool(list, "Hotword Audio Logging Enabled",
322 hotword_service && hotword_service->IsOptedIntoAudioLogging());
324 AddLineBreak(list);
327 // Adds information specific to an extension to the list.
328 void AddExtensionInfo(const std::string& extension_id,
329 const std::string& name_prefix,
330 base::ListValue* list) {
331 DCHECK(!name_prefix.empty());
332 std::string version("undefined");
333 std::string id("undefined");
334 base::FilePath path;
336 extensions::ExtensionSystem* extension_system =
337 extensions::ExtensionSystem::Get(profile_);
338 if (extension_system) {
339 ExtensionService* extension_service =
340 extension_system->extension_service();
341 const extensions::Extension* extension =
342 extension_service->GetExtensionById(extension_id, true);
343 if (extension) {
344 id = extension->id();
345 version = extension->VersionString();
346 path = extension->path();
349 AddPair(list, name_prefix + " Id", id);
350 AddPair(list, name_prefix + " Version", version);
351 AddPair16(list,
352 ASCIIToUTF16(name_prefix + " Path"),
353 path.empty() ?
354 ASCIIToUTF16("undefined") : path.LossyDisplayName());
356 extensions::ExtensionPrefs* extension_prefs =
357 extensions::ExtensionPrefs::Get(profile_);
358 int pref_state = -1;
359 extension_prefs->ReadPrefAsInteger(extension_id, "state", &pref_state);
360 std::string state;
361 switch (pref_state) {
362 case extensions::Extension::DISABLED:
363 state = "DISABLED";
364 break;
365 case extensions::Extension::ENABLED:
366 state = "ENABLED";
367 break;
368 case extensions::Extension::EXTERNAL_EXTENSION_UNINSTALLED:
369 state = "EXTERNAL_EXTENSION_UNINSTALLED";
370 break;
371 default:
372 state = "undefined";
375 AddPair(list, name_prefix + " State", state);
377 AddLineBreak(list);
380 // Adds information specific to voice search in the app launcher to the list.
381 void AddAppListInfo(base::ListValue* list) {
382 #if defined (ENABLE_APP_LIST)
383 std::string state = "No Start Page Service";
384 app_list::StartPageService* start_page_service =
385 app_list::StartPageService::Get(profile_);
386 if (start_page_service) {
387 app_list::SpeechRecognitionState speech_state =
388 start_page_service->state();
389 switch (speech_state) {
390 case app_list::SPEECH_RECOGNITION_OFF:
391 state = "SPEECH_RECOGNITION_OFF";
392 break;
393 case app_list::SPEECH_RECOGNITION_READY:
394 state = "SPEECH_RECOGNITION_READY";
395 break;
396 case app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING:
397 state = "SPEECH_RECOGNITION_HOTWORD_LISTENING";
398 break;
399 case app_list::SPEECH_RECOGNITION_RECOGNIZING:
400 state = "SPEECH_RECOGNITION_RECOGNIZING";
401 break;
402 case app_list::SPEECH_RECOGNITION_IN_SPEECH:
403 state = "SPEECH_RECOGNITION_IN_SPEECH";
404 break;
405 case app_list::SPEECH_RECOGNITION_STOPPING:
406 state = "SPEECH_RECOGNITION_STOPPING";
407 break;
408 case app_list::SPEECH_RECOGNITION_NETWORK_ERROR:
409 state = "SPEECH_RECOGNITION_NETWORK_ERROR";
410 break;
411 default:
412 state = "undefined";
415 AddPair(list, "Start Page State", state);
416 AddLineBreak(list);
417 #endif
420 Profile* profile_;
421 base::WeakPtrFactory<VoiceSearchDomHandler> weak_factory_;
423 DISALLOW_COPY_AND_ASSIGN(VoiceSearchDomHandler);
426 } // namespace
428 ///////////////////////////////////////////////////////////////////////////////
430 // VoiceSearchUI
432 ///////////////////////////////////////////////////////////////////////////////
434 VoiceSearchUI::VoiceSearchUI(content::WebUI* web_ui)
435 : content::WebUIController(web_ui) {
436 Profile* profile = Profile::FromWebUI(web_ui);
437 web_ui->AddMessageHandler(new VoiceSearchDomHandler(profile));
439 // Set up the about:voicesearch source.
440 content::WebUIDataSource::Add(profile, CreateVoiceSearchUiHtmlSource());
443 VoiceSearchUI::~VoiceSearchUI() {}