app_shortcut_launcher_item_controller.cc revision 3551c9c881056c480085172ff9840cab31610854
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "apps/native_app_window.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/wm/window_util.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_process_manager.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/favicon/favicon_tab_helper.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/window.h" 25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ui/base/events/event.h" 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/corewm/window_animations.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The time delta between clicks in which clicks to launch V2 apps are ignored. 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kClickSuppressionInMS = 1000; 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Item controller for an app shortcut. Shortcuts track app and launcher ids, 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// but do not have any associated windows (opening a shortcut will replace the 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// item with the appropriate LauncherItemController type). 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::AppShortcutLauncherItemController( 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& app_id, 423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ChromeLauncherController* controller) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : LauncherItemController(TYPE_SHORTCUT, app_id, controller), 443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_(controller) { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // To detect V1 applications we use their domain and match them against the 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // used URL. This will also work with applications like Google Drive. 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id); 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Some unit tests have no real extension. 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (extension) { 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) set_refocus_url(GURL( 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) extensions::AppLaunchInfo::GetLaunchWebURL(extension).spec() + "*")); 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::~AppShortcutLauncherItemController() { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 AppShortcutLauncherItemController::GetTitle() { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return GetAppTitle(); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool AppShortcutLauncherItemController::IsCurrentlyShownInWindow( 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) aura::Window* window) const { 653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Browser* browser = chrome::FindBrowserWithWindow(window); 663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) content::WebContents* active_content_of_window = 673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL; 683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id()); 713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) std::vector<content::WebContents*>::const_iterator iter = 733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) std::find(content.begin(), content.end(), active_content_of_window); 743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return iter != content.end() ? true : false; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::IsOpen() const { 793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return !chrome_launcher_controller_-> 803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) GetV1ApplicationsFromAppId(app_id()).empty(); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::IsVisible() const { 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Return true if any browser window associated with the app is visible. 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id()); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content.size(); i++) { 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content[i]); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (browser && browser->window()->GetNativeWindow()->IsVisible()) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::Launch(int event_flags) { 963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->LaunchApp(app_id(), event_flags); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::Activate() { 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* content = GetLRUApplication(); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!content) { 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (IsV2App()) { 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Ideally we come here only once. After that ShellLauncherItemController 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // will take over when the shell window gets opened. However there are 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // apps which take a lot of time for pre-processing (like the files app) 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // before they open a window. Since there is currently no other way to 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // detect if an app was started we suppress any further clicks within a 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // special time out. 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!AllowNextLaunchAttempt()) 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Launch(ui::EF_NONE); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ActivateContent(content); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::Close() { 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Close all running 'programs' of this type. 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->GetV1ApplicationsFromAppId(app_id()); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content.size(); i++) { 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content[i]); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!browser) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int index = tab_strip->GetIndexOfWebContents(content[i]); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(index != TabStripModel::kNoTab); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_NONE); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::Clicked(const ui::Event& event) { 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // In case of a keyboard event, we were called by a hotkey. In that case we 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // activate the next item in line if an item of our list is already active. 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event.type() == ui::ET_KEY_RELEASED) { 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (AdvanceToNextApp()) 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Activate(); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::OnRemoved() { 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // AppShortcutLauncherItemController is unowned; delete on removal. 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete this; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::LauncherItemChanged( 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index, 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ash::LauncherItem& old_item) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeLauncherAppMenuItems 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)AppShortcutLauncherItemController::GetApplicationList(int event_flags) { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChromeLauncherAppMenuItems items; 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add the application name to the menu. 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*> content_list = GetRunningApplications(); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content_list.size(); i++) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = content_list[i]; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the icon. 1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents); 1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) string16 title = launcher_controller()->GetAppListTitle(web_contents); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(new ChromeLauncherAppMenuItemTab( 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title, &app_icon, web_contents, i == 0)); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items.Pass(); 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::vector<content::WebContents*> 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::GetRunningApplications() { 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> items; 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLPattern refocus_pattern(URLPattern::SCHEME_ALL); 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(true); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!refocus_url_.is_empty()) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(false); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.Parse(refocus_url_.spec()); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It is possible to come here While an extension gets loaded. 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items; 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BrowserList* ash_browser_list = 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (BrowserList::const_iterator it = ash_browser_list->begin(); 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != ash_browser_list->end(); ++it) { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = *it; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int index = 0; index < tab_strip->count(); index++) { 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = tab_strip->GetWebContentsAt(index); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(web_contents); 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::WebContents* AppShortcutLauncherItemController::GetLRUApplication() { 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLPattern refocus_pattern(URLPattern::SCHEME_ALL); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(true); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!refocus_url_.is_empty()) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(false); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.Parse(refocus_url_.spec()); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We may get here while the extension is loading (and NULL). 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BrowserList* ash_browser_list = 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (BrowserList::const_reverse_iterator 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it = ash_browser_list->begin_last_active(); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != ash_browser_list->end_last_active(); ++it) { 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = *it; 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We start to enumerate from the active index. 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int active_index = tab_strip->active_index(); 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int index = 0; index < tab_strip->count(); index++) { 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = tab_strip->GetWebContentsAt( 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (index + active_index) % tab_strip->count()); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 235bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return web_contents; 236bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 237bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 238bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Coming here our application was not in the LRU list. This could have 239bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // happened because it did never get activated yet. So check the browser list 240bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // as well. 241bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch for (BrowserList::const_iterator it = ash_browser_list->begin(); 242bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch it != ash_browser_list->end(); ++it) { 243bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Browser* browser = *it; 244bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch TabStripModel* tab_strip = browser->tab_strip_model(); 245bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch for (int index = 0; index < tab_strip->count(); index++) { 246bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch content::WebContents* web_contents = tab_strip->GetWebContentsAt(index); 247bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return web_contents; 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::WebContentMatchesApp( 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::Extension* extension, 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const URLPattern& refocus_pattern, 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents) { 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL tab_url = web_contents->GetURL(); 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There are three ways to identify the association of a URL with this 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // extension: 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The refocus pattern is matched (needed for apps like drive). 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The extension's origin + extent gets matched. 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The launcher controller knows that the tab got created for this app. 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ((!refocus_pattern.match_all_urls() && 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.MatchesURL(tab_url)) || 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (extension->OverlapsWithOrigin(tab_url) && 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension->web_extent().MatchesURL(tab_url)) || 2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->IsWebContentHandledByApplication(web_contents, 2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) app_id())); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AppShortcutLauncherItemController::ActivateContent( 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* content) { 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content); 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int index = tab_strip->GetIndexOfWebContents(content); 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_NE(TabStripModel::kNoTab, index); 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int old_index = tab_strip->active_index(); 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (index != old_index) 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tab_strip->ActivateTabAt(index, false); 2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->ActivateWindowOrMinimizeIfActive( 2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) browser->window(), 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) index == old_index && GetRunningApplications().size() == 1); 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool AppShortcutLauncherItemController::AdvanceToNextApp() { 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*> items = GetRunningApplications(); 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (items.size() >= 1) { 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWindow( 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ash::wm::GetActiveWindow()); 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (browser) { 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* active = tab_strip->GetWebContentsAt( 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tab_strip->active_index()); 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*>::const_iterator i( 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::find(items.begin(), items.end(), active)); 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (i != items.end()) { 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (items.size() == 1) { 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If there is only a single item available, we animate it upon key 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // action. 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AnimateWindow(browser->window()->GetNativeWindow(), 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE); 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int index = (static_cast<int>(i - items.begin()) + 1) % items.size(); 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ActivateContent(items[index]); 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppShortcutLauncherItemController::IsV2App() { 3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const Extension* extension = 3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return extension && extension->is_platform_app(); 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppShortcutLauncherItemController::AllowNextLaunchAttempt() { 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (last_launch_attempt_.is_null() || 323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_launch_attempt_ + base::TimeDelta::FromMilliseconds( 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kClickSuppressionInMS) < base::Time::Now()) { 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_launch_attempt_ = base::Time::Now(); 326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 330