summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authordavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 21:33:02 +0000
committerdavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 21:33:02 +0000
commit2acf3e792cc10adbe2c36626f0c9f46bc803bef4 (patch)
tree71db281952298436965b9fee0ed687b6b6f64d23 /chrome
parente2a0ab20ed1d0fa177ce1d50a4fe1a14d9fdf8c6 (diff)
downloadchromium_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.cc2
-rw-r--r--chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.cc44
-rw-r--r--chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.h10
-rw-r--r--chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.cc146
-rw-r--r--chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h46
-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.gypi2
-rw-r--r--chrome/test/base/in_process_browser_test.h3
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().