app_shortcut_launcher_item_controller.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "apps/ui/native_app_window.h" 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/launcher/launcher_model.h" 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shell.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/wm/window_util.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_process_manager.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/favicon/favicon_tab_helper.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h" 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/window.h" 29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/corewm/window_animations.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_CHROMEOS) 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h" 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The time delta between clicks in which clicks to launch V2 apps are ignored. 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kClickSuppressionInMS = 1000; 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Item controller for an app shortcut. Shortcuts track app and launcher ids, 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// but do not have any associated windows (opening a shortcut will replace the 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// item with the appropriate LauncherItemController type). 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::AppShortcutLauncherItemController( 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& app_id, 503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ChromeLauncherController* controller) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : LauncherItemController(TYPE_SHORTCUT, app_id, controller), 523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_(controller) { 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // To detect V1 applications we use their domain and match them against the 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // used URL. This will also work with applications like Google Drive. 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id); 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Some unit tests have no real extension. 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (extension) { 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) set_refocus_url(GURL( 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) extensions::AppLaunchInfo::GetLaunchWebURL(extension).spec() + "*")); 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::~AppShortcutLauncherItemController() { 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool AppShortcutLauncherItemController::IsCurrentlyShownInWindow( 683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) aura::Window* window) const { 693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Browser* browser = chrome::FindBrowserWithWindow(window); 703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) content::WebContents* active_content_of_window = 713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL; 723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id()); 753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) std::vector<content::WebContents*>::const_iterator iter = 773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) std::find(content.begin(), content.end(), active_content_of_window); 783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return iter != content.end() ? true : false; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::IsOpen() const { 833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return !chrome_launcher_controller_-> 843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) GetV1ApplicationsFromAppId(app_id()).empty(); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::IsVisible() const { 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Return true if any browser window associated with the app is visible. 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id()); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content.size(); i++) { 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content[i]); 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (browser && browser->window()->GetNativeWindow()->IsVisible()) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void AppShortcutLauncherItemController::Launch(ash::LaunchSource source, 10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int event_flags) { 10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) launcher_controller()->LaunchApp(app_id(), source, event_flags); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void AppShortcutLauncherItemController::Activate(ash::LaunchSource source) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* content = GetLRUApplication(); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!content) { 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (IsV2App()) { 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Ideally we come here only once. After that ShellLauncherItemController 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // will take over when the shell window gets opened. However there are 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // apps which take a lot of time for pre-processing (like the files app) 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // before they open a window. Since there is currently no other way to 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // detect if an app was started we suppress any further clicks within a 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // special time out. 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!AllowNextLaunchAttempt()) 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Launch(source, ui::EF_NONE); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ActivateContent(content); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppShortcutLauncherItemController::Close() { 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Close all running 'programs' of this type. 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> content = 1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->GetV1ApplicationsFromAppId(app_id()); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content.size(); i++) { 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content[i]); 1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!browser || !launcher_controller()->IsBrowserFromActiveUser(browser)) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int index = tab_strip->GetIndexOfWebContents(content[i]); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(index != TabStripModel::kNoTab); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_NONE); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeLauncherAppMenuItems 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)AppShortcutLauncherItemController::GetApplicationList(int event_flags) { 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChromeLauncherAppMenuItems items; 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add the application name to the menu. 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false)); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*> content_list = GetRunningApplications(); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < content_list.size(); i++) { 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = content_list[i]; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the icon. 1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents); 1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) string16 title = launcher_controller()->GetAppListTitle(web_contents); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(new ChromeLauncherAppMenuItemTab( 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title, &app_icon, web_contents, i == 0)); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items.Pass(); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::vector<content::WebContents*> 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AppShortcutLauncherItemController::GetRunningApplications() { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<content::WebContents*> items; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLPattern refocus_pattern(URLPattern::SCHEME_ALL); 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(true); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!refocus_url_.is_empty()) { 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(false); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.Parse(refocus_url_.spec()); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It is possible to come here While an extension gets loaded. 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items; 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BrowserList* ash_browser_list = 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (BrowserList::const_iterator it = ash_browser_list->begin(); 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != ash_browser_list->end(); ++it) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = *it; 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!launcher_controller()->IsBrowserFromActiveUser(browser)) 1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue; 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int index = 0; index < tab_strip->count(); index++) { 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = tab_strip->GetWebContentsAt(index); 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) items.push_back(web_contents); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return items; 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AppShortcutLauncherItemController::ItemSelected(const ui::Event& event) { 1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_CHROMEOS) 1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!app_id().empty()) 1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chromeos::default_pinned_apps_field_trial::RecordShelfAppClick(app_id()); 1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // In case of a keyboard event, we were called by a hotkey. In that case we 1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // activate the next item in line if an item of our list is already active. 2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (event.type() == ui::ET_KEY_RELEASED) { 2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (AdvanceToNextApp()) 2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Activate(ash::LAUNCH_FROM_UNKNOWN); 2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)base::string16 AppShortcutLauncherItemController::GetTitle() { 2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return GetAppTitle(); 2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ui::MenuModel* AppShortcutLauncherItemController::CreateContextMenu( 2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) aura::Window* root_window) { 2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ash::LauncherItem item = 2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *(launcher_controller()->model()->ItemByID(launcher_id())); 2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return new LauncherContextMenu(launcher_controller(), &item, root_window); 2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ash::LauncherMenuModel* 2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)AppShortcutLauncherItemController::CreateApplicationMenu(int event_flags) { 2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); 2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool AppShortcutLauncherItemController::IsDraggable() { 2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool AppShortcutLauncherItemController::ShouldShowTooltip() { 2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::WebContents* AppShortcutLauncherItemController::GetLRUApplication() { 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLPattern refocus_pattern(URLPattern::SCHEME_ALL); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(true); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!refocus_url_.is_empty()) { 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.SetMatchAllURLs(false); 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.Parse(refocus_url_.spec()); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We may get here while the extension is loading (and NULL). 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BrowserList* ash_browser_list = 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (BrowserList::const_reverse_iterator 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it = ash_browser_list->begin_last_active(); 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != ash_browser_list->end_last_active(); ++it) { 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = *it; 2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!launcher_controller()->IsBrowserFromActiveUser(browser)) 2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue; 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We start to enumerate from the active index. 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int active_index = tab_strip->active_index(); 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int index = 0; index < tab_strip->count(); index++) { 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = tab_strip->GetWebContentsAt( 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (index + active_index) % tab_strip->count()); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 262bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return web_contents; 263bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 264bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 265bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Coming here our application was not in the LRU list. This could have 266bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // happened because it did never get activated yet. So check the browser list 267bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // as well. 268bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch for (BrowserList::const_iterator it = ash_browser_list->begin(); 269bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch it != ash_browser_list->end(); ++it) { 270bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Browser* browser = *it; 2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!launcher_controller()->IsBrowserFromActiveUser(browser)) 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue; 273bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch TabStripModel* tab_strip = browser->tab_strip_model(); 274bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch for (int index = 0; index < tab_strip->count(); index++) { 275bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch content::WebContents* web_contents = tab_strip->GetWebContentsAt(index); 276bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (WebContentMatchesApp(extension, refocus_pattern, web_contents)) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return web_contents; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AppShortcutLauncherItemController::WebContentMatchesApp( 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::Extension* extension, 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const URLPattern& refocus_pattern, 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents) { 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL tab_url = web_contents->GetURL(); 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There are three ways to identify the association of a URL with this 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // extension: 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The refocus pattern is matched (needed for apps like drive). 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The extension's origin + extent gets matched. 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - The launcher controller knows that the tab got created for this app. 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ((!refocus_pattern.match_all_urls() && 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) refocus_pattern.MatchesURL(tab_url)) || 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (extension->OverlapsWithOrigin(tab_url) && 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension->web_extent().MatchesURL(tab_url)) || 2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->IsWebContentHandledByApplication(web_contents, 2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) app_id())); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AppShortcutLauncherItemController::ActivateContent( 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* content) { 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWebContents(content); 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int index = tab_strip->GetIndexOfWebContents(content); 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_NE(TabStripModel::kNoTab, index); 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int old_index = tab_strip->active_index(); 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (index != old_index) 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tab_strip->ActivateTabAt(index, false); 3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->ActivateWindowOrMinimizeIfActive( 3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) browser->window(), 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) index == old_index && GetRunningApplications().size() == 1); 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool AppShortcutLauncherItemController::AdvanceToNextApp() { 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*> items = GetRunningApplications(); 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (items.size() >= 1) { 319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Browser* browser = chrome::FindBrowserWithWindow( 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ash::wm::GetActiveWindow()); 321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (browser) { 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TabStripModel* tab_strip = browser->tab_strip_model(); 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* active = tab_strip->GetWebContentsAt( 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tab_strip->active_index()); 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<content::WebContents*>::const_iterator i( 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::find(items.begin(), items.end(), active)); 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (i != items.end()) { 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (items.size() == 1) { 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If there is only a single item available, we animate it upon key 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // action. 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AnimateWindow(browser->window()->GetNativeWindow(), 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE); 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int index = (static_cast<int>(i - items.begin()) + 1) % items.size(); 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ActivateContent(items[index]); 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppShortcutLauncherItemController::IsV2App() { 3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const Extension* extension = 3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) launcher_controller()->GetExtensionForAppID(app_id()); 347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return extension && extension->is_platform_app(); 348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool AppShortcutLauncherItemController::AllowNextLaunchAttempt() { 351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (last_launch_attempt_.is_null() || 352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_launch_attempt_ + base::TimeDelta::FromMilliseconds( 353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kClickSuppressionInMS) < base::Time::Now()) { 354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_launch_attempt_ = base::Time::Now(); 355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 359