diff options
author | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-18 21:33:02 +0000 |
---|---|---|
committer | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-18 21:33:02 +0000 |
commit | 2acf3e792cc10adbe2c36626f0c9f46bc803bef4 (patch) | |
tree | 71db281952298436965b9fee0ed687b6b6f64d23 /chrome | |
parent | e2a0ab20ed1d0fa177ce1d50a4fe1a14d9fdf8c6 (diff) | |
download | chromium_src-2acf3e792cc10adbe2c36626f0c9f46bc803bef4.zip chromium_src-2acf3e792cc10adbe2c36626f0c9f46bc803bef4.tar.gz chromium_src-2acf3e792cc10adbe2c36626f0c9f46bc803bef4.tar.bz2 |
Get non platform apps to show running state
BUG=125047
TEST=New LauncherAppBrowserTest.*
Review URL: https://chromiumcodereview.appspot.com/10559024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142819 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/ui/views/ash/app_list/extension_app_item.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc | 44 | ||||
-rw-r--r-- | chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h | 10 | ||||
-rw-r--r-- | chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc | 146 | ||||
-rw-r--r-- | chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h | 46 | ||||
-rw-r--r-- | chrome/browser/ui/views/ash/launcher/chrome_launcher_controller_browsertest.cc (renamed from chrome/browser/ui/views/ash/launcher/launcher_platform_app_browsertest.cc) | 196 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 | ||||
-rw-r--r-- | chrome/test/base/in_process_browser_test.h | 3 |
8 files changed, 420 insertions, 29 deletions
diff --git a/chrome/browser/ui/views/ash/app_list/extension_app_item.cc b/chrome/browser/ui/views/ash/app_list/extension_app_item.cc index 74904e0..c8d8086 100644 --- a/chrome/browser/ui/views/ash/app_list/extension_app_item.cc +++ b/chrome/browser/ui/views/ash/app_list/extension_app_item.cc @@ -264,7 +264,7 @@ void ExtensionAppItem::Activate(int event_flags) { if (!extension) return; - extension_utils::OpenExtension(profile_, extension, event_flags); + ChromeLauncherController::instance()->OpenAppID(extension->id(), event_flags); } ui::MenuModel* ExtensionAppItem::GetContextMenuModel() { diff --git a/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc b/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc index 5204a19..e8e31eb 100644 --- a/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc +++ b/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc @@ -24,6 +24,8 @@ #include "ui/aura/window.h" #include "ui/base/resource/resource_bundle.h" +using extensions::Extension; + BrowserLauncherItemController::BrowserLauncherItemController( aura::Window* window, TabStripModel* tab_model, @@ -107,13 +109,29 @@ void BrowserLauncherItemController::ActiveTabChanged( int index, bool user_gesture) { // Update immediately on a tab change. + if (old_contents) + UpdateAppState(old_contents); + UpdateAppState(new_contents); UpdateLauncher(new_contents); } +void BrowserLauncherItemController::TabInsertedAt(TabContents* contents, + int index, + bool foreground) { + UpdateAppState(contents); +} + +void BrowserLauncherItemController::TabDetachedAt(TabContents* contents, + int index) { + launcher_controller_->UpdateAppState( + contents, ChromeLauncherController::APP_STATE_REMOVED); +} + void BrowserLauncherItemController::TabChangedAt( TabContents* tab, int index, TabStripModelObserver::TabChangeType change_type) { + UpdateAppState(tab); if (index != tab_model_->active_index() || !(change_type != TabStripModelObserver::LOADING_ONLY && change_type != TabStripModelObserver::TITLE_NOT_LOADING)) { @@ -134,6 +152,16 @@ void BrowserLauncherItemController::TabChangedAt( } } +void BrowserLauncherItemController::TabReplacedAt( + TabStripModel* tab_strip_model, + TabContents* old_contents, + TabContents* new_contents, + int index) { + launcher_controller_->UpdateAppState( + old_contents, ChromeLauncherController::APP_STATE_REMOVED); + UpdateAppState(new_contents); +} + void BrowserLauncherItemController::FaviconUpdated() { UpdateLauncher(tab_model_->GetActiveTabContents()); } @@ -204,6 +232,22 @@ void BrowserLauncherItemController::UpdateLauncher(TabContents* tab) { launcher_model()->Set(item_index, item); } +void BrowserLauncherItemController::UpdateAppState(TabContents* tab) { + ChromeLauncherController::AppState app_state; + + if (tab_model_->GetIndexOfTabContents(tab) == TabStripModel::kNoTab) { + app_state = ChromeLauncherController::APP_STATE_REMOVED; + } else if (tab_model_->GetActiveTabContents() == tab) { + if (ash::wm::IsActiveWindow(window_)) + app_state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE; + else + app_state = ChromeLauncherController::APP_STATE_ACTIVE; + } else { + app_state = ChromeLauncherController::APP_STATE_INACTIVE; + } + launcher_controller_->UpdateAppState(tab, app_state); +} + ash::LauncherModel* BrowserLauncherItemController::launcher_model() { return launcher_controller_->model(); } diff --git a/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h b/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h index 3f1ae9b..289721a 100644 --- a/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h +++ b/chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h @@ -90,10 +90,18 @@ class BrowserLauncherItemController : public TabStripModelObserver, TabContents* new_contents, int index, bool user_gesture) OVERRIDE; + virtual void TabInsertedAt(TabContents* contents, + int index, + bool foreground) OVERRIDE; + virtual void TabDetachedAt(TabContents* contents, int index) OVERRIDE; virtual void TabChangedAt( TabContents* tab, int index, TabStripModelObserver::TabChangeType change_type) OVERRIDE; + virtual void TabReplacedAt(TabStripModel* tab_strip_model, + TabContents* old_contents, + TabContents* new_contents, + int index) OVERRIDE; // LauncherFaviconLoader::Delegate overrides: virtual void FaviconUpdated() OVERRIDE; @@ -120,6 +128,8 @@ class BrowserLauncherItemController : public TabStripModelObserver, // Updates the launcher from |tab|. void UpdateLauncher(TabContents* tab); + void UpdateAppState(TabContents* tab); + ash::LauncherModel* launcher_model(); // Browser window we're in. diff --git a/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc index 1f960d3..0840d16 100644 --- a/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc @@ -263,18 +263,40 @@ void ChromeLauncherController::Open(ash::LauncherID id, int event_flags) { if (GetItemStatus(id) == ash::STATUS_IS_PENDING) return; - // Check if this item has any windows in the activation list. - for (WindowList::const_iterator i = activation_order_.begin(); - i != activation_order_.end(); ++i) { - if (window_to_id_map_[*i] == id) { - ash::wm::ActivateWindow(*i); - return; - } + OpenAppID(id_to_item_map_[id].app_id, event_flags); + } +} + +void ChromeLauncherController::OpenAppID( + const std::string& app_id, + int event_flags) { + ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id); + // Check if this item has any windows in the activation list. + for (WindowList::const_iterator i = platform_app_windows_.begin(); + i != platform_app_windows_.end(); ++i) { + if (window_to_id_map_[*i] == launcher_id) { + ash::wm::ActivateWindow(*i); + return; } + } + // Check if there are any open tabs for this app. + AppIDToTabContentsListMap::iterator i = + app_id_to_tab_contents_list_.find(app_id); + + if (i != app_id_to_tab_contents_list_.end()) { + DCHECK(i->second.size()); + TabContents* tab = i->second.front(); + Browser* browser = browser::FindBrowserWithWebContents( + tab->web_contents()); + TabStripModel* tab_strip = browser->tab_strip_model(); + int index = tab_strip->GetIndexOfTabContents(tab); + DCHECK(index != TabStripModel::kNoTab); + tab_strip->ActivateTabAt(index, false); + ash::wm::ActivateWindow(browser->window()->GetNativeWindow()); + } else { const Extension* extension = - profile_->GetExtensionService()->GetInstalledExtension( - id_to_item_map_[id].app_id); + profile_->GetExtensionService()->GetInstalledExtension(app_id); extension_utils::OpenExtension(profile_, extension, event_flags); } } @@ -309,6 +331,16 @@ std::string ChromeLauncherController::GetAppID(TabContents* tab) { return app_icon_loader_->GetAppID(tab); } +ash::LauncherID ChromeLauncherController::GetLauncherIDForAppID( + const std::string& app_id) { + for (IDToItemMap::const_iterator i = id_to_item_map_.begin(); + i != id_to_item_map_.end(); ++i) { + if (i->second.app_id == app_id) + return i->first; + } + return 0; +} + void ChromeLauncherController::SetAppImage(const std::string& id, const SkBitmap* image) { // TODO: need to get this working for shortcuts. @@ -401,6 +433,72 @@ void ChromeLauncherController::SetAutoHideBehavior( profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value); } +void ChromeLauncherController::RemoveTabFromRunningApp( + TabContents* tab, + const std::string& app_id) { + tab_contents_to_app_id_.erase(tab); + AppIDToTabContentsListMap::iterator i_app_id = + app_id_to_tab_contents_list_.find(app_id); + if (i_app_id != app_id_to_tab_contents_list_.end()) { + TabContentsList* tab_list = &i_app_id->second; + tab_list->remove(tab); + if (!tab_list->size()) { + app_id_to_tab_contents_list_.erase(i_app_id); + i_app_id = app_id_to_tab_contents_list_.end(); + ash::LauncherID id = GetLauncherIDForAppID(app_id); + if (id > 0) + SetItemStatus(id, ash::STATUS_CLOSED); + } + } +} + +void ChromeLauncherController::UpdateAppState(TabContents* tab, + AppState app_state) { + std::string app_id = GetAppID(tab); + + // Check the old |app_id| for a tab. If the contents has changed we need to + // remove it from the previous app. + if (tab_contents_to_app_id_.find(tab) != tab_contents_to_app_id_.end()) { + std::string last_app_id = tab_contents_to_app_id_[tab]; + if (last_app_id != app_id) + RemoveTabFromRunningApp(tab, last_app_id); + } + + if (app_id.empty()) + return; + + tab_contents_to_app_id_[tab] = app_id; + + if (app_state == APP_STATE_REMOVED) { + // The tab has gone away. + RemoveTabFromRunningApp(tab, app_id); + } else { + AppIDToTabContentsListMap::iterator i_app_id = + app_id_to_tab_contents_list_.find(app_id); + + if (i_app_id == app_id_to_tab_contents_list_.end()) { + app_id_to_tab_contents_list_[app_id] = TabContentsList(); + i_app_id = app_id_to_tab_contents_list_.find(app_id); + } + TabContentsList* tab_list = &i_app_id->second; + if (app_state == APP_STATE_INACTIVE) { + TabContentsList::const_iterator i_tab = + std::find(tab_list->begin(), tab_list->end(), tab); + if (i_tab != tab_list->end()) + tab_list->push_back(tab); + } else { + tab_list->remove(tab); + tab_list->push_front(tab); + } + ash::LauncherID id = GetLauncherIDForAppID(app_id); + if (id > 0) { + // If the window is active, mark the app as active. + SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ? + ash::STATUS_ACTIVE : ash::STATUS_RUNNING); + } + } +} + void ChromeLauncherController::CreateNewTab() { Browser* last_browser = browser::FindTabbedBrowser( GetProfileForNewWindows(), true); @@ -568,9 +666,9 @@ void ChromeLauncherController::OnShellWindowAdded(ShellWindow* shell_window) { id = CreateAppLauncherItem(NULL, app_id, status); window_to_id_map_[window] = id; if (status == ash::STATUS_ACTIVE) - activation_order_.push_front(window); + platform_app_windows_.push_front(window); else - activation_order_.push_back(window); + platform_app_windows_.push_back(window); } void ChromeLauncherController::OnShellWindowRemoved(ShellWindow* shell_window) { @@ -581,8 +679,8 @@ void ChromeLauncherController::OnWindowActivated(aura::Window* active, aura::Window* old_active) { if (window_to_id_map_.find(active) != window_to_id_map_.end()) { ash::LauncherID active_id = window_to_id_map_[active]; - activation_order_.remove(active); - activation_order_.push_front(active); + platform_app_windows_.remove(active); + platform_app_windows_.push_front(active); if (window_to_id_map_.find(old_active) != window_to_id_map_.end() && window_to_id_map_[old_active] == active_id) { // Old and new windows are for the same item. Don't change the status. @@ -602,7 +700,7 @@ void ChromeLauncherController::OnWindowRemovingFromRootWindow( window_to_id_map_.erase(window); DCHECK(id_to_item_map_.find(id) != id_to_item_map_.end()); - activation_order_.remove(window); + platform_app_windows_.remove(window); ShellWindowRegistry::ShellWindowSet remaining_windows = ShellWindowRegistry::Get(profile_)->GetShellWindowsForApp( id_to_item_map_[id].app_id); @@ -784,6 +882,16 @@ void ChromeLauncherController::UpdateAppLaunchersFromPref() { CreateAppLauncherItem(NULL, *pref_app_id, ash::STATUS_CLOSED); } +TabContents* ChromeLauncherController::GetLastActiveTabContents( + const std::string& app_id) { + AppIDToTabContentsListMap::const_iterator i = + app_id_to_tab_contents_list_.find(app_id); + if (i == app_id_to_tab_contents_list_.end()) + return NULL; + DCHECK(i->second.size() > 0); + return *i->second.begin(); +} + ash::LauncherID ChromeLauncherController::InsertAppLauncherItem( BrowserLauncherItemController* controller, const std::string& app_id, @@ -815,6 +923,16 @@ ash::LauncherID ChromeLauncherController::InsertAppLauncherItem( !app_icon_loader_->IsValidID(app_id)) { item.status = ash::STATUS_IS_PENDING; } else { + TabContents* active_tab = GetLastActiveTabContents(app_id); + if (active_tab) { + Browser* browser = browser::FindBrowserWithWebContents( + active_tab->web_contents()); + DCHECK(browser); + if (browser->window()->IsActive()) + status = ash::STATUS_ACTIVE; + else + status = ash::STATUS_RUNNING; + } item.status = status; } model_->AddAt(index, item); diff --git a/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h index c5648338..6e32049 100644 --- a/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h +++ b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h @@ -59,6 +59,14 @@ class ChromeLauncherController : public ash::LauncherDelegate, STATE_NOT_INCOGNITO, }; + // Used to update the state of non plaform apps, as tab contents change. + enum AppState { + APP_STATE_ACTIVE, + APP_STATE_WINDOW_ACTIVE, + APP_STATE_INACTIVE, + APP_STATE_REMOVED + }; + // Interface used to load app icons. This is in it's own class so that it can // be mocked. class AppIconLoader { @@ -125,6 +133,10 @@ class ChromeLauncherController : public ash::LauncherDelegate, // event which triggered this command. void Open(ash::LauncherID id, int event_flags); + // Opens the application identified by |app_id|. If already running + // reactivates the most recently used window or tab owned by the app. + void OpenAppID(const std::string& app_id, int event_flags); + // Closes the specified item. void Close(ash::LauncherID id); @@ -137,6 +149,8 @@ class ChromeLauncherController : public ash::LauncherDelegate, // Returns the id of the app for the specified tab. std::string GetAppID(TabContents* tab); + ash::LauncherID GetLauncherIDForAppID(const std::string& app_id); + // Sets the image for an app tab. This is intended to be invoked from the // AppIconLoader. void SetAppImage(const std::string& app_id, const SkBitmap* image); @@ -167,12 +181,24 @@ class ChromeLauncherController : public ash::LauncherDelegate, // by policy in case there is a pre-defined set of pinned apps. bool CanPin() const; + // Updates the pinned pref state. The pinned state consists of a list pref. + // Each item of the list is a dictionary. The key |kAppIDPath| gives the + // id of the app. + void PersistPinnedState(); + ash::LauncherModel* model() { return model_; } Profile* profile() { return profile_; } void SetAutoHideBehavior(ash::ShelfAutoHideBehavior behavior); + // The tab no longer represents its previously identified application. + void RemoveTabFromRunningApp(TabContents* tab, const std::string& app_id); + + // Notify the controller that the state of an non platform app's tabs + // have changed, + void UpdateAppState(TabContents* tab, AppState app_state); + // ash::LauncherDelegate overrides: virtual void CreateNewTab() OVERRIDE; virtual void CreateNewWindow() OVERRIDE; @@ -238,11 +264,9 @@ class ChromeLauncherController : public ash::LauncherDelegate, typedef std::map<ash::LauncherID, Item> IDToItemMap; typedef std::map<aura::Window*, ash::LauncherID> WindowToIDMap; typedef std::list<aura::Window*> WindowList; - - // Updates the pinned pref state. The pinned state consists of a list pref. - // Each item of the list is a dictionary. The key |kAppIDPath| gives the - // id of the app. - void PersistPinnedState(); + typedef std::list<TabContents*> TabContentsList; + typedef std::map<std::string, TabContentsList> AppIDToTabContentsListMap; + typedef std::map<TabContents*, std::string> TabContentsToAppIDMap; // Sets the AppIconLoader, taking ownership of |loader|. This is intended for // testing. @@ -266,6 +290,9 @@ class ChromeLauncherController : public ash::LauncherDelegate, // Re-syncs launcher model with prefs::kPinnedLauncherApps. void UpdateAppLaunchersFromPref(); + // Returns the most recently active tab contents for an app. + TabContents* GetLastActiveTabContents(const std::string& app_id); + // Creates an app launcher to insert at |index|. Note that |index| may be // adjusted by the model to meet ordering constraints. ash::LauncherID InsertAppLauncherItem( @@ -284,12 +311,19 @@ class ChromeLauncherController : public ash::LauncherDelegate, IDToItemMap id_to_item_map_; + // Maintains activation order of tab contents for each app. + AppIDToTabContentsListMap app_id_to_tab_contents_list_; + + // Direct access to app_id for a tab contents. + TabContentsToAppIDMap tab_contents_to_app_id_; + // Allows us to get from an aura::Window to the id of a launcher item. // Currently only used for platform app windows. WindowToIDMap window_to_id_map_; + // Maintains the activation order. The first element is most recent. // Currently only used for platform app windows. - WindowList activation_order_; + WindowList platform_app_windows_; // Used to load the image for an app tab. scoped_ptr<AppIconLoader> app_icon_loader_; diff --git a/chrome/browser/ui/views/ash/launcher/launcher_platform_app_browsertest.cc b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller_browsertest.cc index 085e848..ca7268e 100644 --- a/chrome/browser/ui/views/ash/launcher/launcher_platform_app_browsertest.cc +++ b/chrome/browser/ui/views/ash/launcher/chrome_launcher_controller_browsertest.cc @@ -18,25 +18,87 @@ #include "chrome/browser/extensions/platform_app_browsertest_util.h" #include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/tab_contents/render_view_context_menu.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/shell_window.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h" +#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/notification_source.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/context_menu_params.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/models/menu_model.h" using extensions::Extension; +using content::WebContents; typedef PlatformAppBrowserTest LauncherPlatformAppBrowserTest; +class LauncherAppBrowserTest : public ExtensionBrowserTest { + protected: + LauncherAppBrowserTest() + : launcher_(NULL), + model_(NULL) { + } + + virtual ~LauncherAppBrowserTest() {} + + virtual void RunTestOnMainThreadLoop() { + launcher_ = ash::Shell::GetInstance()->launcher(); + model_ = launcher_->model(); + return ExtensionBrowserTest::RunTestOnMainThreadLoop(); + } + + const Extension* LoadAndLaunchExtension( + const char* name, + extension_misc::LaunchContainer container) { + EXPECT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name))); + + ExtensionService* service = browser()->profile()->GetExtensionService(); + const Extension* extension = + service->GetExtensionById(last_loaded_extension_id_, false); + EXPECT_TRUE(extension); + + application_launch::OpenApplication( + browser()->profile(), + extension, + // Overriding manifest to open in a panel. + container, + GURL(), + NEW_FOREGROUND_TAB, + NULL); + return extension; + } + + ash::LauncherID CreateShortcut(const char* name) { + ExtensionService* service = browser()->profile()->GetExtensionService(); + LoadExtension(test_data_dir_.AppendASCII(name)); + + // First get app_id. + const Extension* extension = + service->GetExtensionById(last_loaded_extension_id_, false); + const std::string app_id = extension->id(); + + // Then create a shortcut. + ChromeLauncherController* controller = + static_cast<ChromeLauncherController*>(launcher_->delegate()); + int item_count = model_->item_count(); + ash::LauncherID shortcut_id = + controller->CreateAppLauncherItem(NULL, app_id, ash::STATUS_CLOSED); + controller->PersistPinnedState(); + EXPECT_EQ(++item_count, model_->item_count()); + ash::LauncherItem item = *model_->ItemByID(shortcut_id); + EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type); + return item.id; + } + + ash::Launcher* launcher_; + ash::LauncherModel* model_; +}; + // Test that we can launch a platform app and get a running item. IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchUnpinned) { ash::Launcher* launcher = ash::Shell::GetInstance()->launcher(); @@ -363,3 +425,129 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) { ash::wm::ActivateWindow(browser()->window()->GetNativeWindow()); EXPECT_EQ(ash::STATUS_RUNNING, launcher->model()->ItemByID(item_id1)->status); } + +// Test that we can launch an app with a shortcut. +IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, LaunchPinned) { + TabStripModel* tab_strip = browser()->tab_strip_model(); + int tab_count = tab_strip->count(); + ash::LauncherID shortcut_id = CreateShortcut("app1"); + EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id)); + EXPECT_EQ(++tab_count, tab_strip->count()); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); + TabContents* tab = tab_strip->GetActiveTabContents(); + ui_test_utils::WindowedNotificationObserver close_observer( + chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, + content::Source<TabContents>(tab)); + browser()->tab_strip_model()->CloseSelectedTabs(); + close_observer.Wait(); + EXPECT_EQ(--tab_count, tab_strip->count()); + EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); +} + +// Launch the app first and then create the shortcut. +IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, LaunchUnpinned) { + TabStripModel* tab_strip = browser()->tab_strip_model(); + int tab_count = tab_strip->count(); + LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB); + EXPECT_EQ(++tab_count, tab_strip->count()); + ash::LauncherID shortcut_id = CreateShortcut("app1"); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); + TabContents* tab = tab_strip->GetActiveTabContents(); + ui_test_utils::WindowedNotificationObserver close_observer( + chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, + content::Source<TabContents>(tab)); + browser()->tab_strip_model()->CloseSelectedTabs(); + close_observer.Wait(); + EXPECT_EQ(--tab_count, tab_strip->count()); + EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); +} + +// Launches app multiple times through the api that the applist uses. +IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, OpenAppID) { + TabStripModel* tab_strip = browser()->tab_strip_model(); + int tab_count = tab_strip->count(); + const Extension* extension = + LoadExtension(test_data_dir_.AppendASCII("app1")); + + ChromeLauncherController::instance()->OpenAppID(extension->id(), 0); + EXPECT_EQ(++tab_count, tab_strip->count()); + ChromeLauncherController::instance()->OpenAppID(extension->id(), 0); + EXPECT_EQ(tab_count, tab_strip->count()); +} + +// Launch 2 apps and toggle which is active. +IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, MultipleApps) { + int item_count = model_->item_count(); + TabStripModel* tab_strip = browser()->tab_strip_model(); + int tab_count = tab_strip->count(); + ash::LauncherID shortcut1 = CreateShortcut("app1"); + EXPECT_EQ(++item_count, model_->item_count()); + ash::LauncherID shortcut2 = CreateShortcut("app2"); + EXPECT_EQ(++item_count, model_->item_count()); + + // Launch first app. + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1)); + EXPECT_EQ(++tab_count, tab_strip->count()); + TabContents* tab1 = tab_strip->GetActiveTabContents(); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status); + + // Launch second app. + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut2)); + EXPECT_EQ(++tab_count, tab_strip->count()); + TabContents* tab2 = tab_strip->GetActiveTabContents(); + ASSERT_NE(tab1, tab2); + EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status); + + // Reactivate first app. + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1)); + EXPECT_EQ(tab_count, tab_strip->count()); + EXPECT_EQ(tab_strip->GetActiveTabContents(), tab1); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status); + EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut2)).status); + + // Open second tab for second app. This should activate it. + ui_test_utils::NavigateToURLWithDisposition( + browser(), + GURL("http://www.example.com/path3/foo.html"), + NEW_FOREGROUND_TAB, + 0); + EXPECT_EQ(++tab_count, tab_strip->count()); + TabContents* tab3 = tab_strip->GetActiveTabContents(); + EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status); + + // Reactivate first app. + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1)); + EXPECT_EQ(tab_count, tab_strip->count()); + EXPECT_EQ(tab_strip->GetActiveTabContents(), tab1); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status); + EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut2)).status); + + // And second again. This time the second tab should become active. + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut2)); + EXPECT_EQ(tab_count, tab_strip->count()); + EXPECT_EQ(tab_strip->GetActiveTabContents(), tab3); + EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status); +} + +// Confirm that a page can be navigated from and to while maintaining the +// correct running state. +IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, Navigation) { + ash::LauncherID shortcut_id = CreateShortcut("app1"); + EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); + launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id)); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); + + // Navigate away. + ui_test_utils::NavigateToURL( + browser(), GURL("http://www.example.com/path0/bar.html")); + EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status); + + // Navigate back. + ui_test_utils::NavigateToURL( + browser(), GURL("http://www.example.com/path1/foo.html")); + EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status); +} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2b0531e..3973c26 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2911,8 +2911,8 @@ 'browser/ui/tab_modal_confirm_dialog_browsertest.h', 'browser/ui/views/ash/browser_non_client_frame_view_ash_browsertest.cc', 'browser/ui/views/ash/caps_lock_handler_browsertest.cc', + 'browser/ui/views/ash/launcher/chrome_launcher_controller_browsertest.cc', 'browser/ui/views/ash/launcher/launcher_favicon_loader_browsertest.cc', - 'browser/ui/views/ash/launcher/launcher_platform_app_browsertest.cc', 'browser/ui/views/ash/volume_controller_browsertest_chromeos.cc', 'browser/ui/views/browser_action_test_util_views.cc', 'browser/ui/views/browser_actions_container_browsertest.cc', diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h index c86e8dd..a91bb6f 100644 --- a/chrome/test/base/in_process_browser_test.h +++ b/chrome/test/base/in_process_browser_test.h @@ -111,9 +111,6 @@ class InProcessBrowserTest : public BrowserTestBase { void AddTabAtIndex(int index, const GURL& url, content::PageTransition transition); - // Adds a selected tab at |index| to |url| with the specified |transition|. - void AddTabAt(int index, const GURL& url, content::PageTransition transition); - // Override this to add any custom setup code that needs to be done on the // main thread after the browser is created and just before calling // RunTestOnMainThread(). |