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