app_list_view_delegate.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner// Copyright (c) 2012 The Chromium Authors. All rights reserved. 214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner// Use of this source code is governed by a BSD-style license that can be 314852f27e792470232287371c5ffd4cee1d5b943Chris Lattner// found in the LICENSE file. 414852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 514852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/app_list_view_delegate.h" 614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include <vector> 814852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 914852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "base/callback.h" 1014852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "base/files/file_path.h" 1114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "base/metrics/user_metrics.h" 1214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "base/stl_util.h" 1314852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/browser_process.h" 1414852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/chrome_notification_types.h" 1514852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/extensions/extension_service.h" 1614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/feedback/feedback_util.h" 1714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/profiles/profile_info_cache.h" 180b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "chrome/browser/profiles/profile_manager.h" 1914852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 2014852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/app_list_service.h" 2114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/app_list_syncable_service.h" 2214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" 2314852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/search/search_controller.h" 2414852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/app_list/start_page_service.h" 2514852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/browser_finder.h" 2614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/chrome_pages.h" 2714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/host_desktop.h" 2814852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 2914852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/web_applications/web_app.h" 3014852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/common/extensions/extension_constants.h" 3114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/common/url_constants.h" 3214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "components/signin/core/browser/signin_manager.h" 3314852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "content/public/browser/browser_thread.h" 3414852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "content/public/browser/page_navigator.h" 3514852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "content/public/browser/user_metrics.h" 3614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "grit/theme_resources.h" 3714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "ui/app_list/app_list_view_delegate_observer.h" 3814852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "ui/app_list/search_box_model.h" 3914852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "ui/app_list/speech_ui_model.h" 4014852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "ui/base/resource/resource_bundle.h" 4114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 4214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#if defined(USE_ASH) 4379fca6fea87be7221843031870bbf2c9ae1fc555Dan Gohman#include "chrome/browser/ui/ash/app_list/app_sync_ui_state_watcher.h" 4479fca6fea87be7221843031870bbf2c9ae1fc555Dan Gohman#endif 4514852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 4614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#if defined(OS_WIN) 4714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#include "chrome/browser/web_applications/web_app_win.h" 4814852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#endif 49dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 5014852f27e792470232287371c5ffd4cee1d5b943Chris Lattnernamespace { 5114852f27e792470232287371c5ffd4cee1d5b943Chris Lattner 5214852f27e792470232287371c5ffd4cee1d5b943Chris Lattnerconst int kAutoLaunchDefaultTimeoutMilliSec = 50; 53dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 5414852f27e792470232287371c5ffd4cee1d5b943Chris Lattner#if defined(OS_WIN) 5514852f27e792470232287371c5ffd4cee1d5b943Chris Lattnervoid CreateShortcutInWebAppDir( 5614852f27e792470232287371c5ffd4cee1d5b943Chris Lattner const base::FilePath& app_data_dir, 5714852f27e792470232287371c5ffd4cee1d5b943Chris Lattner base::Callback<void(const base::FilePath&)> callback, 5814852f27e792470232287371c5ffd4cee1d5b943Chris Lattner const web_app::ShortcutInfo& info) { 5914852f27e792470232287371c5ffd4cee1d5b943Chris Lattner content::BrowserThread::PostTaskAndReplyWithResult( 6014852f27e792470232287371c5ffd4cee1d5b943Chris Lattner content::BrowserThread::FILE, 61f0443c1eb44d737d9bd78962932fc80f74c6113cDaniel Dunbar FROM_HERE, 6214852f27e792470232287371c5ffd4cee1d5b943Chris Lattner base::Bind(web_app::CreateShortcutInWebAppDir, app_data_dir, info), 6314852f27e792470232287371c5ffd4cee1d5b943Chris Lattner callback); 64} 65#endif 66 67void PopulateUsers(const ProfileInfoCache& profile_info, 68 const base::FilePath& active_profile_path, 69 app_list::AppListViewDelegate::Users* users) { 70 users->clear(); 71 const size_t count = profile_info.GetNumberOfProfiles(); 72 for (size_t i = 0; i < count; ++i) { 73 // Don't display managed users. 74 if (profile_info.ProfileIsManagedAtIndex(i)) 75 continue; 76 77 app_list::AppListViewDelegate::User user; 78 user.name = profile_info.GetNameOfProfileAtIndex(i); 79 user.email = profile_info.GetUserNameOfProfileAtIndex(i); 80 user.profile_path = profile_info.GetPathOfProfileAtIndex(i); 81 user.signin_required = profile_info.ProfileIsSigninRequiredAtIndex(i); 82 user.active = active_profile_path == user.profile_path; 83 users->push_back(user); 84 } 85} 86 87} // namespace 88 89AppListViewDelegate::AppListViewDelegate(Profile* profile, 90 AppListControllerDelegate* controller) 91 : controller_(controller), 92 profile_(profile), 93 model_(NULL), 94 scoped_observer_(this) { 95 CHECK(controller_); 96 SigninManagerFactory::GetInstance()->AddObserver(this); 97 98 // Start observing all already-created SigninManagers. 99 ProfileManager* profile_manager = g_browser_process->profile_manager(); 100 std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles(); 101 for (std::vector<Profile*>::iterator i = profiles.begin(); 102 i != profiles.end(); 103 ++i) { 104 SigninManagerBase* manager = 105 SigninManagerFactory::GetForProfileIfExists(*i); 106 if (manager) { 107 DCHECK(!scoped_observer_.IsObserving(manager)); 108 scoped_observer_.Add(manager); 109 } 110 } 111 112 profile_manager->GetProfileInfoCache().AddObserver(this); 113 114 app_list::StartPageService* service = 115 app_list::StartPageService::Get(profile_); 116 speech_ui_.reset(new app_list::SpeechUIModel( 117 service ? service->state() : app_list::SPEECH_RECOGNITION_OFF)); 118 119#if defined(GOOGLE_CHROME_BUILD) 120 speech_ui_->set_logo( 121 *ui::ResourceBundle::GetSharedInstance(). 122 GetImageSkiaNamed(IDR_APP_LIST_GOOGLE_LOGO_VOICE_SEARCH)); 123#endif 124 125 OnProfileChanged(); // sets model_ 126 if (service) 127 service->AddObserver(this); 128} 129 130AppListViewDelegate::~AppListViewDelegate() { 131 app_list::StartPageService* service = 132 app_list::StartPageService::Get(profile_); 133 if (service) 134 service->RemoveObserver(this); 135 g_browser_process-> 136 profile_manager()->GetProfileInfoCache().RemoveObserver(this); 137 138 SigninManagerFactory* factory = SigninManagerFactory::GetInstance(); 139 if (factory) 140 factory->RemoveObserver(this); 141 142 // Ensure search controller is released prior to speech_ui_. 143 search_controller_.reset(); 144} 145 146void AppListViewDelegate::SigninManagerCreated(SigninManagerBase* manager) { 147 scoped_observer_.Add(manager); 148} 149 150void AppListViewDelegate::SigninManagerShutdown(SigninManagerBase* manager) { 151 if (scoped_observer_.IsObserving(manager)) 152 scoped_observer_.Remove(manager); 153} 154 155void AppListViewDelegate::GoogleSigninFailed( 156 const GoogleServiceAuthError& error) { 157 OnProfileChanged(); 158} 159 160void AppListViewDelegate::GoogleSigninSucceeded(const std::string& username, 161 const std::string& password) { 162 OnProfileChanged(); 163} 164 165void AppListViewDelegate::GoogleSignedOut(const std::string& username) { 166 OnProfileChanged(); 167} 168 169void AppListViewDelegate::OnProfileChanged() { 170 model_ = app_list::AppListSyncableServiceFactory::GetForProfile( 171 profile_)->model(); 172 173 search_controller_.reset(new app_list::SearchController( 174 profile_, model_->search_box(), model_->results(), 175 speech_ui_.get(), controller_)); 176 177 signin_delegate_.SetProfile(profile_); 178 179#if defined(USE_ASH) 180 app_sync_ui_state_watcher_.reset(new AppSyncUIStateWatcher(profile_, model_)); 181#endif 182 183 // Don't populate the app list users if we are on the ash desktop. 184 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 185 controller_->GetAppListWindow()); 186 if (desktop == chrome::HOST_DESKTOP_TYPE_ASH) 187 return; 188 189 // Populate the app list users. 190 PopulateUsers(g_browser_process->profile_manager()->GetProfileInfoCache(), 191 profile_->GetPath(), &users_); 192 193 FOR_EACH_OBSERVER(app_list::AppListViewDelegateObserver, 194 observers_, 195 OnProfilesChanged()); 196} 197 198bool AppListViewDelegate::ForceNativeDesktop() const { 199 return controller_->ForceNativeDesktop(); 200} 201 202void AppListViewDelegate::SetProfileByPath(const base::FilePath& profile_path) { 203 DCHECK(model_); 204 205 // The profile must be loaded before this is called. 206 profile_ = 207 g_browser_process->profile_manager()->GetProfileByPath(profile_path); 208 DCHECK(profile_); 209 210 OnProfileChanged(); 211 212 // Clear search query. 213 model_->search_box()->SetText(base::string16()); 214} 215 216app_list::AppListModel* AppListViewDelegate::GetModel() { 217 return model_; 218} 219 220app_list::SigninDelegate* AppListViewDelegate::GetSigninDelegate() { 221 return &signin_delegate_; 222} 223 224app_list::SpeechUIModel* AppListViewDelegate::GetSpeechUI() { 225 return speech_ui_.get(); 226} 227 228void AppListViewDelegate::GetShortcutPathForApp( 229 const std::string& app_id, 230 const base::Callback<void(const base::FilePath&)>& callback) { 231#if defined(OS_WIN) 232 ExtensionService* service = profile_->GetExtensionService(); 233 DCHECK(service); 234 const extensions::Extension* extension = 235 service->GetInstalledExtension(app_id); 236 if (!extension) { 237 callback.Run(base::FilePath()); 238 return; 239 } 240 241 base::FilePath app_data_dir( 242 web_app::GetWebAppDataDirectory(profile_->GetPath(), 243 extension->id(), 244 GURL())); 245 246 web_app::UpdateShortcutInfoAndIconForApp( 247 extension, 248 profile_, 249 base::Bind(CreateShortcutInWebAppDir, app_data_dir, callback)); 250#else 251 callback.Run(base::FilePath()); 252#endif 253} 254 255void AppListViewDelegate::StartSearch() { 256 if (search_controller_) 257 search_controller_->Start(); 258} 259 260void AppListViewDelegate::StopSearch() { 261 if (search_controller_) 262 search_controller_->Stop(); 263} 264 265void AppListViewDelegate::OpenSearchResult( 266 app_list::SearchResult* result, 267 bool auto_launch, 268 int event_flags) { 269 if (auto_launch) 270 base::RecordAction(base::UserMetricsAction("AppList_AutoLaunched")); 271 search_controller_->OpenResult(result, event_flags); 272} 273 274void AppListViewDelegate::InvokeSearchResultAction( 275 app_list::SearchResult* result, 276 int action_index, 277 int event_flags) { 278 search_controller_->InvokeResultAction(result, action_index, event_flags); 279} 280 281base::TimeDelta AppListViewDelegate::GetAutoLaunchTimeout() { 282 return auto_launch_timeout_; 283} 284 285void AppListViewDelegate::AutoLaunchCanceled() { 286 base::RecordAction(base::UserMetricsAction("AppList_AutoLaunchCanceled")); 287 auto_launch_timeout_ = base::TimeDelta(); 288} 289 290void AppListViewDelegate::ViewInitialized() { 291 app_list::StartPageService* service = 292 app_list::StartPageService::Get(profile_); 293 if (service) 294 service->AppListShown(); 295} 296 297void AppListViewDelegate::Dismiss() { 298 controller_->DismissView(); 299} 300 301void AppListViewDelegate::ViewClosing() { 302 controller_->ViewClosing(); 303 304 app_list::StartPageService* service = 305 app_list::StartPageService::Get(profile_); 306 if (service) 307 service->AppListHidden(); 308} 309 310gfx::ImageSkia AppListViewDelegate::GetWindowIcon() { 311 return controller_->GetWindowIcon(); 312} 313 314void AppListViewDelegate::OpenSettings() { 315 ExtensionService* service = profile_->GetExtensionService(); 316 DCHECK(service); 317 const extensions::Extension* extension = service->GetInstalledExtension( 318 extension_misc::kSettingsAppId); 319 DCHECK(extension); 320 controller_->ActivateApp(profile_, 321 extension, 322 AppListControllerDelegate::LAUNCH_FROM_UNKNOWN, 323 0); 324} 325 326void AppListViewDelegate::OpenHelp() { 327 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 328 controller_->GetAppListWindow()); 329 chrome::ScopedTabbedBrowserDisplayer displayer(profile_, desktop); 330 content::OpenURLParams params(GURL(chrome::kAppLauncherHelpURL), 331 content::Referrer(), 332 NEW_FOREGROUND_TAB, 333 content::PAGE_TRANSITION_LINK, 334 false); 335 displayer.browser()->OpenURL(params); 336} 337 338void AppListViewDelegate::OpenFeedback() { 339 chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow( 340 controller_->GetAppListWindow()); 341 Browser* browser = chrome::FindTabbedBrowser(profile_, false, desktop); 342 chrome::ShowFeedbackPage(browser, std::string(), 343 chrome::kAppLauncherCategoryTag); 344} 345 346void AppListViewDelegate::ToggleSpeechRecognition() { 347 app_list::StartPageService* service = 348 app_list::StartPageService::Get(profile_); 349 if (service) 350 service->ToggleSpeechRecognition(); 351} 352 353void AppListViewDelegate::ShowForProfileByPath( 354 const base::FilePath& profile_path) { 355 controller_->ShowForProfileByPath(profile_path); 356} 357 358void AppListViewDelegate::OnSpeechResult(const base::string16& result, 359 bool is_final) { 360 speech_ui_->SetSpeechResult(result, is_final); 361 if (is_final) { 362 auto_launch_timeout_ = base::TimeDelta::FromMilliseconds( 363 kAutoLaunchDefaultTimeoutMilliSec); 364 model_->search_box()->SetText(result); 365 } 366} 367 368void AppListViewDelegate::OnSpeechSoundLevelChanged(int16 level) { 369 speech_ui_->UpdateSoundLevel(level); 370} 371 372void AppListViewDelegate::OnSpeechRecognitionStateChanged( 373 app_list::SpeechRecognitionState new_state) { 374 speech_ui_->SetSpeechRecognitionState(new_state); 375} 376 377void AppListViewDelegate::OnProfileAdded(const base::FilePath& profile_path) { 378 OnProfileChanged(); 379} 380 381void AppListViewDelegate::OnProfileWasRemoved( 382 const base::FilePath& profile_path, const base::string16& profile_name) { 383 OnProfileChanged(); 384} 385 386void AppListViewDelegate::OnProfileNameChanged( 387 const base::FilePath& profile_path, 388 const base::string16& old_profile_name) { 389 OnProfileChanged(); 390} 391 392content::WebContents* AppListViewDelegate::GetStartPageContents() { 393 app_list::StartPageService* service = 394 app_list::StartPageService::Get(profile_); 395 if (!service) 396 return NULL; 397 398 return service->GetStartPageContents(); 399} 400 401content::WebContents* AppListViewDelegate::GetSpeechRecognitionContents() { 402 app_list::StartPageService* service = 403 app_list::StartPageService::Get(profile_); 404 if (!service) 405 return NULL; 406 407 return service->GetSpeechRecognitionContents(); 408} 409 410const app_list::AppListViewDelegate::Users& 411AppListViewDelegate::GetUsers() const { 412 return users_; 413} 414 415void AppListViewDelegate::AddObserver( 416 app_list::AppListViewDelegateObserver* observer) { 417 observers_.AddObserver(observer); 418} 419 420void AppListViewDelegate::RemoveObserver( 421 app_list::AppListViewDelegateObserver* observer) { 422 observers_.RemoveObserver(observer); 423} 424