1 // Copyright (c) 2013 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/launcher/browser_shortcut_launcher_item_controller.h" 6 7 #include <vector> 8 9 #include "ash/launcher/launcher.h" 10 #include "ash/shell.h" 11 #include "ash/wm/window_util.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" 14 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h" 15 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" 16 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser_finder.h" 19 #include "chrome/browser/ui/browser_list.h" 20 #include "chrome/browser/ui/browser_window.h" 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" 22 #include "chrome/common/extensions/extension_constants.h" 23 #include "content/public/browser/web_contents.h" 24 #include "grit/ash_resources.h" 25 #include "grit/chromium_strings.h" 26 #include "grit/generated_resources.h" 27 #include "ui/aura/window.h" 28 #include "ui/base/events/event.h" 29 #include "ui/base/l10n/l10n_util.h" 30 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/gfx/image/image.h" 32 #include "ui/views/corewm/window_animations.h" 33 34 #if defined(OS_CHROMEOS) 35 #include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h" 36 #endif 37 38 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController( 39 ChromeLauncherControllerPerApp* launcher_controller, 40 Profile* profile) 41 : LauncherItemController(TYPE_SHORTCUT, 42 extension_misc::kChromeAppId, 43 launcher_controller), 44 app_controller_(launcher_controller), 45 profile_(profile) { 46 } 47 48 BrowserShortcutLauncherItemController:: 49 ~BrowserShortcutLauncherItemController() { 50 } 51 52 string16 BrowserShortcutLauncherItemController::GetTitle() { 53 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 54 } 55 56 bool BrowserShortcutLauncherItemController::HasWindow( 57 aura::Window* window) const { 58 const BrowserList* ash_browser_list = 59 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 60 for (BrowserList::const_iterator it = ash_browser_list->begin(); 61 it != ash_browser_list->end(); ++it) { 62 // During browser creation it is possible that this function is called 63 // before a browser got a window (see crbug.com/263563). 64 if ((*it)->window() && 65 (*it)->window()->GetNativeWindow() == window) 66 return true; 67 } 68 return false; 69 } 70 71 bool BrowserShortcutLauncherItemController::IsOpen() const { 72 const BrowserList* ash_browser_list = 73 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 74 return ash_browser_list->empty() ? false : true; 75 } 76 77 bool BrowserShortcutLauncherItemController::IsVisible() const { 78 Browser* last_browser = chrome::FindTabbedBrowser( 79 profile_, 80 true, 81 chrome::HOST_DESKTOP_TYPE_ASH); 82 83 if (!last_browser) { 84 return false; 85 } 86 87 aura::Window* window = last_browser->window()->GetNativeWindow(); 88 return ash::wm::IsActiveWindow(window); 89 } 90 91 void BrowserShortcutLauncherItemController::Launch(int event_flags) { 92 } 93 94 void BrowserShortcutLauncherItemController::Activate() { 95 Browser* last_browser = chrome::FindTabbedBrowser( 96 profile_, 97 true, 98 chrome::HOST_DESKTOP_TYPE_ASH); 99 100 if (!last_browser) { 101 launcher_controller()->CreateNewWindow(); 102 return; 103 } 104 105 launcher_controller()->ActivateWindowOrMinimizeIfActive( 106 last_browser->window(), GetApplicationList(0).size() == 2); 107 } 108 109 void BrowserShortcutLauncherItemController::Close() { 110 } 111 112 void BrowserShortcutLauncherItemController::LauncherItemChanged( 113 int model_index, 114 const ash::LauncherItem& old_item) { 115 } 116 117 void BrowserShortcutLauncherItemController::Clicked(const ui::Event& event) { 118 #if defined(OS_CHROMEOS) 119 chromeos::default_pinned_apps_field_trial::RecordShelfClick( 120 chromeos::default_pinned_apps_field_trial::CHROME); 121 #endif 122 123 if (event.flags() & ui::EF_CONTROL_DOWN) { 124 launcher_controller()->CreateNewWindow(); 125 return; 126 } 127 128 // In case of a keyboard event, we were called by a hotkey. In that case we 129 // activate the next item in line if an item of our list is already active. 130 if (event.type() & ui::ET_KEY_RELEASED) { 131 ActivateOrAdvanceToNextBrowser(); 132 return; 133 } 134 135 Activate(); 136 } 137 138 void BrowserShortcutLauncherItemController::OnRemoved() { 139 // BrowserShortcutLauncherItemController is owned by ChromeLauncherController. 140 } 141 142 ChromeLauncherAppMenuItems 143 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) { 144 ChromeLauncherAppMenuItems items; 145 bool found_tabbed_browser = false; 146 // Add the application name to the menu. 147 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); 148 const BrowserList* ash_browser_list = 149 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 150 for (BrowserList::const_iterator it = ash_browser_list->begin(); 151 it != ash_browser_list->end(); ++it) { 152 Browser* browser = *it; 153 // Make sure that the browser was already shown and it has a proper window. 154 if (std::find(ash_browser_list->begin_last_active(), 155 ash_browser_list->end_last_active(), 156 browser) == ash_browser_list->end_last_active() || 157 !browser->window()) 158 continue; 159 if (browser->is_type_tabbed()) 160 found_tabbed_browser = true; 161 else if (!app_controller_->IsBrowserRepresentedInBrowserList(browser)) 162 continue; 163 TabStripModel* tab_strip = browser->tab_strip_model(); 164 if (tab_strip->active_index() == -1) 165 continue; 166 if (!(event_flags & ui::EF_SHIFT_DOWN)) { 167 content::WebContents* web_contents = 168 tab_strip->GetWebContentsAt(tab_strip->active_index()); 169 gfx::Image app_icon = GetBrowserListIcon(web_contents); 170 string16 title = GetBrowserListTitle(web_contents); 171 items.push_back(new ChromeLauncherAppMenuItemBrowser( 172 title, &app_icon, browser, items.size() == 1)); 173 } else { 174 for (int index = 0; index < tab_strip->count(); ++index) { 175 content::WebContents* web_contents = 176 tab_strip->GetWebContentsAt(index); 177 gfx::Image app_icon = app_controller_->GetAppListIcon(web_contents); 178 string16 title = app_controller_->GetAppListTitle(web_contents); 179 // Check if we need to insert a separator in front. 180 bool leading_separator = !index; 181 items.push_back(new ChromeLauncherAppMenuItemTab( 182 title, &app_icon, web_contents, leading_separator)); 183 } 184 } 185 } 186 // If only windowed applications are open, we return an empty list to 187 // enforce the creation of a new browser. 188 if (!found_tabbed_browser) 189 items.clear(); 190 return items.Pass(); 191 } 192 193 gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon( 194 content::WebContents* web_contents) const { 195 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 196 return rb.GetImageNamed(IsIncognito(web_contents) ? 197 IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER : 198 IDR_AURA_LAUNCHER_LIST_BROWSER); 199 } 200 201 string16 BrowserShortcutLauncherItemController::GetBrowserListTitle( 202 content::WebContents* web_contents) const { 203 string16 title = web_contents->GetTitle(); 204 if (!title.empty()) 205 return title; 206 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE); 207 } 208 209 bool BrowserShortcutLauncherItemController::IsIncognito( 210 content::WebContents* web_contents) const { 211 const Profile* profile = 212 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 213 return profile->IsOffTheRecord() && !profile->IsGuestSession(); 214 } 215 216 void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() { 217 // Create a list of all suitable running browsers. 218 std::vector<Browser*> items; 219 // We use the list in the order of how the browsers got created - not the LRU 220 // order. 221 const BrowserList* ash_browser_list = 222 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 223 for (BrowserList::const_iterator it = 224 ash_browser_list->begin(); 225 it != ash_browser_list->end(); ++it) { 226 if (app_controller_->IsBrowserRepresentedInBrowserList(*it)) 227 items.push_back(*it); 228 } 229 // If there are no suitable browsers we create a new one. 230 if (!items.size()) { 231 launcher_controller()->CreateNewWindow(); 232 return; 233 } 234 Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()); 235 if (items.size() == 1) { 236 // If there is only one suitable browser, we can either activate it, or 237 // bounce it (if it is already active). 238 if (browser == items[0]) { 239 AnimateWindow(browser->window()->GetNativeWindow(), 240 views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE); 241 return; 242 } 243 browser = items[0]; 244 } else { 245 // If there is more then one suitable browser, we advance to the next if 246 // |current_browser| is already active - or - check the last used browser 247 // if it can be used. 248 std::vector<Browser*>::iterator i = 249 std::find(items.begin(), items.end(), browser); 250 if (i != items.end()) { 251 browser = (++i == items.end()) ? items[0] : *i; 252 } else { 253 browser = chrome::FindTabbedBrowser(profile_, 254 true, 255 chrome::HOST_DESKTOP_TYPE_ASH); 256 if (!browser || 257 !app_controller_->IsBrowserRepresentedInBrowserList(browser)) 258 browser = items[0]; 259 } 260 } 261 DCHECK(browser); 262 browser->window()->Show(); 263 browser->window()->Activate(); 264 } 265