| Index: chrome/browser/chromeos/login/user_manager_impl.cc
|
| diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
|
| index 14882c0688b8835c871a5ca38420c6e5a69598a6..c5359766ea762e7d8573fc786f4bb17d5b9c4573 100644
|
| --- a/chrome/browser/chromeos/login/user_manager_impl.cc
|
| +++ b/chrome/browser/chromeos/login/user_manager_impl.cc
|
| @@ -4,6 +4,10 @@
|
|
|
| #include "chrome/browser/chromeos/login/user_manager_impl.h"
|
|
|
| +#include <cstddef>
|
| +#include <set>
|
| +#include <vector>
|
| +
|
| #include "ash/shell.h"
|
| #include "base/bind.h"
|
| #include "base/chromeos/chromeos_version.h"
|
| @@ -23,7 +27,6 @@
|
| #include "chrome/browser/chromeos/login/remove_user_delegate.h"
|
| #include "chrome/browser/chromeos/login/user_image_manager_impl.h"
|
| #include "chrome/browser/chromeos/login/wizard_controller.h"
|
| -#include "chrome/browser/chromeos/settings/cros_settings.h"
|
| #include "chrome/browser/policy/browser_policy_connector.h"
|
| #include "chrome/browser/prefs/pref_service.h"
|
| #include "chrome/browser/prefs/scoped_user_pref_update.h"
|
| @@ -44,8 +47,18 @@ namespace chromeos {
|
|
|
| namespace {
|
|
|
| -// A vector pref of the users who have logged into the device.
|
| -const char kLoggedInUsers[] = "LoggedInUsers";
|
| +// A vector pref of the the regular users known on this device, arranged in LRU
|
| +// order.
|
| +const char kRegularUsers[] = "LoggedInUsers";
|
| +
|
| +// A vector pref of the public accounts defined on this device.
|
| +const char kPublicAccounts[] = "PublicAccounts";
|
| +
|
| +// A string pref that gets set when a public account is removed but a user is
|
| +// currently logged into that account, requiring the account's data to be
|
| +// removed after logout.
|
| +const char kPublicAccountPendingDataRemoval[] =
|
| + "PublicAccountPendingDataRemoval";
|
|
|
| // A dictionary that maps usernames to the displayed name.
|
| const char kUserDisplayName[] = "UserDisplayName";
|
| @@ -97,11 +110,47 @@ void RemoveUserInternal(const std::string& user_email,
|
| delegate->OnUserRemoved(user_email);
|
| }
|
|
|
| +// Helper function that copies users from |users_list| to |users_vector| and
|
| +// |users_set|. Duplicates and users already present in |existing_users| are
|
| +// skipped. The |logged_in_user| is also skipped and the return value
|
| +// indicates whether that user was found in |users_list|.
|
| +bool ParseUserList(const ListValue& users_list,
|
| + const std::set<std::string>& existing_users,
|
| + const std::string& logged_in_user,
|
| + std::vector<std::string>* users_vector,
|
| + std::set<std::string>* users_set) {
|
| + users_vector->clear();
|
| + users_set->clear();
|
| + bool logged_in_user_on_list = false;
|
| + for (size_t i = 0; i < users_list.GetSize(); ++i) {
|
| + std::string email;
|
| + if (!users_list.GetString(i, &email) || email.empty()) {
|
| + LOG(ERROR) << "Corrupt entry in user list at index " << i << ".";
|
| + continue;
|
| + }
|
| + if (existing_users.find(email) != existing_users.end() ||
|
| + !users_set->insert(email).second) {
|
| + LOG(ERROR) << "Duplicate user: " << email;
|
| + continue;
|
| + }
|
| + if (email == logged_in_user) {
|
| + logged_in_user_on_list = true;
|
| + continue;
|
| + }
|
| + users_vector->push_back(email);
|
| + }
|
| + users_set->erase(logged_in_user);
|
| + return logged_in_user_on_list;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // static
|
| void UserManager::RegisterPrefs(PrefService* local_state) {
|
| - local_state->RegisterListPref(kLoggedInUsers, PrefService::UNSYNCABLE_PREF);
|
| + local_state->RegisterListPref(kRegularUsers, PrefService::UNSYNCABLE_PREF);
|
| + local_state->RegisterListPref(kPublicAccounts, PrefService::UNSYNCABLE_PREF);
|
| + local_state->RegisterStringPref(kPublicAccountPendingDataRemoval, "",
|
| + PrefService::UNSYNCABLE_PREF);
|
| local_state->RegisterDictionaryPref(kUserOAuthTokenStatus,
|
| PrefService::UNSYNCABLE_PREF);
|
| local_state->RegisterDictionaryPref(kUserDisplayName,
|
| @@ -111,7 +160,9 @@ void UserManager::RegisterPrefs(PrefService* local_state) {
|
| }
|
|
|
| UserManagerImpl::UserManagerImpl()
|
| - : logged_in_user_(NULL),
|
| + : cros_settings_(CrosSettings::Get()),
|
| + users_loaded_(false),
|
| + logged_in_user_(NULL),
|
| session_started_(false),
|
| is_current_user_owner_(false),
|
| is_current_user_new_(false),
|
| @@ -137,6 +188,12 @@ UserManagerImpl::~UserManagerImpl() {
|
| delete logged_in_user_;
|
| }
|
|
|
| +void UserManagerImpl::Shutdown() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + cros_settings_->RemoveSettingsObserver(kAccountsPrefDeviceLocalAccounts,
|
| + this);
|
| +}
|
| +
|
| UserImageManager* UserManagerImpl::GetUserImageManager() {
|
| return user_image_manager_.get();
|
| }
|
| @@ -168,35 +225,19 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
|
|
|
| EnsureUsersLoaded();
|
|
|
| - // Clear the prefs view of the users.
|
| - PrefService* prefs = g_browser_process->local_state();
|
| - ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
|
| - prefs_users_update->Clear();
|
| + // Remove the user from the user list.
|
| + logged_in_user_ = RemoveRegularUserFromList(email);
|
|
|
| - // Make sure this user is first.
|
| - prefs_users_update->Append(new base::StringValue(email));
|
| - UserList::iterator logged_in_user = users_.end();
|
| - for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
|
| - std::string user_email = (*it)->email();
|
| - // Skip the most recent user.
|
| - if (email != user_email)
|
| - prefs_users_update->Append(new base::StringValue(user_email));
|
| - else
|
| - logged_in_user = it;
|
| - }
|
| + // Add the user to the front of the persistent user list.
|
| + ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
|
| + kRegularUsers);
|
| + prefs_users_update->Insert(0, new base::StringValue(email));
|
|
|
| - if (logged_in_user == users_.end()) {
|
| + // If the user was not found on the user list, create a new user.
|
| + if (!logged_in_user_) {
|
| is_current_user_new_ = true;
|
| logged_in_user_ = User::CreateRegularUser(email);
|
| logged_in_user_->set_oauth_token_status(LoadUserOAuthStatus(email));
|
| - } else {
|
| - logged_in_user_ = *logged_in_user;
|
| - users_.erase(logged_in_user);
|
| - }
|
| - // This user must be in the front of the user list.
|
| - users_.insert(users_.begin(), logged_in_user_);
|
| -
|
| - if (is_current_user_new_) {
|
| SaveUserDisplayName(logged_in_user_->email(),
|
| UTF8ToUTF16(logged_in_user_->GetAccountName(true)));
|
| WallpaperManager::Get()->SetInitialUserWallpaper(email, true);
|
| @@ -209,8 +250,8 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
|
| WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
|
| }
|
|
|
| - // Make sure we persist new user data to Local State.
|
| - prefs->CommitPendingWrite();
|
| + // Make sure that new data is persisted to Local State.
|
| + g_browser_process->local_state()->CommitPendingWrite();
|
|
|
| NotifyOnLogin();
|
| }
|
| @@ -253,7 +294,7 @@ void UserManagerImpl::SessionStarted() {
|
| content::NotificationService::AllSources(),
|
| content::NotificationService::NoDetails());
|
| if (is_current_user_new_) {
|
| - // Make sure we persist new user data to Local State.
|
| + // Make sure that the new user's data is persisted to Local State.
|
| g_browser_process->local_state()->CommitPendingWrite();
|
| }
|
| }
|
| @@ -262,7 +303,8 @@ void UserManagerImpl::RemoveUser(const std::string& email,
|
| RemoveUserDelegate* delegate) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| - if (!IsKnownUser(email))
|
| + const User* user = FindUser(email);
|
| + if (!user || user->GetType() != User::USER_TYPE_REGULAR)
|
| return;
|
|
|
| // Sanity check: we must not remove single user. This check may seem
|
| @@ -283,7 +325,10 @@ void UserManagerImpl::RemoveUser(const std::string& email,
|
| void UserManagerImpl::RemoveUserFromList(const std::string& email) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| EnsureUsersLoaded();
|
| - RemoveUserFromListInternal(email);
|
| + RemoveNonCryptohomeData(email);
|
| + delete RemoveRegularUserFromList(email);
|
| + // Make sure that new data is persisted to Local State.
|
| + g_browser_process->local_state()->CommitPendingWrite();
|
| }
|
|
|
| bool UserManagerImpl::IsKnownUser(const std::string& email) const {
|
| @@ -429,13 +474,18 @@ void UserManagerImpl::Observe(int type,
|
| }
|
| }
|
| break;
|
| + case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED:
|
| + DCHECK_EQ(*content::Details<const std::string>(details).ptr(),
|
| + kAccountsPrefDeviceLocalAccounts);
|
| + RetrieveTrustedDevicePolicies();
|
| + break;
|
| default:
|
| NOTREACHED();
|
| }
|
| }
|
|
|
| void UserManagerImpl::OnStateChanged() {
|
| - DCHECK(IsUserLoggedIn() && !IsLoggedInAsGuest());
|
| + DCHECK(IsLoggedInAsRegularUser());
|
| GoogleServiceAuthError::State state =
|
| observed_sync_service_->GetAuthError().state();
|
| if (state != GoogleServiceAuthError::NONE &&
|
| @@ -484,6 +534,12 @@ bool UserManagerImpl::IsUserLoggedIn() const {
|
| return logged_in_user_;
|
| }
|
|
|
| +bool UserManagerImpl::IsLoggedInAsRegularUser() const {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + return IsUserLoggedIn() &&
|
| + logged_in_user_->GetType() == User::USER_TYPE_REGULAR;
|
| +}
|
| +
|
| bool UserManagerImpl::IsLoggedInAsDemoUser() const {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| return IsUserLoggedIn() &&
|
| @@ -553,46 +609,56 @@ void UserManagerImpl::NotifyLocalStateChanged() {
|
|
|
| void UserManagerImpl::EnsureUsersLoaded() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - if (!users_.empty())
|
| - return;
|
| if (!g_browser_process)
|
| return;
|
|
|
| + if (users_loaded_)
|
| + return;
|
| + users_loaded_ = true;
|
| +
|
| PrefService* local_state = g_browser_process->local_state();
|
| - const ListValue* prefs_users =
|
| - local_state->GetList(kLoggedInUsers);
|
| + const ListValue* prefs_regular_users = local_state->GetList(kRegularUsers);
|
| + const ListValue* prefs_public_accounts =
|
| + local_state->GetList(kPublicAccounts);
|
| const DictionaryValue* prefs_display_names =
|
| local_state->GetDictionary(kUserDisplayName);
|
| const DictionaryValue* prefs_display_emails =
|
| local_state->GetDictionary(kUserDisplayEmail);
|
|
|
| - if (!prefs_users)
|
| - return;
|
| -
|
| - for (ListValue::const_iterator it = prefs_users->begin();
|
| - it != prefs_users->end(); ++it) {
|
| - std::string email;
|
| - if ((*it)->GetAsString(&email)) {
|
| - User* user = User::CreateRegularUser(email);
|
| - user->set_oauth_token_status(LoadUserOAuthStatus(email));
|
| - users_.push_back(user);
|
| -
|
| - string16 display_name;
|
| - if (prefs_display_names &&
|
| - prefs_display_names->GetStringWithoutPathExpansion(
|
| - email, &display_name)) {
|
| - user->set_display_name(display_name);
|
| - }
|
| + // Load regular users.
|
| + std::vector<std::string> regular_users;
|
| + std::set<std::string> regular_users_set;
|
| + ParseUserList(*prefs_regular_users, std::set<std::string>(), "",
|
| + ®ular_users, ®ular_users_set);
|
| + for (std::vector<std::string>::const_iterator it = regular_users.begin();
|
| + it != regular_users.end(); ++it) {
|
| + User* user = User::CreateRegularUser(*it);
|
| + user->set_oauth_token_status(LoadUserOAuthStatus(*it));
|
| + users_.push_back(user);
|
| +
|
| + string16 display_name;
|
| + if (prefs_display_names->GetStringWithoutPathExpansion(*it,
|
| + &display_name)) {
|
| + user->set_display_name(display_name);
|
| + }
|
|
|
| - std::string display_email;
|
| - if (prefs_display_emails &&
|
| - prefs_display_emails->GetStringWithoutPathExpansion(
|
| - email, &display_email)) {
|
| - user->set_display_email(display_email);
|
| - }
|
| + std::string display_email;
|
| + if (prefs_display_emails->GetStringWithoutPathExpansion(*it,
|
| + &display_email)) {
|
| + user->set_display_email(display_email);
|
| }
|
| }
|
|
|
| + // Load public accounts.
|
| + std::vector<std::string> public_accounts;
|
| + std::set<std::string> public_accounts_set;
|
| + ParseUserList(*prefs_public_accounts, regular_users_set, "",
|
| + &public_accounts, &public_accounts_set);
|
| + for (std::vector<std::string>::const_iterator it = public_accounts.begin();
|
| + it != public_accounts.end(); ++it) {
|
| + users_.push_back(User::CreatePublicAccountUser(*it));
|
| + }
|
| +
|
| user_image_manager_->LoadUserImages(users_);
|
| }
|
|
|
| @@ -600,42 +666,53 @@ void UserManagerImpl::RetrieveTrustedDevicePolicies() {
|
| ephemeral_users_enabled_ = false;
|
| owner_email_ = "";
|
|
|
| - CrosSettings* cros_settings = CrosSettings::Get();
|
| // Schedule a callback if device policy has not yet been verified.
|
| - if (CrosSettingsProvider::TRUSTED != cros_settings->PrepareTrustedValues(
|
| + if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
|
| base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies,
|
| base::Unretained(this)))) {
|
| return;
|
| }
|
|
|
| - cros_settings->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
|
| - &ephemeral_users_enabled_);
|
| - cros_settings->GetString(kDeviceOwner, &owner_email_);
|
| + cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
|
| + &ephemeral_users_enabled_);
|
| + cros_settings_->GetString(kDeviceOwner, &owner_email_);
|
| + const base::ListValue* public_accounts;
|
| + cros_settings_->GetList(kAccountsPrefDeviceLocalAccounts, &public_accounts);
|
| +
|
| + EnsureUsersLoaded();
|
| +
|
| + bool changed = UpdateAndCleanUpPublicAccounts(*public_accounts);
|
|
|
| // If ephemeral users are enabled and we are on the login screen, take this
|
| - // opportunity to clean up by removing all users except the owner.
|
| + // opportunity to clean up by removing all regular users except the owner.
|
| if (ephemeral_users_enabled_ && !IsUserLoggedIn()) {
|
| - scoped_ptr<base::ListValue> users(
|
| - g_browser_process->local_state()->GetList(kLoggedInUsers)->DeepCopy());
|
| -
|
| - bool changed = false;
|
| - for (base::ListValue::const_iterator user = users->begin();
|
| - user != users->end(); ++user) {
|
| - std::string user_email;
|
| - (*user)->GetAsString(&user_email);
|
| - if (user_email != owner_email_) {
|
| - RemoveUserFromListInternal(user_email);
|
| + ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
|
| + kRegularUsers);
|
| + prefs_users_update->Clear();
|
| + for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
|
| + const std::string user_email = (*it)->email();
|
| + if ((*it)->GetType() == User::USER_TYPE_REGULAR &&
|
| + user_email != owner_email_) {
|
| + RemoveNonCryptohomeData(user_email);
|
| + delete *it;
|
| + it = users_.erase(it);
|
| changed = true;
|
| + } else {
|
| + prefs_users_update->Append(new base::StringValue(user_email));
|
| + ++it;
|
| }
|
| }
|
| + }
|
|
|
| - if (changed) {
|
| - content::NotificationService::current()->Notify(
|
| - chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
|
| - content::Source<UserManager>(this),
|
| - content::NotificationService::NoDetails());
|
| - }
|
| + if (changed) {
|
| + content::NotificationService::current()->Notify(
|
| + chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
|
| + content::Source<UserManager>(this),
|
| + content::NotificationService::NoDetails());
|
| }
|
| +
|
| + cros_settings_->AddSettingsObserver(kAccountsPrefDeviceLocalAccounts,
|
| + this);
|
| }
|
|
|
| bool UserManagerImpl::AreEphemeralUsersEnabled() const {
|
| @@ -681,24 +758,11 @@ void UserManagerImpl::CheckOwnership() {
|
| base::Unretained(this)));
|
| }
|
|
|
| -void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
|
| - // Clear the prefs view of the users.
|
| - PrefService* prefs = g_browser_process->local_state();
|
| - ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
|
| - prefs_users_update->Clear();
|
| -
|
| - UserList::iterator user_to_remove = users_.end();
|
| - for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
|
| - std::string user_email = (*it)->email();
|
| - // Skip user that we would like to delete.
|
| - if (email != user_email)
|
| - prefs_users_update->Append(new base::StringValue(user_email));
|
| - else
|
| - user_to_remove = it;
|
| - }
|
| -
|
| +void UserManagerImpl::RemoveNonCryptohomeData(const std::string& email) {
|
| WallpaperManager::Get()->RemoveUserWallpaperInfo(email);
|
| + user_image_manager_->DeleteUserImage(email);
|
|
|
| + PrefService* prefs = g_browser_process->local_state();
|
| DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
|
| int oauth_status;
|
| prefs_oauth_update->GetIntegerWithoutPathExpansion(email, &oauth_status);
|
| @@ -709,11 +773,112 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
|
|
|
| DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
|
| prefs_display_email_update->RemoveWithoutPathExpansion(email, NULL);
|
| +}
|
| +
|
| +User *UserManagerImpl::RemoveRegularUserFromList(const std::string& email) {
|
| + ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
|
| + kRegularUsers);
|
| + prefs_users_update->Clear();
|
| + User* user = NULL;
|
| + for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
|
| + const std::string user_email = (*it)->email();
|
| + if (user_email == email) {
|
| + user = *it;
|
| + it = users_.erase(it);
|
| + } else {
|
| + if ((*it)->GetType() == User::USER_TYPE_REGULAR)
|
| + prefs_users_update->Append(new base::StringValue(user_email));
|
| + ++it;
|
| + }
|
| + }
|
| + return user;
|
| +}
|
| +
|
| +bool UserManagerImpl::UpdateAndCleanUpPublicAccounts(
|
| + const base::ListValue& public_accounts) {
|
| + PrefService* local_state = g_browser_process->local_state();
|
|
|
| - if (user_to_remove != users_.end()) {
|
| - delete *user_to_remove;
|
| - users_.erase(user_to_remove);
|
| + // Determine the currently logged-in user's email.
|
| + std::string logged_in_user_email;
|
| + if (IsUserLoggedIn())
|
| + logged_in_user_email = GetLoggedInUser()->email();
|
| +
|
| + // If there is a public account whose data is pending removal and the user is
|
| + // not currently logged in with that account, take this opportunity to remove
|
| + // the data.
|
| + std::string public_account_pending_data_removal =
|
| + local_state->GetString(kPublicAccountPendingDataRemoval);
|
| + if (!public_account_pending_data_removal.empty() &&
|
| + public_account_pending_data_removal != logged_in_user_email) {
|
| + RemoveNonCryptohomeData(public_account_pending_data_removal);
|
| + local_state->ClearPref(kPublicAccountPendingDataRemoval);
|
| }
|
| +
|
| + // Split the current user list public accounts and regular users.
|
| + std::vector<std::string> old_public_accounts;
|
| + std::set<std::string> regular_users;
|
| + for (UserList::const_iterator it = users_.begin(); it != users_.end(); ++it) {
|
| + if ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT)
|
| + old_public_accounts.push_back((*it)->email());
|
| + else
|
| + regular_users.insert((*it)->email());
|
| + }
|
| +
|
| + // Get the new list of public accounts from policy.
|
| + std::vector<std::string> new_public_accounts;
|
| + std::set<std::string> new_public_accounts_set;
|
| + if (!ParseUserList(public_accounts, regular_users, logged_in_user_email,
|
| + &new_public_accounts, &new_public_accounts_set) &&
|
| + IsUserLoggedIn()) {
|
| + User* user = GetLoggedInUser();
|
| + // If the user is currently logged into a public account that has been
|
| + // removed from the list, mark the account's data as pending removal after
|
| + // logout.
|
| + if (user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
|
| + local_state->SetString(kPublicAccountPendingDataRemoval,
|
| + logged_in_user_email);
|
| + }
|
| + }
|
| +
|
| + // Persist the new list of public accounts in a pref.
|
| + ListPrefUpdate prefs_public_accounts_update(local_state, kPublicAccounts);
|
| + scoped_ptr<base::ListValue> prefs_public_accounts(public_accounts.DeepCopy());
|
| + prefs_public_accounts_update->Swap(prefs_public_accounts.get());
|
| +
|
| + // If the list of public accounts has not changed, return.
|
| + if (new_public_accounts.size() == old_public_accounts.size()) {
|
| + bool changed = false;
|
| + for (size_t i = 0; i < new_public_accounts.size(); ++i) {
|
| + if (new_public_accounts[i] != old_public_accounts[i]) {
|
| + changed = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!changed)
|
| + return false;
|
| + }
|
| +
|
| + // Remove the old public accounts from the user list.
|
| + for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
|
| + if ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT) {
|
| + delete *it;
|
| + it = users_.erase(it);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| +
|
| + // Add the new public accounts to the front of the user list.
|
| + for (std::vector<std::string>::const_reverse_iterator
|
| + it = new_public_accounts.rbegin();
|
| + it != new_public_accounts.rend(); ++it) {
|
| + users_.insert(users_.begin(), User::CreatePublicAccountUser(*it));
|
| + }
|
| +
|
| + user_image_manager_->LoadUserImages(
|
| + UserList(users_.begin(), users_.begin() + new_public_accounts.size()));
|
| +
|
| + return true;
|
| }
|
|
|
| } // namespace chromeos
|
|
|