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/omaha_query_params/omaha_query_params.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/search/hotword_service.h" 16 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 17 #include "chrome/browser/ui/app_list/app_list_service.h" 18 #include "chrome/browser/ui/app_list/recommended_apps.h" 19 #include "chrome/browser/ui/app_list/start_page_service.h" 20 #include "chrome/browser/ui/host_desktop.h" 21 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 22 #include "chrome/common/pref_names.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.5014_0"; 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 StartPageService* service = StartPageService::Get(profile); 149 web_ui()->CallJavascriptFunction( 150 "appList.startPage.setHotwordEnabled", 151 base::FundamentalValue(service->HotwordEnabled())); 152 } 153 } 154 #endif 155 156 void StartPageHandler::HandleInitialize(const base::ListValue* args) { 157 Profile* profile = Profile::FromWebUI(web_ui()); 158 StartPageService* service = StartPageService::Get(profile); 159 if (!service) 160 return; 161 162 recommended_apps_ = service->recommended_apps(); 163 recommended_apps_->AddObserver(this); 164 165 SendRecommendedApps(); 166 167 #if defined(OS_CHROMEOS) 168 if (app_list::switches::IsVoiceSearchEnabled() && 169 HotwordService::DoesHotwordSupportLanguage(profile)) { 170 OnHotwordEnabledChanged(); 171 pref_change_registrar_.Init(profile->GetPrefs()); 172 pref_change_registrar_.Add( 173 prefs::kHotwordSearchEnabled, 174 base::Bind(&StartPageHandler::OnHotwordEnabledChanged, 175 base::Unretained(this))); 176 177 extension_registry_observer_.Add( 178 extensions::ExtensionRegistry::Get(profile)); 179 } 180 #endif 181 182 web_ui()->CallJavascriptFunction( 183 "appList.startPage.setNaclArch", 184 base::StringValue(chrome::OmahaQueryParams::GetNaclArch())); 185 186 if (!app_list::switches::IsExperimentalAppListEnabled()) { 187 web_ui()->CallJavascriptFunction( 188 "appList.startPage.onAppListShown", 189 base::FundamentalValue(service->HotwordEnabled())); 190 } 191 } 192 193 void StartPageHandler::HandleLaunchApp(const base::ListValue* args) { 194 std::string app_id; 195 CHECK(args->GetString(0, &app_id)); 196 197 Profile* profile = Profile::FromWebUI(web_ui()); 198 const extensions::Extension* app = 199 extensions::ExtensionRegistry::Get(profile) 200 ->GetExtensionById(app_id, extensions::ExtensionRegistry::EVERYTHING); 201 if (!app) { 202 NOTREACHED(); 203 return; 204 } 205 206 AppListControllerDelegate* controller = AppListService::Get( 207 chrome::GetHostDesktopTypeForNativeView( 208 web_ui()->GetWebContents()->GetNativeView()))-> 209 GetControllerDelegate(); 210 controller->ActivateApp(profile, 211 app, 212 AppListControllerDelegate::LAUNCH_FROM_APP_LIST, 213 ui::EF_NONE); 214 } 215 216 void StartPageHandler::HandleSpeechResult(const base::ListValue* args) { 217 base::string16 query; 218 bool is_final = false; 219 CHECK(args->GetString(0, &query)); 220 CHECK(args->GetBoolean(1, &is_final)); 221 222 StartPageService::Get(Profile::FromWebUI(web_ui()))->OnSpeechResult( 223 query, is_final); 224 } 225 226 void StartPageHandler::HandleSpeechSoundLevel(const base::ListValue* args) { 227 double level; 228 CHECK(args->GetDouble(0, &level)); 229 230 StartPageService* service = 231 StartPageService::Get(Profile::FromWebUI(web_ui())); 232 if (service) 233 service->OnSpeechSoundLevelChanged(static_cast<int16>(level)); 234 } 235 236 void StartPageHandler::HandleSpeechRecognition(const base::ListValue* args) { 237 std::string state_string; 238 CHECK(args->GetString(0, &state_string)); 239 240 SpeechRecognitionState new_state = SPEECH_RECOGNITION_OFF; 241 if (state_string == "READY") 242 new_state = SPEECH_RECOGNITION_READY; 243 else if (state_string == "HOTWORD_RECOGNIZING") 244 new_state = SPEECH_RECOGNITION_HOTWORD_LISTENING; 245 else if (state_string == "RECOGNIZING") 246 new_state = SPEECH_RECOGNITION_RECOGNIZING; 247 else if (state_string == "IN_SPEECH") 248 new_state = SPEECH_RECOGNITION_IN_SPEECH; 249 else if (state_string == "STOPPING") 250 new_state = SPEECH_RECOGNITION_STOPPING; 251 else if (state_string == "NETWORK_ERROR") 252 new_state = SPEECH_RECOGNITION_NETWORK_ERROR; 253 254 StartPageService* service = 255 StartPageService::Get(Profile::FromWebUI(web_ui())); 256 if (service) 257 service->OnSpeechRecognitionStateChanged(new_state); 258 } 259 260 } // namespace app_list 261