summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 20:30:10 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 20:30:10 +0000
commitfca656cb7bd5737a18c809d8f44edc6a99e6bb9a (patch)
tree477a3061a64a4f845642c7de780864214201e3f0 /chrome/browser
parent381f69ad5478d24e5bbb448727c05379204c87d3 (diff)
downloadchromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.zip
chromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.tar.gz
chromium_src-fca656cb7bd5737a18c809d8f44edc6a99e6bb9a.tar.bz2
Adds code to restore application extensions. I'm also enabling tab
pinning on views again as everything in place, except a couple of bugs. BUG=32845 TEST=none Review URL: http://codereview.chromium.org/598027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38657 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser.cc21
-rw-r--r--chrome/browser/browser.h17
-rw-r--r--chrome/browser/defaults.cc6
-rw-r--r--chrome/browser/defaults.h5
-rw-r--r--chrome/browser/sessions/base_session_service.cc32
-rw-r--r--chrome/browser/sessions/base_session_service.h14
-rw-r--r--chrome/browser/sessions/session_restore.cc69
-rw-r--r--chrome/browser/sessions/session_service.cc60
-rw-r--r--chrome/browser/sessions/session_service.h5
-rw-r--r--chrome/browser/sessions/session_service_test_helper.cc7
-rw-r--r--chrome/browser/sessions/session_service_test_helper.h4
-rw-r--r--chrome/browser/sessions/session_service_unittest.cc30
-rw-r--r--chrome/browser/sessions/session_types.h3
-rw-r--r--chrome/browser/sessions/tab_restore_service.cc42
-rw-r--r--chrome/browser/sessions/tab_restore_service.h3
-rw-r--r--chrome/browser/sessions/tab_restore_service_unittest.cc15
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc5
-rw-r--r--chrome/browser/tab_menu_model.cc13
18 files changed, 322 insertions, 29 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 2e6e0d0..0de4558 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -671,11 +671,13 @@ TabContents* Browser::AddRestoredTab(
const std::vector<TabNavigation>& navigations,
int tab_index,
int selected_navigation,
+ const std::string& app_extension_id,
bool select,
bool pin,
bool from_last_session) {
TabContents* new_tab = new TabContents(profile(), NULL,
MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents());
+ SetAppExtensionById(new_tab, app_extension_id);
new_tab->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
@@ -697,9 +699,11 @@ TabContents* Browser::AddRestoredTab(
void Browser::ReplaceRestoredTab(
const std::vector<TabNavigation>& navigations,
int selected_navigation,
- bool from_last_session) {
+ bool from_last_session,
+ const std::string& app_extension_id) {
TabContents* replacement = new TabContents(profile(), NULL,
MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents());
+ SetAppExtensionById(replacement, app_extension_id);
replacement->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
@@ -3262,3 +3266,18 @@ bool Browser::RunUnloadEventsHelper(TabContents* contents) {
}
return false;
}
+
+void Browser::SetAppExtensionById(TabContents* contents,
+ const std::string& app_extension_id) {
+ if (app_extension_id.empty())
+ return;
+
+ ExtensionsService* extension_service = profile()->GetExtensionsService();
+ if (extension_service && extension_service->is_ready()) {
+ Extension* extension =
+ extension_service->GetExtensionById(app_extension_id, false);
+ if (extension)
+ contents->SetAppExtension(extension);
+ }
+}
+
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index e7123c8..bee4138 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -279,12 +279,15 @@ class Browser : public TabStripModelDelegate,
// Add a tab with its session history restored from the SessionRestore
// system. If select is true, the tab is selected. |tab_index| gives the index
// to insert the tab at. |selected_navigation| is the index of the
- // TabNavigation in |navigations| to select. If |pin| is true and |tab_index|
- // is the last pinned tab, then the newly created tab is pinned. If
- // |from_last_session| is true, |navigations| are from the previous session.
+ // TabNavigation in |navigations| to select. If |app_extension_id| is
+ // non-empty the tab is an app tab and |app_extension_id| is the id of the
+ // extension. If |pin| is true and |tab_index|/ is the last pinned tab, then
+ // the newly created tab is pinned. If |from_last_session| is true,
+ // |navigations| are from the previous session.
TabContents* AddRestoredTab(const std::vector<TabNavigation>& navigations,
int tab_index,
int selected_navigation,
+ const std::string& app_extension_id,
bool select,
bool pin,
bool from_last_session);
@@ -321,7 +324,8 @@ class Browser : public TabStripModelDelegate,
void ReplaceRestoredTab(
const std::vector<TabNavigation>& navigations,
int selected_navigation,
- bool from_last_session);
+ bool from_last_session,
+ const std::string& app_extension_id);
// Returns true if a tab can be restored.
virtual bool CanRestoreTab();
@@ -764,6 +768,11 @@ class Browser : public TabStripModelDelegate,
// done only once per application name / per session.
static void RegisterAppPrefs(const std::wstring& app_name);
+ // If |app_extension_id| is not empty this sets the application extension of
+ // |contents| to the extension whose id is |app_extension_id|.
+ void SetAppExtensionById(TabContents* contents,
+ const std::string& app_extension_id);
+
// Data members /////////////////////////////////////////////////////////////
NotificationRegistrar registrar_;
diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc
index 544041d..16017ab 100644
--- a/chrome/browser/defaults.cc
+++ b/chrome/browser/defaults.cc
@@ -45,6 +45,12 @@ const bool kCanToggleSystemTitleBar = true;
#endif
+#if defined(TOOLKIT_VIEWS)
+const bool kEnablePinnedTabs = true;
+#else
+const bool kEnablePinnedTabs = false;
+#endif
+
#if !defined(OS_CHROMEOS)
const SessionStartupPref::Type kDefaultSessionStartupType =
diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h
index f4ebe02a..c2e2c1d 100644
--- a/chrome/browser/defaults.h
+++ b/chrome/browser/defaults.h
@@ -64,6 +64,11 @@ extern const bool kSizeTabButtonToTopOfTabStrip;
// asking the user for credentials.
extern const bool kBootstrapSyncAuthentication;
+// Are pinned tabs enabled?
+// TODO: if you're the last to make this true on all platforms, remove the
+// field.
+extern const bool kEnablePinnedTabs;
+
} // namespace browser_defaults
#endif // CHROME_BROWSER_DEFAULTS_H_
diff --git a/chrome/browser/sessions/base_session_service.cc b/chrome/browser/sessions/base_session_service.cc
index 64b3949..a8be23d 100644
--- a/chrome/browser/sessions/base_session_service.cc
+++ b/chrome/browser/sessions/base_session_service.cc
@@ -180,6 +180,25 @@ SessionCommand* BaseSessionService::CreateUpdateTabNavigationCommand(
return new SessionCommand(command_id, pickle);
}
+SessionCommand* BaseSessionService::CreateSetTabAppExtensionIDCommand(
+ SessionID::id_type command_id,
+ SessionID::id_type tab_id,
+ const std::string& extension_id) {
+ // Use pickle to handle marshalling.
+ Pickle pickle;
+ pickle.WriteInt(tab_id);
+
+ // Enforce a max for ids. They should never be anywhere near this size.
+ static const SessionCommand::size_type max_id_size =
+ std::numeric_limits<SessionCommand::size_type>::max() - 1024;
+
+ int bytes_written = 0;
+
+ WriteStringToPickle(pickle, &bytes_written, max_id_size, extension_id);
+
+ return new SessionCommand(command_id, pickle);
+}
+
bool BaseSessionService::RestoreUpdateTabNavigationCommand(
const SessionCommand& command,
TabNavigation* navigation,
@@ -214,6 +233,19 @@ bool BaseSessionService::RestoreUpdateTabNavigationCommand(
return true;
}
+bool BaseSessionService::RestoreSetTabAppExtensionIDCommand(
+ const SessionCommand& command,
+ SessionID::id_type* tab_id,
+ std::string* app_extension_id) {
+ scoped_ptr<Pickle> pickle(command.PayloadAsPickle());
+ if (!pickle.get())
+ return false;
+
+ void* iterator = NULL;
+ return pickle->ReadInt(&iterator, tab_id) &&
+ pickle->ReadString(&iterator, app_extension_id);
+}
+
bool BaseSessionService::ShouldTrackEntry(const NavigationEntry& entry) {
return entry.virtual_url().is_valid();
}
diff --git a/chrome/browser/sessions/base_session_service.h b/chrome/browser/sessions/base_session_service.h
index ae4cbce..b311fd8 100644
--- a/chrome/browser/sessions/base_session_service.h
+++ b/chrome/browser/sessions/base_session_service.h
@@ -119,6 +119,12 @@ class BaseSessionService : public CancelableRequestProvider,
int index,
const NavigationEntry& entry);
+ // Creates a SessionCommand that represents marking a tab as an application.
+ SessionCommand* CreateSetTabAppExtensionIDCommand(
+ SessionID::id_type command_id,
+ SessionID::id_type tab_id,
+ const std::string& extension_id);
+
// Converts a SessionCommand previously created by
// CreateUpdateTabNavigationCommand into a TabNavigation. Returns true
// on success. If successful |tab_id| is set to the id of the restored tab.
@@ -126,6 +132,14 @@ class BaseSessionService : public CancelableRequestProvider,
TabNavigation* navigation,
SessionID::id_type* tab_id);
+ // Extracts a SessionCommand as previously created by
+ // CreateSetTabAppExtensionIDCommand into the tab id and application
+ // extension id.
+ bool RestoreSetTabAppExtensionIDCommand(
+ const SessionCommand& command,
+ SessionID::id_type* tab_id,
+ std::string* app_extension_id);
+
// Returns true if the NavigationEntry should be written to disk.
bool ShouldTrackEntry(const NavigationEntry& entry);
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index f450013..58be396 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_types.h"
@@ -180,7 +181,8 @@ class SessionRestoreImpl : public NotificationObserver {
synchronous_(synchronous),
clobber_existing_window_(clobber_existing_window),
always_create_tabbed_browser_(always_create_tabbed_browser),
- urls_to_open_(urls_to_open) {
+ urls_to_open_(urls_to_open),
+ waiting_for_extension_service_(false) {
}
void Restore() {
@@ -210,11 +212,28 @@ class SessionRestoreImpl : public NotificationObserver {
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type != NotificationType::BROWSER_CLOSED) {
- NOTREACHED();
- return;
+ switch (type.value) {
+ case NotificationType::BROWSER_CLOSED:
+ delete this;
+ return;
+
+ case NotificationType::EXTENSIONS_READY: {
+ if (!waiting_for_extension_service_)
+ return;
+
+ waiting_for_extension_service_ = false;
+ if (synchronous_) {
+ MessageLoop::current()->Quit();
+ return;
+ }
+ ProcessSessionWindows(&windows_);
+ return;
+ }
+
+ default:
+ NOTREACHED();
+ break;
}
- delete this;
}
private:
@@ -255,15 +274,50 @@ class SessionRestoreImpl : public NotificationObserver {
void OnGotSession(SessionService::Handle handle,
std::vector<SessionWindow*>* windows) {
+ if (HasAppExtensions(*windows) && profile_->GetExtensionsService() &&
+ !profile_->GetExtensionsService()->is_ready()) {
+ // At least one tab is an app tab and the extension service hasn't
+ // finished loading. Wait to continue processing until the extensions
+ // service finishes loading.
+ registrar_.Add(this, NotificationType::EXTENSIONS_READY,
+ Source<Profile>(profile_));
+ windows_.swap(*windows);
+ waiting_for_extension_service_ = true;
+ return;
+ }
+
if (synchronous_) {
// See comment above windows_ as to why we don't process immediately.
windows_.swap(*windows);
MessageLoop::current()->Quit();
return;
}
+
ProcessSessionWindows(windows);
}
+ // Returns true if any tab in |windows| has an application extension id.
+ bool HasAppExtensions(const std::vector<SessionWindow*>& windows) {
+ for (std::vector<SessionWindow*>::const_iterator i = windows.begin();
+ i != windows.end(); ++i) {
+ if (HasAppExtensions((*i)->tabs))
+ return true;
+ }
+
+ return false;
+ }
+
+ // Returns true if any tab in |tabs| has an application extension id.
+ bool HasAppExtensions(const std::vector<SessionTab*>& tabs) {
+ for (std::vector<SessionTab*>::const_iterator i = tabs.begin();
+ i != tabs.end(); ++i) {
+ if (!(*i)->app_extension_id.empty())
+ return true;
+ }
+
+ return false;
+ }
+
void ProcessSessionWindows(std::vector<SessionWindow*>* windows) {
if (windows->empty()) {
// Restore was unsuccessful.
@@ -340,6 +394,7 @@ class SessionRestoreImpl : public NotificationObserver {
&browser->AddRestoredTab(tab.navigations,
static_cast<int>(i - window.tabs.begin()),
selected_index,
+ tab.app_extension_id,
false,
tab.pinned,
true)->controller());
@@ -415,6 +470,10 @@ class SessionRestoreImpl : public NotificationObserver {
// windows when the nested message loop exits.
std::vector<SessionWindow*> windows_;
+ // If true, indicates at least one tab has an application extension id and
+ // we're waiting for the extension service to finish loading.
+ bool waiting_for_extension_service_;
+
NotificationRegistrar registrar_;
};
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 58dcd1a..73689d4 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/defaults.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/session_startup_pref.h"
#include "chrome/browser/sessions/session_backend.h"
@@ -26,6 +27,7 @@
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
@@ -53,6 +55,7 @@ static const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
static const SessionCommand::id_type
kCommandTabNavigationPathPrunedFromFront = 11;
static const SessionCommand::id_type kCommandSetPinnedState = 12;
+static const SessionCommand::id_type kCommandSetAppExtensionID = 13;
// Every kWritesPerReset commands triggers recreating the file.
static const int kWritesPerReset = 250;
@@ -402,6 +405,9 @@ void SessionService::Init() {
NotificationService::AllSources());
registrar_.Add(this, NotificationType::BROWSER_OPENED,
NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
+ NotificationService::AllSources());
}
void SessionService::Observe(NotificationType type,
@@ -445,6 +451,12 @@ void SessionService::Observe(NotificationType type,
NavigationController* controller =
Source<NavigationController>(source).ptr();
SetTabWindow(controller->window_id(), controller->session_id());
+ if (controller->tab_contents()->app_extension()) {
+ SetTabAppExtensionID(
+ controller->window_id(),
+ controller->session_id(),
+ controller->tab_contents()->app_extension()->id());
+ }
break;
}
@@ -493,11 +505,35 @@ void SessionService::Observe(NotificationType type,
break;
}
+ case NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: {
+ TabContents* tab_contents = Source<TabContents>(source).ptr();
+ DCHECK(tab_contents);
+ if (tab_contents->app_extension()) {
+ SetTabAppExtensionID(tab_contents->controller().window_id(),
+ tab_contents->controller().session_id(),
+ tab_contents->app_extension()->id());
+ }
+ break;
+ }
+
default:
NOTREACHED();
}
}
+void SessionService::SetTabAppExtensionID(
+ const SessionID& window_id,
+ const SessionID& tab_id,
+ const std::string& app_extension_id) {
+ if (!ShouldTrackChangesToWindow(window_id))
+ return;
+
+ ScheduleCommand(CreateSetTabAppExtensionIDCommand(
+ kCommandSetAppExtensionID,
+ tab_id.id(),
+ app_extension_id));
+}
+
SessionCommand* SessionService::CreateSetSelectedTabInWindow(
const SessionID& window_id,
int index) {
@@ -910,9 +946,20 @@ bool SessionService::CreateTabsAndWindows(
PinnedStatePayload payload;
if (!command->GetPayload(&payload, sizeof(payload)))
return true;
-#if defined(ENABLE_PINNED_TABS)
- GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state;
-#endif
+ if (browser_defaults::kEnablePinnedTabs)
+ GetTab(payload.tab_id, tabs)->pinned = payload.pinned_state;
+ break;
+ }
+
+ case kCommandSetAppExtensionID: {
+ SessionID::id_type tab_id;
+ std::string app_extension_id;
+ if (!RestoreSetTabAppExtensionIDCommand(
+ *command, &tab_id, &app_extension_id)) {
+ return true;
+ }
+
+ GetTab(tab_id, tabs)->app_extension_id.swap(app_extension_id);
break;
}
@@ -947,6 +994,13 @@ void SessionService::BuildCommandsForTab(
commands->push_back(
CreatePinnedStateCommand(controller->session_id(), true));
}
+ if (controller->tab_contents()->app_extension()) {
+ commands->push_back(
+ CreateSetTabAppExtensionIDCommand(
+ kCommandSetAppExtensionID,
+ controller->session_id().id(),
+ controller->tab_contents()->app_extension()->id()));
+ }
for (int i = min_index; i < max_index; ++i) {
const NavigationEntry* entry = (i == pending_index) ?
controller->pending_entry() : controller->GetEntryAtIndex(i);
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index 5ec3783..940824e 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -173,6 +173,11 @@ class SessionService : public BaseSessionService,
const NotificationSource& source,
const NotificationDetails& details);
+ // Sets the application extension id of the specified tab.
+ void SetTabAppExtensionID(const SessionID& window_id,
+ const SessionID& tab_id,
+ const std::string& app_extension_id);
+
// Methods to create the various commands. It is up to the caller to delete
// the returned the SessionCommand* object.
SessionCommand* CreateSetSelectedTabInWindow(const SessionID& window_id,
diff --git a/chrome/browser/sessions/session_service_test_helper.cc b/chrome/browser/sessions/session_service_test_helper.cc
index 871c222..7703bc8 100644
--- a/chrome/browser/sessions/session_service_test_helper.cc
+++ b/chrome/browser/sessions/session_service_test_helper.cc
@@ -29,6 +29,13 @@ void SessionServiceTestHelper::PrepareTabInWindow(const SessionID& window_id,
service()->SetSelectedTabInWindow(window_id, visual_index);
}
+void SessionServiceTestHelper::SetTabAppExtensionID(
+ const SessionID& window_id,
+ const SessionID& tab_id,
+ const std::string& app_extension_id) {
+ service()->SetTabAppExtensionID(window_id, tab_id, app_extension_id);
+}
+
// Be sure and null out service to force closing the file.
void SessionServiceTestHelper::ReadWindows(
std::vector<SessionWindow*>* windows) {
diff --git a/chrome/browser/sessions/session_service_test_helper.h b/chrome/browser/sessions/session_service_test_helper.h
index 0f04635..869ca50a 100644
--- a/chrome/browser/sessions/session_service_test_helper.h
+++ b/chrome/browser/sessions/session_service_test_helper.h
@@ -34,6 +34,10 @@ class SessionServiceTestHelper {
int visual_index,
bool select);
+ void SetTabAppExtensionID(const SessionID& window_id,
+ const SessionID& tab_id,
+ const std::string& app_extension_id);
+
// Reads the contents of the last session.
void ReadWindows(std::vector<SessionWindow*>* windows);
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc
index 25fc8ad..8d2a9da 100644
--- a/chrome/browser/sessions/session_service_unittest.cc
+++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -9,6 +9,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "chrome/browser/defaults.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_test_helper.h"
@@ -510,6 +511,9 @@ TEST_F(SessionServiceTest, PruneFromFront) {
ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
ASSERT_EQ(1U, windows[0]->tabs.size());
+ // There shouldn't be an app id.
+ EXPECT_TRUE(windows[0]->tabs[0]->app_extension_id.empty());
+
// We should be left with three navigations, the 2nd selected.
SessionTab* tab = windows[0]->tabs[0];
ASSERT_EQ(1, tab->current_navigation_index);
@@ -553,9 +557,31 @@ TEST_F(SessionServiceTest, PinnedFalseWhenSetToFalse) {
EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
}
-#if defined(ENABLE_PINNED_TABS)
+// Make sure application extension ids are persisted.
+TEST_F(SessionServiceTest, PersistApplicationExtensionID) {
+ SessionID tab_id;
+ ASSERT_NE(window_id.id(), tab_id.id());
+ std::string app_id("foo");
+
+ TabNavigation nav1(0, GURL("http://google.com"), GURL(),
+ ASCIIToUTF16("abc"), std::string(),
+ PageTransition::QUALIFIER_MASK);
+
+ helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
+ UpdateNavigation(window_id, tab_id, nav1, 0, true);
+ helper_.SetTabAppExtensionID(window_id, tab_id, app_id);
+
+ ScopedVector<SessionWindow> windows;
+ ReadWindows(&(windows.get()));
+
+ helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
+ EXPECT_TRUE(app_id == windows[0]->tabs[0]->app_extension_id);
+}
+
// Explicitly set the pinned state to true and make sure we get back true.
TEST_F(SessionServiceTest, PinnedTrue) {
+ if (!browser_defaults::kEnablePinnedTabs)
+ return;
+
EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
}
-#endif
diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h
index 5841810..6bc0142 100644
--- a/chrome/browser/sessions/session_types.h
+++ b/chrome/browser/sessions/session_types.h
@@ -136,6 +136,9 @@ struct SessionTab {
// True if the tab is pinned.
bool pinned;
+ // If non-empty, this tab is an app tab and this is the id of the extension.
+ std::string app_extension_id;
+
std::vector<TabNavigation> navigations;
private:
diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/tab_restore_service.cc
index aeaceab..68ccc10 100644
--- a/chrome/browser/sessions/tab_restore_service.cc
+++ b/chrome/browser/sessions/tab_restore_service.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/extensions/extension.h"
using base::Time;
@@ -47,8 +48,9 @@ const size_t TabRestoreService::kMaxEntries = 10;
// . When the user closes a tab a command of type
// kCommandSelectedNavigationInTab is written identifying the tab and
// the selected index, then a kCommandPinnedState command if the tab was
-// pinned. This is followed by any number of kCommandUpdateTabNavigation
-// commands (1 per navigation entry).
+// pinned and kCommandSetAppExtensionID if the tab has an app id. This is
+// followed by any number of kCommandUpdateTabNavigation commands (1 per
+// navigation entry).
// . When the user closes a window a kCommandSelectedNavigationInTab command
// is written out and followed by n tab closed sequences (as previoulsy
// described).
@@ -59,6 +61,7 @@ static const SessionCommand::id_type kCommandRestoredEntry = 2;
static const SessionCommand::id_type kCommandWindow = 3;
static const SessionCommand::id_type kCommandSelectedNavigationInTab = 4;
static const SessionCommand::id_type kCommandPinnedState = 5;
+static const SessionCommand::id_type kCommandSetAppExtensionID = 6;
// Number of entries (not commands) before we clobber the file and write
// everything.
@@ -269,7 +272,8 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
if (replace_existing_tab && browser) {
browser->ReplaceRestoredTab(tab->navigations,
tab->current_navigation_index,
- tab->from_last_session);
+ tab->from_last_session,
+ tab->app_extension_id);
} else {
// Use the tab's former browser and index, if available.
Browser* tab_browser = NULL;
@@ -291,8 +295,9 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
if (tab_index < 0 || tab_index > tab_browser->tab_count())
tab_index = tab_browser->tab_count();
tab_browser->AddRestoredTab(tab->navigations, tab_index,
- tab->current_navigation_index, true,
- tab->pinned, tab->from_last_session);
+ tab->current_navigation_index,
+ tab->app_extension_id, true, tab->pinned,
+ tab->from_last_session);
}
} else if (entry->type == WINDOW) {
Browser* current_browser = browser;
@@ -303,6 +308,7 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
TabContents* restored_tab =
browser->AddRestoredTab(tab.navigations, browser->tab_count(),
tab.current_navigation_index,
+ tab.app_extension_id,
(static_cast<int>(tab_i) ==
window->selected_tab_index),
tab.pinned, tab.from_last_session);
@@ -407,6 +413,10 @@ void TabRestoreService::PopulateTab(Tab* tab,
if (tab->current_navigation_index == -1 && entry_count > 0)
tab->current_navigation_index = 0;
+ Extension* extension = controller->tab_contents()->app_extension();
+ if (extension)
+ tab->app_extension_id = extension->id();
+
// Browser may be NULL during unit tests.
if (browser) {
tab->browser_id = browser->session_id().id();
@@ -509,6 +519,12 @@ void TabRestoreService::ScheduleCommandsForTab(const Tab& tab,
ScheduleCommand(command);
}
+ if (!tab.app_extension_id.empty()) {
+ ScheduleCommand(
+ CreateSetTabAppExtensionIDCommand(kCommandSetAppExtensionID, tab.id,
+ tab.app_extension_id));
+ }
+
// Then write the navigations.
for (int i = first_index_to_persist, wrote_count = 0;
i < max_index && wrote_count < 2 * max_persist_navigation_count; ++i) {
@@ -740,6 +756,21 @@ void TabRestoreService::CreateEntriesFromCommands(
break;
}
+ case kCommandSetAppExtensionID: {
+ if (!current_tab) {
+ // Should be in a tab when we get this.
+ return;
+ }
+ SessionID::id_type tab_id;
+ std::string app_extension_id;
+ if (!RestoreSetTabAppExtensionIDCommand(command, &tab_id,
+ &app_extension_id)) {
+ return;
+ }
+ current_tab->app_extension_id.swap(app_extension_id);
+ break;
+ }
+
default:
// Unknown type, usually indicates corruption of file. Ignore it.
return;
@@ -852,6 +883,7 @@ bool TabRestoreService::ConvertSessionWindowToWindow(
tab.navigations.swap(session_window->tabs[i]->navigations);
tab.current_navigation_index =
session_window->tabs[i]->current_navigation_index;
+ tab.app_extension_id = session_window->tabs[i]->app_extension_id;
tab.timestamp = Time();
}
}
diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h
index ce488be..f8488e1 100644
--- a/chrome/browser/sessions/tab_restore_service.h
+++ b/chrome/browser/sessions/tab_restore_service.h
@@ -99,6 +99,9 @@ class TabRestoreService : public BaseSessionService {
// True if the tab was pinned.
bool pinned;
+
+ // If non-empty gives the id of the extension for the tab.
+ std::string app_extension_id;
};
// Represents a previously open window.
diff --git a/chrome/browser/sessions/tab_restore_service_unittest.cc b/chrome/browser/sessions/tab_restore_service_unittest.cc
index 19f1056..1cc3bf1 100644
--- a/chrome/browser/sessions/tab_restore_service_unittest.cc
+++ b/chrome/browser/sessions/tab_restore_service_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/defaults.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/session_service.h"
@@ -126,6 +127,7 @@ TEST_F(TabRestoreServiceTest, Basic) {
ASSERT_EQ(TabRestoreService::TAB, entry->type);
TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
EXPECT_FALSE(tab->pinned);
+ EXPECT_TRUE(tab->app_extension_id.empty());
ASSERT_EQ(3U, tab->navigations.size());
EXPECT_TRUE(url1_ == tab->navigations[0].url());
EXPECT_TRUE(url2_ == tab->navigations[1].url());
@@ -191,7 +193,10 @@ TEST_F(TabRestoreServiceTest, Restore) {
}
// Tests restoring a single pinned tab.
-TEST_F(TabRestoreServiceTest, RestorePinned) {
+TEST_F(TabRestoreServiceTest, RestorePinnedAndApp) {
+ if (!browser_defaults::kEnablePinnedTabs)
+ return;
+
AddThreeNavigations();
// Have the service record the tab.
@@ -206,6 +211,8 @@ TEST_F(TabRestoreServiceTest, RestorePinned) {
ASSERT_EQ(TabRestoreService::TAB, entry->type);
TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
tab->pinned = true;
+ const std::string app_extension_id("test");
+ tab->app_extension_id = app_extension_id;
// Recreate the service and have it load the tabs.
RecreateService();
@@ -223,6 +230,7 @@ TEST_F(TabRestoreServiceTest, RestorePinned) {
EXPECT_TRUE(url2_ == tab->navigations[1].url());
EXPECT_TRUE(url3_ == tab->navigations[2].url());
EXPECT_EQ(2, tab->current_navigation_index);
+ EXPECT_TRUE(app_extension_id == tab->app_extension_id);
}
// Make sure we persist entries to disk that have post data.
@@ -363,9 +371,11 @@ TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabs) {
EXPECT_TRUE(url3_ == tab->navigations[2].url());
}
-#if defined(ENABLE_PINNED_TABS)
// Make sure pinned state is correctly loaded from session service.
TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
+ if (!browser_defaults::kEnablePinnedTabs)
+ return;
+
CreateSessionServiceWithOneWindow(true);
profile()->GetSessionService()->MoveCurrentSessionToLastSession();
@@ -402,7 +412,6 @@ TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
EXPECT_TRUE(url2_ == tab->navigations[1].url());
EXPECT_TRUE(url3_ == tab->navigations[2].url());
}
-#endif
// Creates TabRestoreService::kMaxEntries + 1 windows in the session service
// and makes sure we only get back TabRestoreService::kMaxEntries on restore.
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 58eb083..704428d 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -462,6 +462,11 @@ RenderProcessHost* TabContents::GetRenderProcessHost() const {
void TabContents::SetAppExtension(Extension* extension) {
DCHECK(!extension || extension->IsApp());
app_extension_ = extension;
+
+ NotificationService::current()->Notify(
+ NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
+ Source<TabContents>(this),
+ NotificationService::NoDetails());
}
const GURL& TabContents::GetURL() const {
diff --git a/chrome/browser/tab_menu_model.cc b/chrome/browser/tab_menu_model.cc
index 986d352..f0fe251 100644
--- a/chrome/browser/tab_menu_model.cc
+++ b/chrome/browser/tab_menu_model.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/tab_menu_model.h"
+#include "chrome/browser/defaults.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "grit/generated_resources.h"
@@ -18,17 +19,17 @@ void TabMenuModel::Build() {
AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD);
AddItemWithStringId(TabStripModel::CommandDuplicate,
IDS_TAB_CXMENU_DUPLICATE);
-#if defined(ENABLE_PINNED_TABS)
+ if (browser_defaults::kEnablePinnedTabs) {
// On Mac the HIG prefers "pin/unpin" to a checkmark. The Mac code will fix up
// the actual string based on the tab's state via the delegate.
#if defined(OS_MACOSX)
- AddItemWithStringId(TabStripModel::CommandTogglePinned,
- IDS_TAB_CXMENU_PIN_TAB);
+ AddItemWithStringId(TabStripModel::CommandTogglePinned,
+ IDS_TAB_CXMENU_PIN_TAB);
#else
- AddCheckItemWithStringId(TabStripModel::CommandTogglePinned,
- IDS_TAB_CXMENU_PIN_TAB);
-#endif
+ AddCheckItemWithStringId(TabStripModel::CommandTogglePinned,
+ IDS_TAB_CXMENU_PIN_TAB);
#endif
+ }
AddSeparator();
AddItemWithStringId(TabStripModel::CommandCloseTab,
IDS_TAB_CXMENU_CLOSETAB);