From 2e2929bd78578081b5665fcea6d085793df2c233 Mon Sep 17 00:00:00 2001 From: "marja@chromium.org" Date: Tue, 10 Jan 2012 16:10:08 +0000 Subject: Restore all profiles which were active when restoring the last open pages. Upon startup, all profiles which had browsers open at the last exit are restored. This will restore the last open pages if the profile settings so dictate. BUG=99088 TEST=see bug & ProfileManagerTest.LastActiveProfiles(AtShutdown)?, BrowserInitTest.StartupURLsForTwoProfiles Review URL: http://codereview.chromium.org/9087009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117033 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/profiles/profile_manager.cc | 103 ++++++++++++++++++- chrome/browser/profiles/profile_manager.h | 22 ++++- .../browser/profiles/profile_manager_unittest.cc | 110 ++++++++++++++++++++- 3 files changed, 229 insertions(+), 6 deletions(-) (limited to 'chrome/browser/profiles') diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index b1943b6..f621be6 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -181,10 +181,18 @@ Profile* ProfileManager::GetLastUsedProfile() { return profile_manager->GetLastUsedProfile(profile_manager->user_data_dir_); } +// static +std::vector ProfileManager::GetLastActiveProfiles() { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + return profile_manager->GetLastActiveProfiles( + profile_manager->user_data_dir_); +} + ProfileManager::ProfileManager(const FilePath& user_data_dir) : user_data_dir_(user_data_dir), logged_in_(false), - will_import_(false) { + will_import_(false), + shutdown_started_(false) { BrowserList::AddObserver(this); #if defined(OS_CHROMEOS) registrar_.Add( @@ -192,6 +200,18 @@ ProfileManager::ProfileManager(const FilePath& user_data_dir) chrome::NOTIFICATION_LOGIN_USER_CHANGED, content::NotificationService::AllSources()); #endif + registrar_.Add( + this, + chrome::NOTIFICATION_BROWSER_OPENED, + content::NotificationService::AllSources()); + registrar_.Add( + this, + chrome::NOTIFICATION_BROWSER_CLOSED, + content::NotificationService::AllSources()); + registrar_.Add( + this, + content::NOTIFICATION_APP_EXITING, + content::NotificationService::AllSources()); } ProfileManager::~ProfileManager() { @@ -255,6 +275,30 @@ Profile* ProfileManager::GetLastUsedProfile(const FilePath& user_data_dir) { return GetProfile(last_used_profile_dir); } +std::vector ProfileManager::GetLastActiveProfiles( + const FilePath& user_data_dir) { + PrefService* local_state = g_browser_process->local_state(); + DCHECK(local_state); + + std::vector to_return; + if (local_state->HasPrefPath(prefs::kProfilesLastActive)) { + const ListValue* profile_list = + local_state->GetList(prefs::kProfilesLastActive); + if (profile_list) { + ListValue::const_iterator it; + std::string profile; + for (it = profile_list->begin(); it != profile_list->end(); ++it) { + if (!(*it)->GetAsString(&profile) || profile.empty()) { + LOG(WARNING) << "Invalid entry in " << prefs::kProfilesLastActive; + continue; + } + to_return.push_back(GetProfile(user_data_dir.AppendASCII(profile))); + } + } + } + return to_return; +} + Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) { FilePath default_profile_dir(user_data_dir); default_profile_dir = default_profile_dir.Append(GetInitialProfileDir()); @@ -413,8 +457,62 @@ void ProfileManager::Observe( CHECK(chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->IsMounted()); } logged_in_ = true; + return; } #endif + if (shutdown_started_) + return; + + bool update_active_profiles = false; + switch (type) { + case content::NOTIFICATION_APP_EXITING: { + // Ignore any browsers closing from now on. + shutdown_started_ = true; + break; + } + case chrome::NOTIFICATION_BROWSER_OPENED: { + Browser* browser = content::Source(source).ptr(); + DCHECK(browser); + Profile* profile = browser->profile(); + DCHECK(profile); + if (++browser_counts_[profile] == 1) { + active_profiles_.push_back(profile); + update_active_profiles = true; + } + break; + } + case chrome::NOTIFICATION_BROWSER_CLOSED: { + Browser* browser = content::Source(source).ptr(); + DCHECK(browser); + Profile* profile = browser->profile(); + DCHECK(profile); + if (--browser_counts_[profile] == 0) { + active_profiles_.erase( + std::remove(active_profiles_.begin(), active_profiles_.end(), + profile), + active_profiles_.end()); + update_active_profiles = true; + } + break; + } + default: { + NOTREACHED(); + break; + } + } + if (update_active_profiles) { + PrefService* local_state = g_browser_process->local_state(); + DCHECK(local_state); + ListPrefUpdate update(local_state, prefs::kProfilesLastActive); + ListValue* profile_list = update.Get(); + + profile_list->Clear(); + std::vector::const_iterator it; + for (it = active_profiles_.begin(); it != active_profiles_.end(); ++it) { + profile_list->Append( + new StringValue((*it)->GetPath().BaseName().MaybeAsASCII())); + } + } } void ProfileManager::SetWillImport() { @@ -553,6 +651,7 @@ void ProfileManager::CreateMultiProfileAsync() { void ProfileManager::RegisterPrefs(PrefService* prefs) { prefs->RegisterStringPref(prefs::kProfileLastUsed, ""); prefs->RegisterIntegerPref(prefs::kProfilesNumCreated, 1); + prefs->RegisterListPref(prefs::kProfilesLastActive); } size_t ProfileManager::GetNumberOfProfiles() { diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index 229d702..14c1aef 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -86,13 +86,24 @@ class ProfileManager : public base::NonThreadSafe, // relative to the user data directory currently in use.. FilePath GetInitialProfileDir(); - // Get the Profile last used with this Chrome build. If no signed profile has - // been stored in Local State, hand back the Default profile. + // Get the Profile last used (the Profile to which owns the most recently + // focused window) with this Chrome build. If no signed profile has been + // stored in Local State, hand back the Default profile. Profile* GetLastUsedProfile(const FilePath& user_data_dir); // Same as instance method but provides the default user_data_dir as well. static Profile* GetLastUsedProfile(); + // Get the Profiles which are currently active, i.e., have open browsers, or + // were active the last time Chrome was running. The Profiles appear in the + // order they became active. The last used profile will be on the list, but + // its index on the list will depend on when it became active (so, it is not + // necessarily the last one). + std::vector GetLastActiveProfiles(const FilePath& user_data_dir); + + // Same as instance method but provides the default user_data_dir as well. + static std::vector GetLastActiveProfiles(); + // Returns created profiles. Note, profiles order is NOT guaranteed to be // related with the creation order. std::vector GetLoadedProfiles() const; @@ -289,6 +300,11 @@ class ProfileManager : public base::NonThreadSafe, scoped_ptr profile_shortcut_manager_; #endif + // For keeping track of the last active profiles. + std::map browser_counts_; + std::vector active_profiles_; + bool shutdown_started_; + DISALLOW_COPY_AND_ASSIGN(ProfileManager); }; diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc index 7d598c3..6802985 100644 --- a/chrome/browser/profiles/profile_manager_unittest.cc +++ b/chrome/browser/profiles/profile_manager_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -384,3 +384,111 @@ TEST_F(ProfileManagerTest, InitProfileInfoCacheForAProfile) { EXPECT_EQ(avatar_index, cache.GetAvatarIconIndexOfProfileAtIndex(profile_index)); } + +TEST_F(ProfileManagerTest, LastActiveProfiles) { + FilePath dest_path1 = temp_dir_.path(); + dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1")); + + FilePath dest_path2 = temp_dir_.path(); + dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("New Profile 2")); + + ProfileManager* profile_manager = g_browser_process->profile_manager(); + + // Successfully create the profiles. + TestingProfile* profile1 = + static_cast(profile_manager->GetProfile(dest_path1)); + ASSERT_TRUE(profile1); + + TestingProfile* profile2 = + static_cast(profile_manager->GetProfile(dest_path2)); + ASSERT_TRUE(profile2); + + std::vector last_active_profiles = + profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(0U, last_active_profiles.size()); + + // Create a browser for profile1. + scoped_ptr browser1a(new Browser(Browser::TYPE_TABBED, profile1)); + + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(1U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + + // And for profile2. + scoped_ptr browser2(new Browser(Browser::TYPE_TABBED, profile2)); + + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(2U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + EXPECT_EQ(profile2, last_active_profiles[1]); + + // Adding more browsers doesn't change anything. + scoped_ptr browser1b(new Browser(Browser::TYPE_TABBED, profile1)); + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(2U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + EXPECT_EQ(profile2, last_active_profiles[1]); + + // Close the browsers. + browser1a.reset(); + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(2U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + EXPECT_EQ(profile2, last_active_profiles[1]); + + browser1b.reset(); + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(1U, last_active_profiles.size()); + EXPECT_EQ(profile2, last_active_profiles[0]); + + browser2.reset(); + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(0U, last_active_profiles.size()); +} + +TEST_F(ProfileManagerTest, LastActiveProfilesAtShutdown) { + FilePath dest_path1 = temp_dir_.path(); + dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1")); + + FilePath dest_path2 = temp_dir_.path(); + dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("New Profile 2")); + + ProfileManager* profile_manager = g_browser_process->profile_manager(); + + // Successfully create the profiles. + TestingProfile* profile1 = + static_cast(profile_manager->GetProfile(dest_path1)); + ASSERT_TRUE(profile1); + + TestingProfile* profile2 = + static_cast(profile_manager->GetProfile(dest_path2)); + ASSERT_TRUE(profile2); + + // Create a browser for profile1. + scoped_ptr browser1(new Browser(Browser::TYPE_TABBED, profile1)); + + // And for profile2. + scoped_ptr browser2(new Browser(Browser::TYPE_TABBED, profile2)); + + std::vector last_active_profiles = + profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(2U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + EXPECT_EQ(profile2, last_active_profiles[1]); + + // Simulate a shutdown. + content::NotificationService::current()->Notify( + content::NOTIFICATION_APP_EXITING, + content::NotificationService::AllSources(), + content::NotificationService::NoDetails()); + + // Even if the browsers are destructed during shutdown, the profiles stay + // active. + browser1.reset(); + browser2.reset(); + + last_active_profiles = profile_manager->GetLastActiveProfiles(); + ASSERT_EQ(2U, last_active_profiles.size()); + EXPECT_EQ(profile1, last_active_profiles[0]); + EXPECT_EQ(profile2, last_active_profiles[1]); +} -- cgit v1.1