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/voicesearch_ui.h"
7 #include "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/path_service.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/plugins/plugin_prefs.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search/hotword_service.h"
18 #include "chrome/browser/search/hotword_service_factory.h"
19 #include "chrome/browser/ui/app_list/start_page_service.h"
20 #include "chrome/browser/ui/webui/version_handler.h"
21 #include "chrome/common/chrome_content_client.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_version_info.h"
24 #include "chrome/common/extensions/extension_constants.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/chromium_strings.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/grit/google_chrome_strings.h"
30 #include "content/public/browser/plugin_service.h"
31 #include "content/public/browser/url_data_source.h"
32 #include "content/public/browser/web_ui.h"
33 #include "content/public/browser/web_ui_data_source.h"
34 #include "content/public/browser/web_ui_message_handler.h"
35 #include "content/public/common/user_agent.h"
36 #include "extensions/browser/extension_prefs.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/common/extension.h"
39 #include "grit/browser_resources.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "v8/include/v8.h"
44 #include "base/win/windows_version.h"
47 using base::ASCIIToUTF16
;
48 using content::WebUIMessageHandler
;
52 content::WebUIDataSource
* CreateVoiceSearchUiHtmlSource() {
53 content::WebUIDataSource
* html_source
=
54 content::WebUIDataSource::Create(chrome::kChromeUIVoiceSearchHost
);
56 html_source
->AddLocalizedString("loadingMessage",
57 IDS_VOICESEARCH_LOADING_MESSAGE
);
58 html_source
->AddLocalizedString("voiceSearchLongTitle",
59 IDS_VOICESEARCH_TITLE_MESSAGE
);
61 html_source
->SetJsonPath("strings.js");
62 html_source
->AddResourcePath("about_voicesearch.js",
63 IDR_ABOUT_VOICESEARCH_JS
);
64 html_source
->SetDefaultResource(IDR_ABOUT_VOICESEARCH_HTML
);
68 // Helper functions for collecting a list of key-value pairs that will
70 void AddPair(base::ListValue
* list
,
71 const base::string16
& key
,
72 const base::string16
& value
) {
73 scoped_ptr
<base::DictionaryValue
> results(new base::DictionaryValue());
74 results
->SetString("key", key
);
75 results
->SetString("value", value
);
76 list
->Append(results
.release());
79 // Generate an empty data-pair which acts as a line break.
80 void AddLineBreak(base::ListValue
* list
) {
81 AddPair(list
, ASCIIToUTF16(base::StringPiece()),
82 ASCIIToUTF16(base::StringPiece()));
85 ////////////////////////////////////////////////////////////////////////////////
87 // VoiceSearchDomHandler
89 ////////////////////////////////////////////////////////////////////////////////
91 // The handler for Javascript messages for the about:flags page.
92 class VoiceSearchDomHandler
: public WebUIMessageHandler
{
94 explicit VoiceSearchDomHandler(Profile
* profile
) : profile_(profile
) {}
96 virtual ~VoiceSearchDomHandler() {}
98 // WebUIMessageHandler implementation.
99 virtual void RegisterMessages() override
{
100 web_ui()->RegisterMessageCallback(
101 "requestVoiceSearchInfo",
102 base::Bind(&VoiceSearchDomHandler::HandleRequestVoiceSearchInfo
,
103 base::Unretained(this)));
107 // Callback for the "requestVoiceSearchInfo" message. No arguments.
108 void HandleRequestVoiceSearchInfo(const base::ListValue
* args
) {
109 base::DictionaryValue voiceSearchInfo
;
110 PopulatePageInformation(&voiceSearchInfo
);
111 web_ui()->CallJavascriptFunction("returnVoiceSearchInfo",
115 // Fill in the data to be displayed on the page.
116 void PopulatePageInformation(base::DictionaryValue
* voiceSearchInfo
) {
117 // Store Key-Value pairs of about-information.
118 scoped_ptr
<base::ListValue
> list(new base::ListValue());
120 // Populate information.
121 AddOperatingSystemInfo(list
.get());
122 AddAudioInfo(list
.get());
123 AddLanguageInfo(list
.get());
124 AddHotwordInfo(list
.get());
125 AddHotwordExtensionInfo(list
.get());
126 AddAppListInfo(list
.get());
128 // voiceSearchInfo will take ownership of list, and clean it up on
130 voiceSearchInfo
->Set("voiceSearchInfo", list
.release());
133 // Adds information regarding the system and chrome version info to list.
134 void AddOperatingSystemInfo(base::ListValue
* list
) {
135 // Obtain the Chrome version info.
136 chrome::VersionInfo version_info
;
138 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
),
140 version_info
.Version() + " (" +
141 chrome::VersionInfo::GetVersionStringModifier() + ")"));
143 // OS version information.
144 std::string os_label
= version_info
.OSType();
146 base::win::OSInfo
* os
= base::win::OSInfo::GetInstance();
147 switch (os
->version()) {
148 case base::win::VERSION_XP
:
151 case base::win::VERSION_SERVER_2003
:
152 os_label
+= " Server 2003 or XP Pro 64 bit";
154 case base::win::VERSION_VISTA
:
155 os_label
+= " Vista or Server 2008";
157 case base::win::VERSION_WIN7
:
158 os_label
+= " 7 or Server 2008 R2";
160 case base::win::VERSION_WIN8
:
161 os_label
+= " 8 or Server 2012";
164 os_label
+= " UNKNOWN";
167 os_label
+= " SP" + base::IntToString(os
->service_pack().major
);
169 if (os
->service_pack().minor
> 0)
170 os_label
+= "." + base::IntToString(os
->service_pack().minor
);
172 if (os
->architecture() == base::win::OSInfo::X64_ARCHITECTURE
)
173 os_label
+= " 64 bit";
176 l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS
),
177 ASCIIToUTF16(os_label
));
182 // Adds information regarding audio to the list.
183 void AddAudioInfo(base::ListValue
* list
) {
184 // NaCl and its associated functions are not available on most mobile
185 // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not
186 // allow Hotwording anyways since it is an extension.
187 std::string nacl_enabled
= "not available";
188 #if defined(ENABLE_EXTENSIONS)
190 // Determine if NaCl is available.
192 if (PathService::Get(chrome::FILE_NACL_PLUGIN
, &path
)) {
193 content::WebPluginInfo info
;
194 PluginPrefs
* plugin_prefs
= PluginPrefs::GetForProfile(profile_
).get();
195 if (content::PluginService::GetInstance()->GetPluginInfoByPath(path
,
197 plugin_prefs
->IsPluginEnabled(info
)) {
198 nacl_enabled
= "Yes";
203 AddPair(list
, ASCIIToUTF16("NaCl Enabled"), ASCIIToUTF16(nacl_enabled
));
205 AddPair(list
, ASCIIToUTF16("Microphone"),
207 HotwordServiceFactory::IsMicrophoneAvailable() ? "Yes" : "No"));
209 std::string audio_capture
= "No";
210 if (profile_
->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed
))
211 audio_capture
= "Yes";
212 AddPair(list
, ASCIIToUTF16("Audio Capture Allowed"),
213 ASCIIToUTF16(audio_capture
));
218 // Adds information regarding languages to the list.
219 void AddLanguageInfo(base::ListValue
* list
) {
221 #if defined(OS_CHROMEOS)
222 // On ChromeOS locale is per-profile.
223 profile_
->GetPrefs()->GetString(prefs::kApplicationLocale
);
225 g_browser_process
->GetApplicationLocale();
227 AddPair(list
, ASCIIToUTF16("Current Language"), ASCIIToUTF16(locale
));
229 AddPair(list
, ASCIIToUTF16("Hotword Previous Language"),
230 ASCIIToUTF16(profile_
->GetPrefs()->GetString(
231 prefs::kHotwordPreviousLanguage
)));
236 // Adds information specific to the hotword configuration to the list.
237 void AddHotwordInfo(base::ListValue
* list
) {
238 std::string search_enabled
= "No";
239 if (profile_
->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled
))
240 search_enabled
= "Yes";
241 AddPair(list
, ASCIIToUTF16("Hotword Search Enabled"),
242 ASCIIToUTF16(search_enabled
));
244 std::string audio_logging_enabled
= "No";
245 HotwordService
* hotword_service
=
246 HotwordServiceFactory::GetForProfile(profile_
);
247 if (hotword_service
&& hotword_service
->IsOptedIntoAudioLogging())
248 audio_logging_enabled
= "Yes";
249 AddPair(list
, ASCIIToUTF16("Hotword Audio Logging Enabled"),
250 ASCIIToUTF16(audio_logging_enabled
));
252 std::string group
= base::FieldTrialList::FindFullName(
253 hotword_internal::kHotwordFieldTrialName
);
254 AddPair(list
, ASCIIToUTF16("Field trial"), ASCIIToUTF16(group
));
259 // Adds information specific to the hotword extension to the list.
260 void AddHotwordExtensionInfo(base::ListValue
* list
) {
261 std::string
version("undefined");
262 std::string
id("undefined");
265 extensions::ExtensionSystem
* extension_system
=
266 extensions::ExtensionSystem::Get(profile_
);
267 if (extension_system
) {
268 ExtensionService
* extension_service
=
269 extension_system
->extension_service();
270 const extensions::Extension
* extension
=
271 extension_service
->GetExtensionById(
272 extension_misc::kHotwordExtensionId
, true);
274 id
= extension
->id();
275 version
= extension
->VersionString();
276 path
= extension
->path();
279 AddPair(list
, ASCIIToUTF16("Extension Id"),
281 AddPair(list
, ASCIIToUTF16("Extension Version"),
282 ASCIIToUTF16(version
));
283 AddPair(list
, ASCIIToUTF16("Extension Path"),
284 path
.empty() ? ASCIIToUTF16("undefined") : path
.LossyDisplayName());
286 extensions::ExtensionPrefs
* extension_prefs
=
287 extensions::ExtensionPrefs::Get(profile_
);
289 extension_prefs
->ReadPrefAsInteger(extension_misc::kHotwordExtensionId
,
290 "state", &pref_state
);
292 switch (pref_state
) {
293 case extensions::Extension::DISABLED
:
296 case extensions::Extension::ENABLED
:
299 case extensions::Extension::EXTERNAL_EXTENSION_UNINSTALLED
:
300 state
= "EXTERNAL_EXTENSION_UNINSTALLED";
306 AddPair(list
, ASCIIToUTF16("Extension State"), ASCIIToUTF16(state
));
311 // Adds information specific to voice search in the app launcher to the list.
312 void AddAppListInfo(base::ListValue
* list
) {
313 #if defined (ENABLE_APP_LIST)
314 std::string state
= "No Start Page Service";
315 app_list::StartPageService
* start_page_service
=
316 app_list::StartPageService::Get(profile_
);
317 if (start_page_service
) {
318 app_list::SpeechRecognitionState speech_state
=
319 start_page_service
->state();
320 switch (speech_state
) {
321 case app_list::SPEECH_RECOGNITION_OFF
:
322 state
= "SPEECH_RECOGNITION_OFF";
324 case app_list::SPEECH_RECOGNITION_READY
:
325 state
= "SPEECH_RECOGNITION_READY";
327 case app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING
:
328 state
= "SPEECH_RECOGNITION_HOTWORD_LISTENING";
330 case app_list::SPEECH_RECOGNITION_RECOGNIZING
:
331 state
= "SPEECH_RECOGNITION_RECOGNIZING";
333 case app_list::SPEECH_RECOGNITION_IN_SPEECH
:
334 state
= "SPEECH_RECOGNITION_IN_SPEECH";
336 case app_list::SPEECH_RECOGNITION_STOPPING
:
337 state
= "SPEECH_RECOGNITION_STOPPING";
339 case app_list::SPEECH_RECOGNITION_NETWORK_ERROR
:
340 state
= "SPEECH_RECOGNITION_NETWORK_ERROR";
346 AddPair(list
, ASCIIToUTF16("Start Page State"), ASCIIToUTF16(state
));
352 DISALLOW_COPY_AND_ASSIGN(VoiceSearchDomHandler
);
357 ///////////////////////////////////////////////////////////////////////////////
361 ///////////////////////////////////////////////////////////////////////////////
363 VoiceSearchUI::VoiceSearchUI(content::WebUI
* web_ui
)
364 : content::WebUIController(web_ui
) {
365 Profile
* profile
= Profile::FromWebUI(web_ui
);
366 web_ui
->AddMessageHandler(new VoiceSearchDomHandler(profile
));
368 // Set up the about:voicesearch source.
369 content::WebUIDataSource::Add(profile
, CreateVoiceSearchUiHtmlSource());
372 VoiceSearchUI::~VoiceSearchUI() {}