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