chrome_shell_delegate.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/ash/chrome_shell_delegate.h" 6 7#include "apps/shell_window.h" 8#include "ash/ash_switches.h" 9#include "ash/host/root_window_host_factory.h" 10#include "ash/launcher/launcher_types.h" 11#include "ash/magnifier/magnifier_constants.h" 12#include "ash/session_state_delegate.h" 13#include "ash/shelf/shelf_widget.h" 14#include "ash/system/tray/system_tray_delegate.h" 15#include "ash/wm/window_properties.h" 16#include "ash/wm/window_util.h" 17#include "base/bind.h" 18#include "base/command_line.h" 19#include "base/prefs/pref_service.h" 20#include "base/strings/utf_string_conversions.h" 21#include "chrome/browser/app_mode/app_mode_utils.h" 22#include "chrome/browser/chrome_notification_types.h" 23#include "chrome/browser/extensions/shell_window_registry.h" 24#include "chrome/browser/lifetime/application_lifetime.h" 25#include "chrome/browser/profiles/profile_manager.h" 26#include "chrome/browser/sessions/tab_restore_service.h" 27#include "chrome/browser/sessions/tab_restore_service_factory.h" 28#include "chrome/browser/sessions/tab_restore_service_observer.h" 29#include "chrome/browser/ui/app_list/app_list_view_delegate.h" 30#include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h" 31#include "chrome/browser/ui/ash/ash_keyboard_controller_proxy.h" 32#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 33#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" 34#include "chrome/browser/ui/ash/user_action_handler.h" 35#include "chrome/browser/ui/ash/window_positioner.h" 36#include "chrome/browser/ui/browser.h" 37#include "chrome/browser/ui/browser_commands.h" 38#include "chrome/browser/ui/browser_finder.h" 39#include "chrome/browser/ui/browser_window.h" 40#include "chrome/browser/ui/extensions/native_app_window.h" 41#include "chrome/browser/ui/host_desktop.h" 42#include "chrome/browser/ui/immersive_fullscreen_configuration.h" 43#include "chrome/common/chrome_switches.h" 44#include "chrome/common/time_format.h" 45#include "content/public/browser/notification_service.h" 46#include "content/public/browser/user_metrics.h" 47#include "grit/chromium_strings.h" 48#include "grit/generated_resources.h" 49#include "ui/aura/client/user_action_client.h" 50#include "ui/aura/window.h" 51#include "ui/base/l10n/l10n_util.h" 52 53#if defined(OS_CHROMEOS) 54#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h" 55#endif 56 57// static 58ChromeShellDelegate* ChromeShellDelegate::instance_ = NULL; 59 60namespace { 61 62void RestoreTabUsingProfile(Profile* profile) { 63 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile); 64 service->RestoreMostRecentEntry(NULL, chrome::HOST_DESKTOP_TYPE_ASH); 65} 66 67} // namespace 68 69// TabRestoreHelper is used to restore a tab. In particular when the user 70// attempts to a restore a tab if the TabRestoreService hasn't finished loading 71// this waits for it. Once the TabRestoreService finishes loading the tab is 72// restored. 73class ChromeShellDelegate::TabRestoreHelper : public TabRestoreServiceObserver { 74 public: 75 TabRestoreHelper(ChromeShellDelegate* delegate, 76 Profile* profile, 77 TabRestoreService* service) 78 : delegate_(delegate), 79 profile_(profile), 80 tab_restore_service_(service) { 81 tab_restore_service_->AddObserver(this); 82 } 83 84 virtual ~TabRestoreHelper() { 85 tab_restore_service_->RemoveObserver(this); 86 } 87 88 TabRestoreService* tab_restore_service() { return tab_restore_service_; } 89 90 virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE { 91 } 92 virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE { 93 // This destroys us. 94 delegate_->tab_restore_helper_.reset(); 95 } 96 97 virtual void TabRestoreServiceLoaded(TabRestoreService* service) OVERRIDE { 98 RestoreTabUsingProfile(profile_); 99 // This destroys us. 100 delegate_->tab_restore_helper_.reset(); 101 } 102 103 private: 104 ChromeShellDelegate* delegate_; 105 Profile* profile_; 106 TabRestoreService* tab_restore_service_; 107 108 DISALLOW_COPY_AND_ASSIGN(TabRestoreHelper); 109}; 110 111ChromeShellDelegate::ChromeShellDelegate() 112 : window_positioner_(new ash::WindowPositioner()), 113 weak_factory_(this), 114 launcher_delegate_(NULL) { 115 instance_ = this; 116 PlatformInit(); 117} 118 119ChromeShellDelegate::~ChromeShellDelegate() { 120 if (instance_ == this) 121 instance_ = NULL; 122} 123 124bool ChromeShellDelegate::IsMultiProfilesEnabled() const { 125 return CommandLine::ForCurrentProcess()->HasSwitch(switches::kMultiProfiles); 126} 127 128bool ChromeShellDelegate::IsRunningInForcedAppMode() const { 129 return chrome::IsRunningInForcedAppMode(); 130} 131 132void ChromeShellDelegate::Exit() { 133 chrome::AttemptUserExit(); 134} 135 136void ChromeShellDelegate::NewTab() { 137 Browser* browser = GetTargetBrowser(); 138 // If the browser was not active, we call BrowserWindow::Show to make it 139 // visible. Otherwise, we let Browser::NewTab handle the active window change. 140 const bool was_active = browser->window()->IsActive(); 141 chrome::NewTab(browser); 142 if (!was_active) 143 browser->window()->Show(); 144} 145 146void ChromeShellDelegate::NewWindow(bool is_incognito) { 147 Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord(); 148 chrome::NewEmptyWindow( 149 is_incognito ? profile->GetOffTheRecordProfile() : profile, 150 chrome::HOST_DESKTOP_TYPE_ASH); 151} 152 153void ChromeShellDelegate::ToggleFullscreen() { 154 // Only toggle if the user has a window open. 155 aura::Window* window = ash::wm::GetActiveWindow(); 156 if (!window) 157 return; 158 159 bool is_fullscreen = ash::wm::IsWindowFullscreen(window); 160 161 // Windows which cannot be maximized should not be fullscreened. 162 if (!is_fullscreen && !ash::wm::CanMaximizeWindow(window)) 163 return; 164 165 Browser* browser = chrome::FindBrowserWithWindow(window); 166 if (browser) { 167 // If a window is fullscreen, exit fullscreen. 168 if (is_fullscreen) { 169 chrome::ToggleFullscreenMode(browser); 170 return; 171 } 172 173 // AppNonClientFrameViewAsh shows only the window controls and no other 174 // window decorations which is pretty close to fullscreen. Put v1 apps 175 // into maximized mode instead of fullscreen to avoid showing the ugly 176 // fullscreen exit bubble. 177#if defined(OS_WIN) 178 if (browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_NATIVE) { 179 chrome::ToggleFullscreenMode(browser); 180 return; 181 } 182#endif // OS_WIN 183 if (browser->is_app() && browser->app_type() != Browser::APP_TYPE_CHILD) 184 ash::wm::ToggleMaximizedWindow(window); 185 else 186 chrome::ToggleFullscreenMode(browser); 187 return; 188 } 189 190 // |window| may belong to a shell window. 191 apps::ShellWindow* shell_window = extensions::ShellWindowRegistry:: 192 GetShellWindowForNativeWindowAnyProfile(window); 193 if (shell_window) { 194 if (is_fullscreen) 195 shell_window->Restore(); 196 else 197 shell_window->Fullscreen(); 198 } 199} 200 201void ChromeShellDelegate::ToggleMaximized() { 202 // Only toggle if the user has a window open. 203 aura::Window* window = ash::wm::GetActiveWindow(); 204 if (!window) 205 return; 206 207 // Get out of fullscreen when in fullscreen mode. 208 if (ash::wm::IsWindowFullscreen(window)) { 209 ToggleFullscreen(); 210 return; 211 } 212 ash::wm::ToggleMaximizedWindow(window); 213} 214 215void ChromeShellDelegate::RestoreTab() { 216 if (tab_restore_helper_.get()) { 217 DCHECK(!tab_restore_helper_->tab_restore_service()->IsLoaded()); 218 return; 219 } 220 221 Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()); 222 Profile* profile = browser ? browser->profile() : NULL; 223 if (!profile) 224 profile = ProfileManager::GetDefaultProfileOrOffTheRecord(); 225 if (profile->IsOffTheRecord()) 226 return; 227 TabRestoreService* service = 228 TabRestoreServiceFactory::GetForProfile(profile); 229 if (!service) 230 return; 231 232 if (service->IsLoaded()) { 233 RestoreTabUsingProfile(profile); 234 } else { 235 tab_restore_helper_.reset(new TabRestoreHelper(this, profile, service)); 236 service->LoadTabsFromLastSession(); 237 } 238} 239 240void ChromeShellDelegate::ShowTaskManager() { 241 chrome::OpenTaskManager(NULL); 242} 243 244content::BrowserContext* ChromeShellDelegate::GetCurrentBrowserContext() { 245 return ProfileManager::GetDefaultProfile(); 246} 247 248app_list::AppListViewDelegate* 249 ChromeShellDelegate::CreateAppListViewDelegate() { 250 DCHECK(ash::Shell::HasInstance()); 251 // Shell will own the created delegate, and the delegate will own 252 // the controller. 253 Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord(); 254 return new AppListViewDelegate(new AppListControllerDelegateAsh(), profile); 255} 256 257ash::LauncherDelegate* ChromeShellDelegate::CreateLauncherDelegate( 258 ash::LauncherModel* model) { 259 DCHECK(ProfileManager::IsGetDefaultProfileAllowed()); 260 // TODO(oshima): This is currently broken with multiple launchers. 261 // Refactor so that there is just one launcher delegate in the 262 // shell. 263 if (!launcher_delegate_) { 264 launcher_delegate_ = ChromeLauncherController::CreateInstance(NULL, model); 265 launcher_delegate_->Init(); 266 } 267 return launcher_delegate_; 268} 269 270aura::client::UserActionClient* ChromeShellDelegate::CreateUserActionClient() { 271 return new UserActionHandler; 272} 273 274void ChromeShellDelegate::OpenFeedbackPage() { 275 chrome::OpenFeedbackDialog(GetTargetBrowser()); 276} 277 278void ChromeShellDelegate::RecordUserMetricsAction( 279 ash::UserMetricsAction action) { 280 switch (action) { 281 case ash::UMA_ACCEL_KEYBOARD_BRIGHTNESS_DOWN_F6: 282 content::RecordAction( 283 content::UserMetricsAction("Accel_KeyboardBrightnessDown_F6")); 284 break; 285 case ash::UMA_ACCEL_KEYBOARD_BRIGHTNESS_UP_F7: 286 content::RecordAction( 287 content::UserMetricsAction("Accel_KeyboardBrightnessUp_F7")); 288 break; 289 case ash::UMA_ACCEL_LOCK_SCREEN_L: 290 content::RecordAction( 291 content::UserMetricsAction("Accel_LockScreen_L")); 292 break; 293 case ash::UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON: 294 content::RecordAction( 295 content::UserMetricsAction("Accel_LockScreen_LockButton")); 296 break; 297 case ash::UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON: 298 content::RecordAction( 299 content::UserMetricsAction("Accel_LockScreen_PowerButton")); 300 break; 301 case ash::UMA_ACCEL_FULLSCREEN_F4: 302 content::RecordAction(content::UserMetricsAction("Accel_Fullscreen_F4")); 303 break; 304 case ash::UMA_ACCEL_MAXIMIZE_RESTORE_F4: 305 content::RecordAction( 306 content::UserMetricsAction("Accel_Maximize_Restore_F4")); 307 break; 308 case ash::UMA_ACCEL_NEWTAB_T: 309 content::RecordAction(content::UserMetricsAction("Accel_NewTab_T")); 310 break; 311 case ash::UMA_ACCEL_NEXTWINDOW_F5: 312 content::RecordAction(content::UserMetricsAction("Accel_NextWindow_F5")); 313 break; 314 case ash::UMA_ACCEL_NEXTWINDOW_TAB: 315 content::RecordAction(content::UserMetricsAction("Accel_NextWindow_Tab")); 316 break; 317 case ash::UMA_ACCEL_PREVWINDOW_F5: 318 content::RecordAction(content::UserMetricsAction("Accel_PrevWindow_F5")); 319 break; 320 case ash::UMA_ACCEL_PREVWINDOW_TAB: 321 content::RecordAction(content::UserMetricsAction("Accel_PrevWindow_Tab")); 322 break; 323 case ash::UMA_ACCEL_EXIT_FIRST_Q: 324 content::RecordAction(content::UserMetricsAction("Accel_Exit_First_Q")); 325 break; 326 case ash::UMA_ACCEL_EXIT_SECOND_Q: 327 content::RecordAction(content::UserMetricsAction("Accel_Exit_Second_Q")); 328 break; 329 case ash::UMA_ACCEL_SEARCH_LWIN: 330 content::RecordAction(content::UserMetricsAction("Accel_Search_LWin")); 331 break; 332 case ash::UMA_ACCEL_SHUT_DOWN_POWER_BUTTON: 333 content::RecordAction( 334 content::UserMetricsAction("Accel_ShutDown_PowerButton")); 335 break; 336 case ash::UMA_CLOSE_THROUGH_CONTEXT_MENU: 337 content::RecordAction(content::UserMetricsAction("CloseFromContextMenu")); 338 break; 339 case ash::UMA_LAUNCHER_CLICK_ON_APP: 340 content::RecordAction(content::UserMetricsAction("Launcher_ClickOnApp")); 341 break; 342 case ash::UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON: 343 content::RecordAction( 344 content::UserMetricsAction("Launcher_ClickOnApplistButton")); 345#if defined(OS_CHROMEOS) 346 chromeos::default_pinned_apps_field_trial::RecordShelfClick( 347 chromeos::default_pinned_apps_field_trial::APP_LAUNCHER); 348#endif 349 break; 350 case ash::UMA_MINIMIZE_PER_KEY: 351 content::RecordAction(content::UserMetricsAction("Minimize_UsingKey")); 352 break; 353 case ash::UMA_MOUSE_DOWN: 354 content::RecordAction(content::UserMetricsAction("Mouse_Down")); 355 break; 356 case ash::UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK: 357 content::RecordAction( 358 content::UserMetricsAction("Caption_ClickTogglesMaximize")); 359 break; 360 case ash::UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE: 361 content::RecordAction( 362 content::UserMetricsAction("Caption_GestureTogglesMaximize")); 363 break; 364 case ash::UMA_TOUCHSCREEN_TAP_DOWN: 365 content::RecordAction(content::UserMetricsAction("Touchscreen_Down")); 366 break; 367 case ash::UMA_TRAY_HELP: 368 content::RecordAction(content::UserMetricsAction("Tray_Help")); 369 break; 370 case ash::UMA_TRAY_LOCK_SCREEN: 371 content::RecordAction(content::UserMetricsAction("Tray_LockScreen")); 372 break; 373 case ash::UMA_TRAY_SHUT_DOWN: 374 content::RecordAction(content::UserMetricsAction("Tray_ShutDown")); 375 break; 376 case ash::UMA_WINDOW_APP_CLOSE_BUTTON_CLICK: 377 content::RecordAction(content::UserMetricsAction("AppCloseButton_Clk")); 378 break; 379 case ash::UMA_WINDOW_CLOSE_BUTTON_CLICK: 380 content::RecordAction(content::UserMetricsAction("CloseButton_Clk")); 381 break; 382 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN: 383 content::RecordAction(content::UserMetricsAction("MaxButton_Clk_ExitFS")); 384 break; 385 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE: 386 content::RecordAction( 387 content::UserMetricsAction("MaxButton_Clk_Restore")); 388 break; 389 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE: 390 content::RecordAction( 391 content::UserMetricsAction("MaxButton_Clk_Maximize")); 392 break; 393 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE: 394 content::RecordAction(content::UserMetricsAction("MinButton_Clk")); 395 break; 396 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE: 397 content::RecordAction(content::UserMetricsAction("MaxButton_Maximize")); 398 break; 399 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT: 400 content::RecordAction(content::UserMetricsAction("MaxButton_MaxLeft")); 401 break; 402 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT: 403 content::RecordAction(content::UserMetricsAction("MaxButton_MaxRight")); 404 break; 405 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_MINIMIZE: 406 content::RecordAction(content::UserMetricsAction("MaxButton_Minimize")); 407 break; 408 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_RESTORE: 409 content::RecordAction(content::UserMetricsAction("MaxButton_Restore")); 410 break; 411 case ash::UMA_WINDOW_MAXIMIZE_BUTTON_SHOW_BUBBLE: 412 content::RecordAction(content::UserMetricsAction("MaxButton_ShowBubble")); 413 break; 414 } 415} 416 417string16 ChromeShellDelegate::GetTimeRemainingString(base::TimeDelta delta) { 418 return TimeFormat::TimeRemainingLong(delta); 419} 420 421string16 ChromeShellDelegate::GetTimeDurationLongString(base::TimeDelta delta) { 422 return TimeFormat::TimeDurationLong(delta); 423} 424 425ui::MenuModel* ChromeShellDelegate::CreateContextMenu(aura::RootWindow* root) { 426 DCHECK(launcher_delegate_); 427 // Don't show context menu for exclusive app runtime mode. 428 if (chrome::IsRunningInAppMode()) 429 return NULL; 430 431 return new LauncherContextMenu(launcher_delegate_, root); 432} 433 434ash::RootWindowHostFactory* ChromeShellDelegate::CreateRootWindowHostFactory() { 435 return ash::RootWindowHostFactory::Create(); 436} 437 438string16 ChromeShellDelegate::GetProductName() const { 439 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 440} 441 442Browser* ChromeShellDelegate::GetTargetBrowser() { 443 Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()); 444 if (browser) 445 return browser; 446 return chrome::FindOrCreateTabbedBrowser( 447 ProfileManager::GetDefaultProfileOrOffTheRecord(), 448 chrome::HOST_DESKTOP_TYPE_ASH); 449} 450 451keyboard::KeyboardControllerProxy* 452 ChromeShellDelegate::CreateKeyboardControllerProxy() { 453 return new AshKeyboardControllerProxy(); 454} 455