app_list_view_delegate.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2012 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/app_list/app_list_view_delegate.h" 6 7#include <vector> 8 9#include "base/callback.h" 10#include "base/files/file_path.h" 11#include "base/metrics/user_metrics.h" 12#include "base/stl_util.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/chrome_notification_types.h" 15#include "chrome/browser/extensions/extension_service.h" 16#include "chrome/browser/feedback/feedback_util.h" 17#include "chrome/browser/profiles/profile_info_cache.h" 18#include "chrome/browser/profiles/profile_manager.h" 19#include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 20#include "chrome/browser/ui/app_list/app_list_service.h" 21#include "chrome/browser/ui/app_list/app_list_syncable_service.h" 22#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" 23#include "chrome/browser/ui/app_list/search/search_controller.h" 24#include "chrome/browser/ui/app_list/start_page_service.h" 25#include "chrome/browser/ui/browser_finder.h" 26#include "chrome/browser/ui/chrome_pages.h" 27#include "chrome/browser/ui/host_desktop.h" 28#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 29#include "chrome/browser/ui/web_applications/web_app_ui.h" 30#include "chrome/browser/web_applications/web_app.h" 31#include "chrome/common/extensions/extension_constants.h" 32#include "chrome/common/url_constants.h" 33#include "content/public/browser/browser_thread.h" 34#include "content/public/browser/notification_service.h" 35#include "content/public/browser/notification_source.h" 36#include "content/public/browser/page_navigator.h" 37#include "content/public/browser/user_metrics.h" 38#include "grit/theme_resources.h" 39#include "ui/app_list/app_list_view_delegate_observer.h" 40#include "ui/app_list/search_box_model.h" 41#include "ui/app_list/speech_ui_model.h" 42#include "ui/base/resource/resource_bundle.h" 43 44#if defined(USE_ASH) 45#include "chrome/browser/ui/ash/app_list/app_sync_ui_state_watcher.h" 46#endif 47 48#if defined(OS_WIN) 49#include "chrome/browser/web_applications/web_app_win.h" 50#endif 51 52namespace { 53 54const int kAutoLaunchDefaultTimeoutMilliSec = 50; 55 56#if defined(OS_WIN) 57void CreateShortcutInWebAppDir( 58 const base::FilePath& app_data_dir, 59 base::Callback<void(const base::FilePath&)> callback, 60 const ShellIntegration::ShortcutInfo& info) { 61 content::BrowserThread::PostTaskAndReplyWithResult( 62 content::BrowserThread::FILE, 63 FROM_HERE, 64 base::Bind(web_app::CreateShortcutInWebAppDir, app_data_dir, info), 65 callback); 66} 67#endif 68 69void PopulateUsers(const ProfileInfoCache& profile_info, 70 const base::FilePath& active_profile_path, 71 app_list::AppListViewDelegate::Users* users) { 72 users->clear(); 73 const size_t count = profile_info.GetNumberOfProfiles(); 74 for (size_t i = 0; i < count; ++i) { 75 // Don't display managed users. 76 if (profile_info.ProfileIsManagedAtIndex(i)) 77 continue; 78 79 app_list::AppListViewDelegate::User user; 80 user.name = profile_info.GetNameOfProfileAtIndex(i); 81 user.email = profile_info.GetUserNameOfProfileAtIndex(i); 82 user.profile_path = profile_info.GetPathOfProfileAtIndex(i); 83 user.active = active_profile_path == user.profile_path; 84 users->push_back(user); 85 } 86} 87 88} // namespace 89 90AppListViewDelegate::AppListViewDelegate(Profile* profile, 91 AppListControllerDelegate* controller) 92 : controller_(controller), 93 profile_(profile), 94 model_(NULL) { 95 CHECK(controller_); 96 RegisterForNotifications(); 97 g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this); 98 99 app_list::StartPageService* service = 100 app_list::StartPageService::Get(profile_); 101 speech_ui_.reset(new app_list::SpeechUIModel( 102 service ? service->state() : app_list::SPEECH_RECOGNITION_OFF)); 103 104#if defined(GOOGLE_CHROME_BUILD) 105 speech_ui_->set_logo( 106 *ui::ResourceBundle::GetSharedInstance(). 107 GetImageSkiaNamed(IDR_APP_LIST_GOOGLE_LOGO_VOICE_SEARCH)); 108#endif 109 110 OnProfileChanged(); // sets model_ 111 if (service) 112 service->AddObserver(this); 113} 114 115AppListViewDelegate::~AppListViewDelegate() { 116 app_list::StartPageService* service = 117 app_list::StartPageService::Get(profile_); 118 if (service) 119 service->RemoveObserver(this); 120 g_browser_process-> 121 profile_manager()->GetProfileInfoCache().RemoveObserver(this); 122 // Ensure search controller is released prior to speech_ui_. 123 search_controller_.reset(); 124} 125 126void AppListViewDelegate::RegisterForNotifications() { 127 registrar_.RemoveAll(); 128 DCHECK(profile_); 129 130 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 131 content::NotificationService::AllSources()); 132 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, 133 content::NotificationService::AllSources()); 134 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, 135 content::NotificationService::AllSources()); 136} 137 138void AppListViewDelegate::OnProfileChanged() { 139 model_ = app_list::AppListSyncableServiceFactory::GetForProfile( 140 profile_)->model(); 141 142 search_controller_.reset(new app_list::SearchController( 143 profile_, model_->search_box(), model_->results(), 144 speech_ui_.get(), controller_)); 145 146 signin_delegate_.SetProfile(profile_); 147 148#if defined(USE_ASH) 149 app_sync_ui_state_watcher_.reset(new AppSyncUIStateWatcher(profile_, model_)); 150#endif 151 152 // Don't populate the app list users if we are on the ash desktop. 153 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 154 controller_->GetAppListWindow()); 155 if (desktop == chrome::HOST_DESKTOP_TYPE_ASH) 156 return; 157 158 // Populate the app list users. 159 PopulateUsers(g_browser_process->profile_manager()->GetProfileInfoCache(), 160 profile_->GetPath(), &users_); 161 162 FOR_EACH_OBSERVER(app_list::AppListViewDelegateObserver, 163 observers_, 164 OnProfilesChanged()); 165} 166 167bool AppListViewDelegate::ForceNativeDesktop() const { 168 return controller_->ForceNativeDesktop(); 169} 170 171void AppListViewDelegate::SetProfileByPath(const base::FilePath& profile_path) { 172 DCHECK(model_); 173 174 // The profile must be loaded before this is called. 175 profile_ = 176 g_browser_process->profile_manager()->GetProfileByPath(profile_path); 177 DCHECK(profile_); 178 179 RegisterForNotifications(); 180 181 OnProfileChanged(); 182 183 // Clear search query. 184 model_->search_box()->SetText(base::string16()); 185} 186 187app_list::AppListModel* AppListViewDelegate::GetModel() { 188 return model_; 189} 190 191app_list::SigninDelegate* AppListViewDelegate::GetSigninDelegate() { 192 return &signin_delegate_; 193} 194 195app_list::SpeechUIModel* AppListViewDelegate::GetSpeechUI() { 196 return speech_ui_.get(); 197} 198 199void AppListViewDelegate::GetShortcutPathForApp( 200 const std::string& app_id, 201 const base::Callback<void(const base::FilePath&)>& callback) { 202#if defined(OS_WIN) 203 ExtensionService* service = profile_->GetExtensionService(); 204 DCHECK(service); 205 const extensions::Extension* extension = 206 service->GetInstalledExtension(app_id); 207 if (!extension) { 208 callback.Run(base::FilePath()); 209 return; 210 } 211 212 base::FilePath app_data_dir( 213 web_app::GetWebAppDataDirectory(profile_->GetPath(), 214 extension->id(), 215 GURL())); 216 217 web_app::UpdateShortcutInfoAndIconForApp( 218 *extension, 219 profile_, 220 base::Bind(CreateShortcutInWebAppDir, app_data_dir, callback)); 221#else 222 callback.Run(base::FilePath()); 223#endif 224} 225 226void AppListViewDelegate::StartSearch() { 227 if (search_controller_) 228 search_controller_->Start(); 229} 230 231void AppListViewDelegate::StopSearch() { 232 if (search_controller_) 233 search_controller_->Stop(); 234} 235 236void AppListViewDelegate::OpenSearchResult( 237 app_list::SearchResult* result, 238 bool auto_launch, 239 int event_flags) { 240 if (auto_launch) 241 base::RecordAction(base::UserMetricsAction("AppList_AutoLaunched")); 242 search_controller_->OpenResult(result, event_flags); 243} 244 245void AppListViewDelegate::InvokeSearchResultAction( 246 app_list::SearchResult* result, 247 int action_index, 248 int event_flags) { 249 search_controller_->InvokeResultAction(result, action_index, event_flags); 250} 251 252base::TimeDelta AppListViewDelegate::GetAutoLaunchTimeout() { 253 return auto_launch_timeout_; 254} 255 256void AppListViewDelegate::AutoLaunchCanceled() { 257 base::RecordAction(base::UserMetricsAction("AppList_AutoLaunchCanceled")); 258 auto_launch_timeout_ = base::TimeDelta(); 259} 260 261void AppListViewDelegate::ViewInitialized() { 262 content::WebContents* contents = GetSpeechRecognitionContents(); 263 if (contents) { 264 contents->GetWebUI()->CallJavascriptFunction( 265 "appList.startPage.onAppListShown"); 266 } 267} 268 269void AppListViewDelegate::Dismiss() { 270 controller_->DismissView(); 271} 272 273void AppListViewDelegate::ViewClosing() { 274 controller_->ViewClosing(); 275 276 content::WebContents* contents = GetSpeechRecognitionContents(); 277 if (contents) { 278 contents->GetWebUI()->CallJavascriptFunction( 279 "appList.startPage.onAppListHidden"); 280 } 281} 282 283gfx::ImageSkia AppListViewDelegate::GetWindowIcon() { 284 return controller_->GetWindowIcon(); 285} 286 287void AppListViewDelegate::OpenSettings() { 288 ExtensionService* service = profile_->GetExtensionService(); 289 DCHECK(service); 290 const extensions::Extension* extension = service->GetInstalledExtension( 291 extension_misc::kSettingsAppId); 292 DCHECK(extension); 293 controller_->ActivateApp(profile_, 294 extension, 295 AppListControllerDelegate::LAUNCH_FROM_UNKNOWN, 296 0); 297} 298 299void AppListViewDelegate::OpenHelp() { 300 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 301 controller_->GetAppListWindow()); 302 chrome::ScopedTabbedBrowserDisplayer displayer(profile_, desktop); 303 content::OpenURLParams params(GURL(chrome::kAppLauncherHelpURL), 304 content::Referrer(), 305 NEW_FOREGROUND_TAB, 306 content::PAGE_TRANSITION_LINK, 307 false); 308 displayer.browser()->OpenURL(params); 309} 310 311void AppListViewDelegate::OpenFeedback() { 312 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 313 controller_->GetAppListWindow()); 314 Browser* browser = chrome::FindTabbedBrowser(profile_, false, desktop); 315 chrome::ShowFeedbackPage(browser, std::string(), 316 chrome::kAppLauncherCategoryTag); 317} 318 319void AppListViewDelegate::ToggleSpeechRecognition() { 320 app_list::StartPageService* service = 321 app_list::StartPageService::Get(profile_); 322 if (service) 323 service->ToggleSpeechRecognition(); 324} 325 326void AppListViewDelegate::ShowForProfileByPath( 327 const base::FilePath& profile_path) { 328 controller_->ShowForProfileByPath(profile_path); 329} 330 331void AppListViewDelegate::OnSpeechResult(const base::string16& result, 332 bool is_final) { 333 speech_ui_->SetSpeechResult(result, is_final); 334 if (is_final) { 335 auto_launch_timeout_ = base::TimeDelta::FromMilliseconds( 336 kAutoLaunchDefaultTimeoutMilliSec); 337 model_->search_box()->SetText(result); 338 } 339} 340 341void AppListViewDelegate::OnSpeechSoundLevelChanged(int16 level) { 342 speech_ui_->UpdateSoundLevel(level); 343} 344 345void AppListViewDelegate::OnSpeechRecognitionStateChanged( 346 app_list::SpeechRecognitionState new_state) { 347 speech_ui_->SetSpeechRecognitionState(new_state); 348} 349 350void AppListViewDelegate::Observe( 351 int type, 352 const content::NotificationSource& source, 353 const content::NotificationDetails& details) { 354 OnProfileChanged(); 355} 356 357void AppListViewDelegate::OnProfileAdded(const base::FilePath& profile_path) { 358 OnProfileChanged(); 359} 360 361void AppListViewDelegate::OnProfileWasRemoved( 362 const base::FilePath& profile_path, const base::string16& profile_name) { 363 OnProfileChanged(); 364} 365 366void AppListViewDelegate::OnProfileNameChanged( 367 const base::FilePath& profile_path, 368 const base::string16& old_profile_name) { 369 OnProfileChanged(); 370} 371 372content::WebContents* AppListViewDelegate::GetStartPageContents() { 373 app_list::StartPageService* service = 374 app_list::StartPageService::Get(profile_); 375 if (!service) 376 return NULL; 377 378 return service->GetStartPageContents(); 379} 380 381content::WebContents* AppListViewDelegate::GetSpeechRecognitionContents() { 382 app_list::StartPageService* service = 383 app_list::StartPageService::Get(profile_); 384 if (!service) 385 return NULL; 386 387 return service->GetSpeechRecognitionContents(); 388} 389 390const app_list::AppListViewDelegate::Users& 391AppListViewDelegate::GetUsers() const { 392 return users_; 393} 394 395void AppListViewDelegate::AddObserver( 396 app_list::AppListViewDelegateObserver* observer) { 397 observers_.AddObserver(observer); 398} 399 400void AppListViewDelegate::RemoveObserver( 401 app_list::AppListViewDelegateObserver* observer) { 402 observers_.RemoveObserver(observer); 403} 404