Home | History | Annotate | Download | only in webui
      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.
      4 
      5 #include "chrome/browser/ui/webui/voicesearch_ui.h"
      6 
      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"
     42 
     43 #if defined(OS_WIN)
     44 #include "base/win/windows_version.h"
     45 #endif
     46 
     47 using base::ASCIIToUTF16;
     48 using content::WebUIMessageHandler;
     49 
     50 namespace {
     51 
     52 content::WebUIDataSource* CreateVoiceSearchUiHtmlSource() {
     53   content::WebUIDataSource* html_source =
     54       content::WebUIDataSource::Create(chrome::kChromeUIVoiceSearchHost);
     55 
     56   html_source->AddLocalizedString("loadingMessage",
     57                                   IDS_VOICESEARCH_LOADING_MESSAGE);
     58   html_source->AddLocalizedString("voiceSearchLongTitle",
     59                                   IDS_VOICESEARCH_TITLE_MESSAGE);
     60 
     61   html_source->SetUseJsonJSFormatV2();
     62   html_source->SetJsonPath("strings.js");
     63   html_source->AddResourcePath("about_voicesearch.js",
     64                                IDR_ABOUT_VOICESEARCH_JS);
     65   html_source->SetDefaultResource(IDR_ABOUT_VOICESEARCH_HTML);
     66   return html_source;
     67 }
     68 
     69 // Helper functions for collecting a list of key-value pairs that will
     70 // be displayed.
     71 void AddPair(base::ListValue* list,
     72              const base::string16& key,
     73              const base::string16& value) {
     74   scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue());
     75   results->SetString("key", key);
     76   results->SetString("value", value);
     77   list->Append(results.release());
     78 }
     79 
     80 // Generate an empty data-pair which acts as a line break.
     81 void AddLineBreak(base::ListValue* list) {
     82   AddPair(list, ASCIIToUTF16(base::StringPiece()),
     83           ASCIIToUTF16(base::StringPiece()));
     84 }
     85 
     86 ////////////////////////////////////////////////////////////////////////////////
     87 //
     88 // VoiceSearchDomHandler
     89 //
     90 ////////////////////////////////////////////////////////////////////////////////
     91 
     92 // The handler for Javascript messages for the about:flags page.
     93 class VoiceSearchDomHandler : public WebUIMessageHandler {
     94  public:
     95   explicit VoiceSearchDomHandler(Profile* profile) : profile_(profile) {}
     96 
     97   virtual ~VoiceSearchDomHandler() {}
     98 
     99   // WebUIMessageHandler implementation.
    100   virtual void RegisterMessages() OVERRIDE {
    101     web_ui()->RegisterMessageCallback(
    102         "requestVoiceSearchInfo",
    103         base::Bind(&VoiceSearchDomHandler::HandleRequestVoiceSearchInfo,
    104                    base::Unretained(this)));
    105   }
    106 
    107  private:
    108   // Callback for the "requestVoiceSearchInfo" message. No arguments.
    109   void HandleRequestVoiceSearchInfo(const base::ListValue* args) {
    110     base::DictionaryValue voiceSearchInfo;
    111     PopulatePageInformation(&voiceSearchInfo);
    112     web_ui()->CallJavascriptFunction("returnVoiceSearchInfo",
    113                                      voiceSearchInfo);
    114   }
    115 
    116   // Fill in the data to be displayed on the page.
    117   void PopulatePageInformation(base::DictionaryValue* voiceSearchInfo) {
    118     // Store Key-Value pairs of about-information.
    119     scoped_ptr<base::ListValue> list(new base::ListValue());
    120 
    121     // Populate information.
    122     AddOperatingSystemInfo(list.get());
    123     AddAudioInfo(list.get());
    124     AddLanguageInfo(list.get());
    125     AddHotwordInfo(list.get());
    126     AddHotwordExtensionInfo(list.get());
    127     AddAppListInfo(list.get());
    128 
    129     // voiceSearchInfo will take ownership of list, and clean it up on
    130     // destruction.
    131     voiceSearchInfo->Set("voiceSearchInfo", list.release());
    132   }
    133 
    134   // Adds information regarding the system and chrome version info to list.
    135   void AddOperatingSystemInfo(base::ListValue* list)  {
    136     // Obtain the Chrome version info.
    137     chrome::VersionInfo version_info;
    138     AddPair(list,
    139             l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
    140             ASCIIToUTF16(
    141                 version_info.Version() + " (" +
    142                 chrome::VersionInfo::GetVersionStringModifier() + ")"));
    143 
    144     // OS version information.
    145     std::string os_label = version_info.OSType();
    146 #if defined(OS_WIN)
    147     base::win::OSInfo* os = base::win::OSInfo::GetInstance();
    148     switch (os->version()) {
    149       case base::win::VERSION_XP:
    150         os_label += " XP";
    151         break;
    152       case base::win::VERSION_SERVER_2003:
    153         os_label += " Server 2003 or XP Pro 64 bit";
    154         break;
    155       case base::win::VERSION_VISTA:
    156         os_label += " Vista or Server 2008";
    157         break;
    158       case base::win::VERSION_WIN7:
    159         os_label += " 7 or Server 2008 R2";
    160         break;
    161       case base::win::VERSION_WIN8:
    162         os_label += " 8 or Server 2012";
    163         break;
    164       default:
    165         os_label += " UNKNOWN";
    166         break;
    167     }
    168     os_label += " SP" + base::IntToString(os->service_pack().major);
    169 
    170     if (os->service_pack().minor > 0)
    171       os_label += "." + base::IntToString(os->service_pack().minor);
    172 
    173     if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE)
    174       os_label += " 64 bit";
    175 #endif
    176     AddPair(list,
    177             l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS),
    178             ASCIIToUTF16(os_label));
    179 
    180     AddLineBreak(list);
    181   }
    182 
    183   // Adds information regarding audio to the list.
    184   void AddAudioInfo(base::ListValue* list) {
    185     // NaCl and its associated functions are not available on most mobile
    186     // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not
    187     // allow Hotwording anyways since it is an extension.
    188     std::string nacl_enabled = "not available";
    189 #if defined(ENABLE_EXTENSIONS)
    190     nacl_enabled = "No";
    191     // Determine if NaCl is available.
    192     base::FilePath path;
    193     if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) {
    194       content::WebPluginInfo info;
    195       PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get();
    196       if (content::PluginService::GetInstance()->GetPluginInfoByPath(path,
    197                                                                      &info) &&
    198           plugin_prefs->IsPluginEnabled(info)) {
    199         nacl_enabled = "Yes";
    200       }
    201     }
    202 #endif
    203 
    204     AddPair(list, ASCIIToUTF16("NaCl Enabled"), ASCIIToUTF16(nacl_enabled));
    205 
    206     AddPair(list, ASCIIToUTF16("Microphone"),
    207             ASCIIToUTF16(
    208                 HotwordServiceFactory::IsMicrophoneAvailable() ? "Yes" : "No"));
    209 
    210     std::string audio_capture = "No";
    211     if (profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed))
    212       audio_capture = "Yes";
    213     AddPair(list, ASCIIToUTF16("Audio Capture Allowed"),
    214             ASCIIToUTF16(audio_capture));
    215 
    216     AddLineBreak(list);
    217   }
    218 
    219   // Adds information regarding languages to the list.
    220   void AddLanguageInfo(base::ListValue* list) {
    221     std::string locale =
    222 #if defined(OS_CHROMEOS)
    223         // On ChromeOS locale is per-profile.
    224         profile_->GetPrefs()->GetString(prefs::kApplicationLocale);
    225 #else
    226         g_browser_process->GetApplicationLocale();
    227 #endif
    228     AddPair(list, ASCIIToUTF16("Current Language"), ASCIIToUTF16(locale));
    229 
    230     AddPair(list, ASCIIToUTF16("Hotword Previous Language"),
    231             ASCIIToUTF16(profile_->GetPrefs()->GetString(
    232                 prefs::kHotwordPreviousLanguage)));
    233 
    234     AddLineBreak(list);
    235   }
    236 
    237   // Adds information specific to the hotword configuration to the list.
    238   void AddHotwordInfo(base::ListValue* list)  {
    239     std::string search_enabled = "No";
    240     if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled))
    241       search_enabled = "Yes";
    242     AddPair(list, ASCIIToUTF16("Hotword Search Enabled"),
    243             ASCIIToUTF16(search_enabled));
    244 
    245     std::string audio_logging_enabled = "No";
    246     HotwordService* hotword_service =
    247         HotwordServiceFactory::GetForProfile(profile_);
    248     if (hotword_service && hotword_service->IsOptedIntoAudioLogging())
    249       audio_logging_enabled = "Yes";
    250     AddPair(list, ASCIIToUTF16("Hotword Audio Logging Enabled"),
    251             ASCIIToUTF16(audio_logging_enabled));
    252 
    253     std::string group = base::FieldTrialList::FindFullName(
    254         hotword_internal::kHotwordFieldTrialName);
    255     AddPair(list, ASCIIToUTF16("Field trial"), ASCIIToUTF16(group));
    256 
    257     AddLineBreak(list);
    258   }
    259 
    260   // Adds information specific to the hotword extension to the list.
    261   void AddHotwordExtensionInfo(base::ListValue* list) {
    262     std::string version("undefined");
    263     std::string id("undefined");
    264     base::FilePath path;
    265 
    266     extensions::ExtensionSystem* extension_system =
    267         extensions::ExtensionSystem::Get(profile_);
    268     if (extension_system) {
    269       ExtensionService* extension_service =
    270           extension_system->extension_service();
    271       const extensions::Extension* extension =
    272           extension_service->GetExtensionById(
    273               extension_misc::kHotwordExtensionId, true);
    274       if (extension) {
    275         id = extension->id();
    276         version = extension->VersionString();
    277         path = extension->path();
    278       }
    279     }
    280     AddPair(list, ASCIIToUTF16("Extension Id"),
    281             ASCIIToUTF16(id));
    282     AddPair(list, ASCIIToUTF16("Extension Version"),
    283             ASCIIToUTF16(version));
    284     AddPair(list, ASCIIToUTF16("Extension Path"),
    285             path.empty() ? ASCIIToUTF16("undefined") : path.LossyDisplayName());
    286 
    287     extensions::ExtensionPrefs* extension_prefs =
    288         extensions::ExtensionPrefs::Get(profile_);
    289     int pref_state = -1;
    290     extension_prefs->ReadPrefAsInteger(extension_misc::kHotwordExtensionId,
    291                                        "state", &pref_state);
    292     std::string state;
    293     switch (pref_state) {
    294       case extensions::Extension::DISABLED:
    295         state = "DISABLED";
    296         break;
    297       case extensions::Extension::ENABLED:
    298         state = "ENABLED";
    299         break;
    300       case extensions::Extension::EXTERNAL_EXTENSION_UNINSTALLED:
    301         state = "EXTERNAL_EXTENSION_UNINSTALLED";
    302         break;
    303       default:
    304         state = "undefined";
    305     }
    306 
    307     AddPair(list, ASCIIToUTF16("Extension State"), ASCIIToUTF16(state));
    308 
    309     AddLineBreak(list);
    310   }
    311 
    312   // Adds information specific to voice search in the app launcher to the list.
    313   void AddAppListInfo(base::ListValue* list) {
    314 #if defined (ENABLE_APP_LIST)
    315     std::string state = "No Start Page Service";
    316     app_list::StartPageService* start_page_service =
    317         app_list::StartPageService::Get(profile_);
    318     if (start_page_service) {
    319       app_list::SpeechRecognitionState speech_state =
    320           start_page_service->state();
    321       switch (speech_state) {
    322         case app_list::SPEECH_RECOGNITION_OFF:
    323           state = "SPEECH_RECOGNITION_OFF";
    324           break;
    325         case app_list::SPEECH_RECOGNITION_READY:
    326           state = "SPEECH_RECOGNITION_READY";
    327           break;
    328         case app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING:
    329           state = "SPEECH_RECOGNITION_HOTWORD_LISTENING";
    330           break;
    331         case app_list::SPEECH_RECOGNITION_RECOGNIZING:
    332           state = "SPEECH_RECOGNITION_RECOGNIZING";
    333           break;
    334         case app_list::SPEECH_RECOGNITION_IN_SPEECH:
    335           state = "SPEECH_RECOGNITION_IN_SPEECH";
    336           break;
    337         case app_list::SPEECH_RECOGNITION_STOPPING:
    338           state = "SPEECH_RECOGNITION_STOPPING";
    339           break;
    340         case app_list::SPEECH_RECOGNITION_NETWORK_ERROR:
    341           state = "SPEECH_RECOGNITION_NETWORK_ERROR";
    342           break;
    343         default:
    344           state = "undefined";
    345       }
    346     }
    347     AddPair(list, ASCIIToUTF16("Start Page State"), ASCIIToUTF16(state));
    348 #endif
    349   }
    350 
    351   Profile* profile_;
    352 
    353   DISALLOW_COPY_AND_ASSIGN(VoiceSearchDomHandler);
    354 };
    355 
    356 }  // namespace
    357 
    358 ///////////////////////////////////////////////////////////////////////////////
    359 //
    360 // VoiceSearchUI
    361 //
    362 ///////////////////////////////////////////////////////////////////////////////
    363 
    364 VoiceSearchUI::VoiceSearchUI(content::WebUI* web_ui)
    365     : content::WebUIController(web_ui) {
    366   Profile* profile = Profile::FromWebUI(web_ui);
    367   web_ui->AddMessageHandler(new VoiceSearchDomHandler(profile));
    368 
    369   // Set up the about:voicesearch source.
    370   content::WebUIDataSource::Add(profile, CreateVoiceSearchUiHtmlSource());
    371 }
    372 
    373 VoiceSearchUI::~VoiceSearchUI() {}
    374