Home | History | Annotate | Download | only in app_list
      1 // Copyright 2013 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/app_list/start_page_handler.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/values.h"
     12 #include "base/version.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/browser/search/hotword_service.h"
     15 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
     16 #include "chrome/browser/ui/app_list/app_list_service.h"
     17 #include "chrome/browser/ui/app_list/recommended_apps.h"
     18 #include "chrome/browser/ui/app_list/start_page_service.h"
     19 #include "chrome/browser/ui/host_desktop.h"
     20 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
     21 #include "chrome/common/pref_names.h"
     22 #include "components/omaha_query_params/omaha_query_params.h"
     23 #include "content/public/browser/web_ui.h"
     24 #include "extensions/browser/extension_registry.h"
     25 #include "extensions/browser/extension_system.h"
     26 #include "extensions/common/constants.h"
     27 #include "extensions/common/extension.h"
     28 #include "extensions/common/extension_icon_set.h"
     29 #include "ui/app_list/app_list_switches.h"
     30 #include "ui/app_list/speech_ui_model_observer.h"
     31 #include "ui/events/event_constants.h"
     32 
     33 namespace app_list {
     34 
     35 namespace {
     36 
     37 #if defined(OS_CHROMEOS)
     38 const char kOldHotwordExtensionVersionString[] = "0.1.1.5023";
     39 #endif
     40 
     41 scoped_ptr<base::DictionaryValue> CreateAppInfo(
     42     const extensions::Extension* app) {
     43   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
     44   dict->SetString("appId", app->id());
     45   dict->SetString("textTitle", app->short_name());
     46   dict->SetString("title", app->name());
     47 
     48   const bool grayscale = false;
     49   bool icon_exists = true;
     50   GURL icon_url = extensions::ExtensionIconSource::GetIconURL(
     51       app,
     52       extension_misc::EXTENSION_ICON_MEDIUM,
     53       ExtensionIconSet::MATCH_BIGGER,
     54       grayscale,
     55       &icon_exists);
     56   dict->SetString("iconUrl", icon_url.spec());
     57 
     58   return dict.Pass();
     59 }
     60 
     61 }  // namespace
     62 
     63 StartPageHandler::StartPageHandler()
     64     : recommended_apps_(NULL),
     65       extension_registry_observer_(this) {
     66 }
     67 
     68 StartPageHandler::~StartPageHandler() {
     69   if (recommended_apps_)
     70     recommended_apps_->RemoveObserver(this);
     71 }
     72 
     73 void StartPageHandler::RegisterMessages() {
     74   web_ui()->RegisterMessageCallback(
     75       "initialize",
     76       base::Bind(&StartPageHandler::HandleInitialize, base::Unretained(this)));
     77   web_ui()->RegisterMessageCallback(
     78       "launchApp",
     79       base::Bind(&StartPageHandler::HandleLaunchApp, base::Unretained(this)));
     80   web_ui()->RegisterMessageCallback(
     81       "speechResult",
     82       base::Bind(&StartPageHandler::HandleSpeechResult,
     83                  base::Unretained(this)));
     84   web_ui()->RegisterMessageCallback(
     85       "speechSoundLevel",
     86       base::Bind(&StartPageHandler::HandleSpeechSoundLevel,
     87                  base::Unretained(this)));
     88   web_ui()->RegisterMessageCallback(
     89       "setSpeechRecognitionState",
     90       base::Bind(&StartPageHandler::HandleSpeechRecognition,
     91                  base::Unretained(this)));
     92 }
     93 
     94 void StartPageHandler::OnExtensionLoaded(
     95     content::BrowserContext* browser_context,
     96     const extensions::Extension* extension) {
     97 #if defined(OS_CHROMEOS)
     98   DCHECK_EQ(Profile::FromWebUI(web_ui()),
     99             Profile::FromBrowserContext(browser_context));
    100   if (extension->id() == extension_misc::kHotwordExtensionId)
    101     OnHotwordEnabledChanged();
    102 #endif
    103 }
    104 
    105 void StartPageHandler::OnExtensionUnloaded(
    106     content::BrowserContext* browser_context,
    107     const extensions::Extension* extension,
    108     extensions::UnloadedExtensionInfo::Reason reason) {
    109 #if defined(OS_CHROMEOS)
    110   DCHECK_EQ(Profile::FromWebUI(web_ui()),
    111             Profile::FromBrowserContext(browser_context));
    112   if (extension->id() == extension_misc::kHotwordExtensionId)
    113     OnHotwordEnabledChanged();
    114 #endif
    115 }
    116 
    117 void StartPageHandler::OnRecommendedAppsChanged() {
    118   SendRecommendedApps();
    119 }
    120 
    121 void StartPageHandler::SendRecommendedApps() {
    122   const RecommendedApps::Apps& recommends = recommended_apps_->apps();
    123 
    124   base::ListValue recommended_list;
    125   for (size_t i = 0; i < recommends.size(); ++i) {
    126     recommended_list.Append(CreateAppInfo(recommends[i].get()).release());
    127   }
    128 
    129   web_ui()->CallJavascriptFunction("appList.startPage.setRecommendedApps",
    130                                    recommended_list);
    131 }
    132 
    133 #if defined(OS_CHROMEOS)
    134 void StartPageHandler::OnHotwordEnabledChanged() {
    135   // If the hotword extension is new enough, we should use the new
    136   // hotwordPrivate API to provide the feature.
    137   // TODO(mukai): remove this after everything gets stable.
    138   Profile* profile = Profile::FromWebUI(web_ui());
    139 
    140   extensions::ExtensionRegistry* registry =
    141       extensions::ExtensionRegistry::Get(profile);
    142   const extensions::Extension* hotword_extension =
    143       registry->GetExtensionById(extension_misc::kHotwordExtensionId,
    144                                  extensions::ExtensionRegistry::ENABLED);
    145   if (hotword_extension &&
    146       hotword_extension->version()->CompareTo(
    147           base::Version(kOldHotwordExtensionVersionString)) <= 0 &&
    148       !HotwordService::IsExperimentalHotwordingEnabled()) {
    149     StartPageService* service = StartPageService::Get(profile);
    150     web_ui()->CallJavascriptFunction(
    151         "appList.startPage.setHotwordEnabled",
    152         base::FundamentalValue(service->HotwordEnabled()));
    153   }
    154 }
    155 #endif
    156 
    157 void StartPageHandler::HandleInitialize(const base::ListValue* args) {
    158   Profile* profile = Profile::FromWebUI(web_ui());
    159   StartPageService* service = StartPageService::Get(profile);
    160   if (!service)
    161     return;
    162 
    163   recommended_apps_ = service->recommended_apps();
    164   recommended_apps_->AddObserver(this);
    165 
    166   SendRecommendedApps();
    167 
    168 #if defined(OS_CHROMEOS)
    169   if (app_list::switches::IsVoiceSearchEnabled() &&
    170       HotwordService::DoesHotwordSupportLanguage(profile)) {
    171     OnHotwordEnabledChanged();
    172     pref_change_registrar_.Init(profile->GetPrefs());
    173     pref_change_registrar_.Add(
    174         prefs::kHotwordSearchEnabled,
    175         base::Bind(&StartPageHandler::OnHotwordEnabledChanged,
    176                    base::Unretained(this)));
    177 
    178     extension_registry_observer_.Add(
    179         extensions::ExtensionRegistry::Get(profile));
    180   }
    181 
    182   extensions::ExtensionRegistry* registry =
    183       extensions::ExtensionRegistry::Get(profile);
    184   const extensions::Extension* hotword_extension =
    185       registry->GetExtensionById(extension_misc::kHotwordExtensionId,
    186                                  extensions::ExtensionRegistry::ENABLED);
    187   if (hotword_extension &&
    188       hotword_extension->version()->CompareTo(
    189           base::Version(kOldHotwordExtensionVersionString)) <= 0) {
    190     web_ui()->CallJavascriptFunction(
    191         "appList.startPage.setNaclArch",
    192         base::StringValue(omaha_query_params::OmahaQueryParams::GetNaclArch()));
    193   }
    194 #endif
    195 
    196   if (!app_list::switches::IsExperimentalAppListEnabled()) {
    197     // If experimental hotwording is enabled, don't enable hotwording in the
    198     // start page, since the hotword extension is taking care of this.
    199     bool hotword_enabled = service->HotwordEnabled() &&
    200         !HotwordService::IsExperimentalHotwordingEnabled();
    201     web_ui()->CallJavascriptFunction(
    202         "appList.startPage.onAppListShown",
    203         base::FundamentalValue(hotword_enabled));
    204   }
    205 }
    206 
    207 void StartPageHandler::HandleLaunchApp(const base::ListValue* args) {
    208   std::string app_id;
    209   CHECK(args->GetString(0, &app_id));
    210 
    211   Profile* profile = Profile::FromWebUI(web_ui());
    212   const extensions::Extension* app =
    213       extensions::ExtensionRegistry::Get(profile)
    214           ->GetExtensionById(app_id, extensions::ExtensionRegistry::EVERYTHING);
    215   if (!app) {
    216     NOTREACHED();
    217     return;
    218   }
    219 
    220   AppListControllerDelegate* controller = AppListService::Get(
    221       chrome::GetHostDesktopTypeForNativeView(
    222           web_ui()->GetWebContents()->GetNativeView()))->
    223               GetControllerDelegate();
    224   controller->ActivateApp(profile,
    225                           app,
    226                           AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
    227                           ui::EF_NONE);
    228 }
    229 
    230 void StartPageHandler::HandleSpeechResult(const base::ListValue* args) {
    231   base::string16 query;
    232   bool is_final = false;
    233   CHECK(args->GetString(0, &query));
    234   CHECK(args->GetBoolean(1, &is_final));
    235 
    236   StartPageService::Get(Profile::FromWebUI(web_ui()))->OnSpeechResult(
    237       query, is_final);
    238 }
    239 
    240 void StartPageHandler::HandleSpeechSoundLevel(const base::ListValue* args) {
    241   double level;
    242   CHECK(args->GetDouble(0, &level));
    243 
    244   StartPageService* service =
    245       StartPageService::Get(Profile::FromWebUI(web_ui()));
    246   if (service)
    247     service->OnSpeechSoundLevelChanged(static_cast<int16>(level));
    248 }
    249 
    250 void StartPageHandler::HandleSpeechRecognition(const base::ListValue* args) {
    251   std::string state_string;
    252   CHECK(args->GetString(0, &state_string));
    253 
    254   SpeechRecognitionState new_state = SPEECH_RECOGNITION_OFF;
    255   if (state_string == "READY")
    256     new_state = SPEECH_RECOGNITION_READY;
    257   else if (state_string == "HOTWORD_RECOGNIZING")
    258     new_state = SPEECH_RECOGNITION_HOTWORD_LISTENING;
    259   else if (state_string == "RECOGNIZING")
    260     new_state = SPEECH_RECOGNITION_RECOGNIZING;
    261   else if (state_string == "IN_SPEECH")
    262     new_state = SPEECH_RECOGNITION_IN_SPEECH;
    263   else if (state_string == "STOPPING")
    264     new_state = SPEECH_RECOGNITION_STOPPING;
    265   else if (state_string == "NETWORK_ERROR")
    266     new_state = SPEECH_RECOGNITION_NETWORK_ERROR;
    267 
    268   StartPageService* service =
    269       StartPageService::Get(Profile::FromWebUI(web_ui()));
    270   if (service)
    271     service->OnSpeechRecognitionStateChanged(new_state);
    272 }
    273 
    274 }  // namespace app_list
    275