Home | History | Annotate | Download | only in launcher
      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