summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralemate@chromium.org <alemate@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-20 18:09:26 +0000
committeralemate@chromium.org <alemate@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-20 18:09:26 +0000
commit357d4d0549a199286fb4a9bb60e4bdd404391e95 (patch)
treee781fc597d62bffaefafdce0efb82ec3e37462fa
parent2246526c5191696ea09314c79ab767ba6b4cdf64 (diff)
downloadchromium_src-357d4d0549a199286fb4a9bb60e4bdd404391e95.zip
chromium_src-357d4d0549a199286fb4a9bb60e4bdd404391e95.tar.gz
chromium_src-357d4d0549a199286fb4a9bb60e4bdd404391e95.tar.bz2
WallpaperLoader should inform caller that load request is finished.
There are several problems with wallpaper loading: 1) WallpaperLoader is asynchronous, but exposes synchronous API. Therefore callers do not know when request is finished and whether it is completed or not. 2) WallpaperLoader doesn't have "rate limit" on SetWallpaper requests, therefore it is implemented outside of it (currently in JS). Taking into account the fact that caller has no way to know the result of request, this mechanism leads to stuck wallpaper, or even to blocked UI. This CL introduces: 1) A callback is passed along with load request to WallpaperLoader to get "Finished" event. 2) Wallpaper load scheduler in WallpaperManager to "rate limit" load requests. It has automatic load delay management so that most SetUserWallpaper() requests would become immediate. But delay is automatically adjusted to the average of several last load attempts. BUG=333809 TEST=manual Review URL: https://codereview.chromium.org/88263002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245925 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/extensions/wallpaper_private_api.cc2
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.cc20
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.cc411
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.h143
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc60
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager_unittest.cc5
-rw-r--r--chrome/browser/chromeos/login/webui_login_display.cc4
-rw-r--r--chrome/browser/resources/chromeos/login/screen_account_picker.js8
-rw-r--r--chrome/browser/resources/chromeos/login/user_pod_row.js24
-rw-r--r--chrome/browser/resources/chromeos/login/wallpaper_loader.js223
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc2
-rw-r--r--chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc2
-rw-r--r--chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc10
-rw-r--r--chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h7
14 files changed, 520 insertions, 401 deletions
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
index c4b71df..bd280f7 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -499,7 +499,7 @@ bool WallpaperPrivateResetWallpaperFunction::RunImpl() {
bool is_persistent =
!user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
- wallpaper_manager->SetDefaultWallpaper();
+ wallpaper_manager->SetDefaultWallpaperNow();
return true;
}
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index d0ce2ce..bd03d26 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -344,7 +344,7 @@ void UserManagerImpl::UserLoggedIn(const std::string& user_id,
// Reset the new user flag if the user already exists.
is_current_user_new_ = false;
// Set active user wallpaper back.
- WallpaperManager::Get()->SetUserWallpaper(active_user_->email());
+ WallpaperManager::Get()->SetUserWallpaperNow(active_user_->email());
NotifyUserAddedToSession(user);
return;
}
@@ -1228,8 +1228,7 @@ void UserManagerImpl::GuestUserLoggedIn() {
// http://crosbug.com/230859
active_user_->SetStubImage(User::kInvalidImageIndex, false);
// Initializes wallpaper after active_user_ is set.
- WallpaperManager::Get()->SetInitialUserWallpaper(UserManager::kGuestUserName,
- false);
+ WallpaperManager::Get()->SetUserWallpaperNow(UserManager::kGuestUserName);
}
void UserManagerImpl::AddUserRecord(User* user) {
@@ -1251,7 +1250,7 @@ void UserManagerImpl::RegularUserLoggedIn(const std::string& user_id) {
active_user_->set_oauth_token_status(LoadUserOAuthStatus(user_id));
SaveUserDisplayName(active_user_->email(),
base::UTF8ToUTF16(active_user_->GetAccountName(true)));
- WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
+ WallpaperManager::Get()->SetUserWallpaperNow(user_id);
}
AddUserRecord(active_user_);
@@ -1271,7 +1270,7 @@ void UserManagerImpl::RegularUserLoggedInAsEphemeral(
is_current_user_ephemeral_regular_user_ = true;
active_user_ = User::CreateRegularUser(user_id);
GetUserImageManager(user_id)->UserLoggedIn(is_current_user_new_, false);
- WallpaperManager::Get()->SetInitialUserWallpaper(user_id, false);
+ WallpaperManager::Get()->SetUserWallpaperNow(user_id);
}
void UserManagerImpl::LocallyManagedUserLoggedIn(
@@ -1285,11 +1284,11 @@ void UserManagerImpl::LocallyManagedUserLoggedIn(
is_current_user_new_ = true;
active_user_ = User::CreateLocallyManagedUser(user_id);
// Leaving OAuth token status at the default state = unknown.
- WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
+ WallpaperManager::Get()->SetUserWallpaperNow(user_id);
} else {
if (supervised_user_manager_->CheckForFirstRun(user_id)) {
is_current_user_new_ = true;
- WallpaperManager::Get()->SetInitialUserWallpaper(user_id, true);
+ WallpaperManager::Get()->SetUserWallpaperNow(user_id);
} else {
is_current_user_new_ = false;
}
@@ -1334,7 +1333,8 @@ void UserManagerImpl::KioskAppLoggedIn(const std::string& app_id) {
active_user_ = User::CreateKioskAppUser(app_id);
active_user_->SetStubImage(User::kInvalidImageIndex, false);
- WallpaperManager::Get()->SetInitialUserWallpaper(app_id, false);
+
+ WallpaperManager::Get()->SetUserWallpaperNow(app_id);
// TODO(bartfab): Add KioskAppUsers to the users_ list and keep metadata like
// the kiosk_app_id in these objects, removing the need to re-parse the
@@ -1375,8 +1375,8 @@ void UserManagerImpl::RetailModeUserLoggedIn() {
GetUserImageManager(UserManager::kRetailModeUserName)->UserLoggedIn(
is_current_user_new_,
true);
- WallpaperManager::Get()->SetInitialUserWallpaper(
- UserManager::kRetailModeUserName, false);
+ WallpaperManager::Get()->SetUserWallpaperNow(
+ UserManager::kRetailModeUserName);
}
void UserManagerImpl::NotifyOnLogin() {
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index e19da34..479c13e 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
+#include <numeric>
#include <vector>
#include "ash/shell.h"
@@ -75,6 +76,18 @@ const char kOriginalCustomWallpaperSuffix[] = "_wallpaper";
// Maximum number of wallpapers cached by CacheUsersWallpapers().
const int kMaxWallpapersToCache = 3;
+// Maximum number of entries in WallpaperManager::last_load_times_ .
+const size_t kLastLoadsStatsMsMaxSize = 4;
+
+// Minimum delay between wallpaper loads, milliseconds.
+const unsigned kLoadMinDelayMs = 50;
+
+// Default wallpaper load delay, milliseconds.
+const unsigned kLoadDefaultDelayMs = 200;
+
+// Maximum wallpaper load delay, milliseconds.
+const unsigned kLoadMaxDelayMs = 2000;
+
// For our scaling ratios we need to round positive numbers.
int RoundPositive(double x) {
return static_cast<int>(floor(x + 0.5));
@@ -115,6 +128,142 @@ const char kThumbnailWallpaperSubDir[] = "thumb";
static WallpaperManager* g_wallpaper_manager = NULL;
+// This object is passed between several threads while wallpaper is being
+// loaded. It will notify callback when last reference to it is removed
+// (thus indicating that the last load action has finished).
+class MovableOnDestroyCallback {
+ public:
+ explicit MovableOnDestroyCallback(const base::Closure& callback)
+ : callback_(callback) {
+ }
+
+ ~MovableOnDestroyCallback() {
+ if (!callback_.is_null())
+ callback_.Run();
+ }
+
+ private:
+ base::Closure callback_;
+};
+
+WallpaperManager::PendingWallpaper::PendingWallpaper(
+ const base::TimeDelta delay,
+ const std::string& username)
+ : username_(username),
+ default_(false),
+ on_finish_(new MovableOnDestroyCallback(
+ base::Bind(&WallpaperManager::PendingWallpaper::OnWallpaperSet,
+ this))) {
+ timer.Start(
+ FROM_HERE,
+ delay,
+ base::Bind(&WallpaperManager::PendingWallpaper::ProcessRequest, this));
+}
+
+WallpaperManager::PendingWallpaper::~PendingWallpaper() {}
+
+void WallpaperManager::PendingWallpaper::ResetSetWallpaperImage(
+ const gfx::ImageSkia& user_wallpaper,
+ const WallpaperInfo& info) {
+ SetMode(user_wallpaper, info, base::FilePath(), false);
+}
+
+void WallpaperManager::PendingWallpaper::ResetLoadWallpaper(
+ const WallpaperInfo& info) {
+ SetMode(gfx::ImageSkia(), info, base::FilePath(), false);
+}
+
+void WallpaperManager::PendingWallpaper::ResetSetCustomWallpaper(
+ const WallpaperInfo& info,
+ const base::FilePath& wallpaper_path) {
+ SetMode(gfx::ImageSkia(), info, wallpaper_path, false);
+}
+
+void WallpaperManager::PendingWallpaper::ResetSetDefaultWallpaper() {
+ SetMode(gfx::ImageSkia(), WallpaperInfo(), base::FilePath(), true);
+}
+
+void WallpaperManager::PendingWallpaper::SetMode(
+ const gfx::ImageSkia& user_wallpaper,
+ const WallpaperInfo& info,
+ const base::FilePath& wallpaper_path,
+ const bool is_default) {
+ user_wallpaper_ = user_wallpaper;
+ info_ = info;
+ wallpaper_path_ = wallpaper_path;
+ default_ = is_default;
+}
+
+void WallpaperManager::PendingWallpaper::ProcessRequest() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ timer.Stop(); // Erase reference to self.
+
+ WallpaperManager* manager = WallpaperManager::Get();
+ if (manager->pending_inactive_ == this)
+ manager->pending_inactive_ = NULL;
+
+ started_load_at_ = base::Time::Now();
+
+ if (default_) {
+ manager->DoSetDefaultWallpaper(on_finish_.Pass());
+ } else if (!user_wallpaper_.isNull()) {
+ ash::Shell::GetInstance()->
+ desktop_background_controller()->
+ SetCustomWallpaper(user_wallpaper_, info_.layout);
+ } else if (!wallpaper_path_.empty()) {
+ manager->task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
+ base::Unretained(manager),
+ username_,
+ info_,
+ wallpaper_path_,
+ true /* update wallpaper */,
+ base::Passed(on_finish_.Pass())));
+ } else if (!info_.file.empty()) {
+ manager->LoadWallpaper(username_, info_, true, on_finish_.Pass());
+ } else {
+ // PendingWallpaper was created and never initialized?
+ NOTREACHED();
+ // Error. Do not record time.
+ started_load_at_ = base::Time();
+ }
+ on_finish_.reset();
+}
+
+void WallpaperManager::PendingWallpaper::OnWallpaperSet() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The only known case for this check to fail is global destruction during
+ // wallpaper load. It should never happen.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
+ return; // We are in a process of global destruction.
+
+ timer.Stop(); // Erase reference to self.
+
+ WallpaperManager* manager = WallpaperManager::Get();
+ if (!started_load_at_.is_null()) {
+ const base::TimeDelta elapsed = base::Time::Now() - started_load_at_;
+ manager->SaveLastLoadTime(elapsed);
+ }
+ if (manager->pending_inactive_ == this) {
+ // ProcessRequest() was never executed.
+ manager->pending_inactive_ = NULL;
+ }
+
+ // Destroy self.
+ DCHECK(manager->loading_.size() > 0);
+
+ for (WallpaperManager::PendingList::iterator i = manager->loading_.begin();
+ i != manager->loading_.end();
+ ++i)
+ if (i->get() == this) {
+ manager->loading_.erase(i);
+ break;
+ }
+}
+
// WallpaperManager, public: ---------------------------------------------------
// TestApi. For testing purpose
@@ -140,7 +289,8 @@ WallpaperManager::WallpaperManager()
: loaded_wallpapers_(0),
command_line_for_testing_(NULL),
should_cache_wallpaper_(false),
- weak_factory_(this) {
+ weak_factory_(this),
+ pending_inactive_(NULL) {
registrar_.Add(this,
chrome::NOTIFICATION_LOGIN_USER_CHANGED,
content::NotificationService::AllSources());
@@ -164,6 +314,7 @@ WallpaperManager::~WallpaperManager() {
// TODO(bshe): Lifetime of WallpaperManager needs more consideration.
// http://crbug.com/171694
DCHECK(!show_user_name_on_signin_subscription_);
+
ClearObsoleteWallpaperPrefs();
weak_factory_.InvalidateWeakPtrs();
}
@@ -201,7 +352,7 @@ void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
if (info == current_user_wallpaper_info_)
return;
}
- SetUserWallpaper(UserManager::Get()->GetLoggedInUser()->email());
+ SetUserWallpaperNow(UserManager::Get()->GetLoggedInUser()->email());
}
void WallpaperManager::ClearWallpaperCache() {
@@ -277,12 +428,12 @@ void WallpaperManager::InitializeWallpaper() {
if (!user_manager->IsUserLoggedIn()) {
if (!StartupUtils::IsDeviceRegistered())
- SetDefaultWallpaper();
+ SetDefaultWallpaperDelayed();
else
InitializeRegisteredDeviceWallpaper();
return;
}
- SetUserWallpaper(user_manager->GetLoggedInUser()->email());
+ SetUserWallpaperDelayed(user_manager->GetLoggedInUser()->email());
}
void WallpaperManager::Observe(int type,
@@ -432,7 +583,7 @@ void WallpaperManager::SetCustomWallpaper(const std::string& username,
// If decoded wallpaper is empty, we are probably failed to decode the file.
// Use default wallpaper in this case.
if (wallpaper.image().isNull()) {
- SetDefaultWallpaper();
+ SetDefaultWallpaperDelayed();
return;
}
@@ -479,18 +630,32 @@ void WallpaperManager::SetCustomWallpaper(const std::string& username,
SetUserWallpaperInfo(username, info, is_persistent);
}
-void WallpaperManager::SetDefaultWallpaper() {
+void WallpaperManager::SetDefaultWallpaperNow() {
+ GetPendingWallpaper(std::string(), false)->ResetSetDefaultWallpaper();
+}
+
+void WallpaperManager::SetDefaultWallpaperDelayed() {
+ GetPendingWallpaper(std::string(), true)->ResetSetDefaultWallpaper();
+}
+
+void WallpaperManager::DoSetDefaultWallpaper(
+ MovableOnDestroyCallbackHolder on_finish) {
// There is no visible background in kiosk mode.
if (UserManager::Get()->IsLoggedInAsKioskApp())
return;
current_wallpaper_path_.clear();
+ // Some browser tests do not have a shell instance. As no wallpaper is needed
+ // in these tests anyway, avoid loading one, preventing crashes and speeding
+ // up the tests.
+ if (!ash::Shell::HasInstance())
+ return;
if (ash::Shell::GetInstance()->desktop_background_controller()->
SetDefaultWallpaper(UserManager::Get()->IsLoggedInAsGuest()))
loaded_wallpapers_++;
}
-void WallpaperManager::SetInitialUserWallpaper(const std::string& username,
- bool is_persistent) {
+void WallpaperManager::InitInitialUserWallpaper(const std::string& username,
+ bool is_persistent) {
current_user_wallpaper_info_.file = "";
current_user_wallpaper_info_.layout = ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
current_user_wallpaper_info_.type = User::DEFAULT;
@@ -498,13 +663,6 @@ void WallpaperManager::SetInitialUserWallpaper(const std::string& username,
WallpaperInfo info = current_user_wallpaper_info_;
SetUserWallpaperInfo(username, info, is_persistent);
- SetLastSelectedUser(username);
-
- // Some browser tests do not have a shell instance. As no wallpaper is needed
- // in these tests anyway, avoid loading one, preventing crashes and speeding
- // up the tests.
- if (ash::Shell::HasInstance())
- SetDefaultWallpaper();
}
void WallpaperManager::SetUserWallpaperInfo(const std::string& username,
@@ -533,13 +691,26 @@ void WallpaperManager::SetLastSelectedUser(
last_selected_user_ = last_selected_user;
}
-void WallpaperManager::SetUserWallpaper(const std::string& email) {
+void WallpaperManager::SetUserWallpaperDelayed(const std::string& email) {
+ ScheduleSetUserWallpaper(email, true);
+}
+
+void WallpaperManager::SetUserWallpaperNow(const std::string& email) {
+ ScheduleSetUserWallpaper(email, false);
+}
+
+void WallpaperManager::ScheduleSetUserWallpaper(const std::string& email,
+ bool delayed) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// There is no visible background in kiosk mode.
if (UserManager::Get()->IsLoggedInAsKioskApp())
return;
- if (email == UserManager::kGuestUserName) {
- SetDefaultWallpaper();
+ // Guest user, regular user in ephemeral mode, or kiosk app.
+ const User* user = UserManager::Get()->FindUser(email);
+ if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(email) ||
+ (user != NULL && user->GetType() == User::USER_TYPE_KIOSK_APP)) {
+ InitInitialUserWallpaper(email, false);
+ GetPendingWallpaper(email, delayed)->ResetSetDefaultWallpaper();
return;
}
@@ -550,49 +721,50 @@ void WallpaperManager::SetUserWallpaper(const std::string& email) {
WallpaperInfo info;
- if (GetUserWallpaperInfo(email, &info)) {
- gfx::ImageSkia user_wallpaper;
- current_user_wallpaper_info_ = info;
- if (GetWallpaperFromCache(email, &user_wallpaper)) {
- ash::Shell::GetInstance()->desktop_background_controller()->
- SetCustomWallpaper(user_wallpaper, info.layout);
- } else {
- if (info.type == User::CUSTOMIZED) {
- ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
- desktop_background_controller()->GetAppropriateResolution();
- const char* sub_dir = (resolution == ash::WALLPAPER_RESOLUTION_SMALL) ?
- kSmallWallpaperSubDir : kLargeWallpaperSubDir;
- // Wallpaper is not resized when layout is ash::WALLPAPER_LAYOUT_CENTER.
- // Original wallpaper should be used in this case.
- // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
- if (info.layout == ash::WALLPAPER_LAYOUT_CENTER)
- sub_dir = kOriginalWallpaperSubDir;
- base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
- wallpaper_path = wallpaper_path.Append(info.file);
- if (current_wallpaper_path_ == wallpaper_path)
- return;
- current_wallpaper_path_ = wallpaper_path;
- loaded_wallpapers_++;
-
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
- base::Unretained(this), email, info, wallpaper_path,
- true /* update wallpaper */));
- return;
- }
+ if (!GetUserWallpaperInfo(email, &info))
+ InitInitialUserWallpaper(email, true);
- if (info.file.empty()) {
- // Uses default built-in wallpaper when file is empty. Eventually, we
- // will only ship one built-in wallpaper in ChromeOS image.
- SetDefaultWallpaper();
+ gfx::ImageSkia user_wallpaper;
+ current_user_wallpaper_info_ = info;
+ if (GetWallpaperFromCache(email, &user_wallpaper)) {
+ GetPendingWallpaper(email, delayed)->
+ ResetSetWallpaperImage(user_wallpaper, info);
+ } else {
+ if (info.type == User::CUSTOMIZED) {
+ ash::WallpaperResolution resolution =
+ ash::Shell::GetInstance()->
+ desktop_background_controller()->
+ GetAppropriateResolution();
+ const char* sub_dir = (resolution == ash::WALLPAPER_RESOLUTION_SMALL)
+ ? kSmallWallpaperSubDir
+ : kLargeWallpaperSubDir;
+
+ // Wallpaper is not resized when layout is ash::WALLPAPER_LAYOUT_CENTER.
+ // Original wallpaper should be used in this case.
+ // TODO(bshe): Generates cropped custom wallpaper for CENTER layout.
+ if (info.layout == ash::WALLPAPER_LAYOUT_CENTER)
+ sub_dir = kOriginalWallpaperSubDir;
+ base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
+ wallpaper_path = wallpaper_path.Append(info.file);
+ if (current_wallpaper_path_ == wallpaper_path)
return;
- }
+ current_wallpaper_path_ = wallpaper_path;
+ loaded_wallpapers_++;
- // Load downloaded ONLINE or converted DEFAULT wallpapers.
- LoadWallpaper(email, info, true /* update wallpaper */);
+ GetPendingWallpaper(email, delayed)->
+ ResetSetCustomWallpaper(info, wallpaper_path);
+ return;
}
- } else {
- SetInitialUserWallpaper(email, true);
+
+ if (info.file.empty()) {
+ // Uses default built-in wallpaper when file is empty. Eventually, we
+ // will only ship one built-in wallpaper in ChromeOS image.
+ GetPendingWallpaper(email, delayed)->ResetSetDefaultWallpaper();
+ return;
+ }
+
+ // Load downloaded ONLINE or converted DEFAULT wallpapers.
+ GetPendingWallpaper(email, delayed)->ResetLoadWallpaper(info);
}
}
@@ -602,8 +774,10 @@ void WallpaperManager::SetWallpaperFromImageSkia(
// There is no visible background in kiosk mode.
if (UserManager::Get()->IsLoggedInAsKioskApp())
return;
- ash::Shell::GetInstance()->desktop_background_controller()->
- SetCustomWallpaper(wallpaper, layout);
+ WallpaperInfo info;
+ info.layout = layout;
+ GetPendingWallpaper(last_selected_user_, false /* Not delayed */)->
+ ResetSetWallpaperImage(wallpaper, info);
}
void WallpaperManager::UpdateWallpaper() {
@@ -614,10 +788,10 @@ void WallpaperManager::UpdateWallpaper() {
// be set. It could result a black screen on external monitors.
// See http://crbug.com/265689 for detail.
if (last_selected_user_.empty()) {
- SetDefaultWallpaper();
+ SetDefaultWallpaperNow();
return;
}
- SetUserWallpaper(last_selected_user_);
+ SetUserWallpaperNow(last_selected_user_);
}
void WallpaperManager::AddObserver(WallpaperManager::Observer* observer) {
@@ -666,13 +840,21 @@ void WallpaperManager::CacheUserWallpaper(const std::string& email) {
kSmallWallpaperSubDir : kLargeWallpaperSubDir;
base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir);
wallpaper_path = wallpaper_path.Append(info.file);
- task_runner_->PostTask(FROM_HERE,
+ task_runner_->PostTask(
+ FROM_HERE,
base::Bind(&WallpaperManager::GetCustomWallpaperInternal,
- base::Unretained(this), email, info, wallpaper_path,
- false /* do not update wallpaper */));
+ base::Unretained(this),
+ email,
+ info,
+ wallpaper_path,
+ false /* do not update wallpaper */,
+ base::Passed(MovableOnDestroyCallbackHolder())));
return;
}
- LoadWallpaper(email, info, false /* do not update wallpaper */);
+ LoadWallpaper(email,
+ info,
+ false /* do not update wallpaper */,
+ MovableOnDestroyCallbackHolder().Pass());
}
}
@@ -789,7 +971,7 @@ void WallpaperManager::InitializeRegisteredDeviceWallpaper() {
const chromeos::UserList& users = UserManager::Get()->GetUsers();
if (!show_users || users.empty()) {
// Boot into sign in form, preload default wallpaper.
- SetDefaultWallpaper();
+ SetDefaultWallpaperDelayed();
return;
}
@@ -797,13 +979,14 @@ void WallpaperManager::InitializeRegisteredDeviceWallpaper() {
// Normal boot, load user wallpaper.
// If normal boot animation is disabled wallpaper would be set
// asynchronously once user pods are loaded.
- SetUserWallpaper(users[0]->email());
+ SetUserWallpaperDelayed(users[0]->email());
}
}
void WallpaperManager::LoadWallpaper(const std::string& email,
const WallpaperInfo& info,
- bool update_wallpaper) {
+ bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish) {
base::FilePath wallpaper_dir;
base::FilePath wallpaper_path;
if (info.type == User::ONLINE) {
@@ -821,10 +1004,12 @@ void WallpaperManager::LoadWallpaper(const std::string& email,
wallpaper_path = wallpaper_dir.Append(file_name);
if (current_wallpaper_path_ == wallpaper_path)
return;
+
if (update_wallpaper)
current_wallpaper_path_ = wallpaper_path;
+
loaded_wallpapers_++;
- StartLoad(email, info, update_wallpaper, wallpaper_path);
+ StartLoad(email, info, update_wallpaper, wallpaper_path, on_finish.Pass());
} else if (info.type == User::DEFAULT) {
// Default wallpapers are migrated from M21 user profiles. A code refactor
// overlooked that case and caused these wallpapers not being loaded at all.
@@ -833,12 +1018,12 @@ void WallpaperManager::LoadWallpaper(const std::string& email,
base::FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
wallpaper_path = user_data_dir.Append(info.file);
- StartLoad(email, info, update_wallpaper, wallpaper_path);
+ StartLoad(email, info, update_wallpaper, wallpaper_path, on_finish.Pass());
} else {
// In unexpected cases, revert to default wallpaper to fail safely. See
// crosbug.com/38429.
LOG(ERROR) << "Wallpaper reverts to default unexpected.";
- SetDefaultWallpaper();
+ DoSetDefaultWallpaper(on_finish.Pass());
}
}
@@ -938,7 +1123,8 @@ void WallpaperManager::GetCustomWallpaperInternal(
const std::string& email,
const WallpaperInfo& info,
const base::FilePath& wallpaper_path,
- bool update_wallpaper) {
+ bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish) {
DCHECK(BrowserThread::GetBlockingPool()->
IsRunningSequenceOnCurrentThread(sequence_token_));
@@ -963,8 +1149,9 @@ void WallpaperManager::GetCustomWallpaperInternal(
"Fallback to default wallpaper";
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
- base::Bind(&WallpaperManager::SetDefaultWallpaper,
- base::Unretained(this)));
+ base::Bind(&WallpaperManager::DoSetDefaultWallpaper,
+ base::Unretained(this),
+ base::Passed(on_finish.Pass())));
} else {
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
@@ -973,14 +1160,17 @@ void WallpaperManager::GetCustomWallpaperInternal(
email,
info,
update_wallpaper,
- valid_path));
+ valid_path,
+ base::Passed(on_finish.Pass())));
}
}
-void WallpaperManager::OnWallpaperDecoded(const std::string& email,
- ash::WallpaperLayout layout,
- bool update_wallpaper,
- const UserImage& wallpaper) {
+void WallpaperManager::OnWallpaperDecoded(
+ const std::string& email,
+ ash::WallpaperLayout layout,
+ bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish,
+ const UserImage& wallpaper) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
TRACE_EVENT_ASYNC_END0("ui", "LoadAndDecodeWallpaper", this);
@@ -997,7 +1187,7 @@ void WallpaperManager::OnWallpaperDecoded(const std::string& email,
SetUserWallpaperInfo(email, info, true);
if (update_wallpaper)
- SetDefaultWallpaper();
+ DoSetDefaultWallpaper(on_finish.Pass());
return;
}
@@ -1073,16 +1263,71 @@ void WallpaperManager::SaveWallpaperInternal(const base::FilePath& path,
void WallpaperManager::StartLoad(const std::string& email,
const WallpaperInfo& info,
bool update_wallpaper,
- const base::FilePath& wallpaper_path) {
+ const base::FilePath& wallpaper_path,
+ MovableOnDestroyCallbackHolder on_finish) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
TRACE_EVENT_ASYNC_BEGIN0("ui", "LoadAndDecodeWallpaper", this);
- wallpaper_loader_->Start(wallpaper_path.value(), 0,
+ wallpaper_loader_->Start(wallpaper_path.value(),
+ 0,
base::Bind(&WallpaperManager::OnWallpaperDecoded,
base::Unretained(this),
email,
info.layout,
- update_wallpaper));
+ update_wallpaper,
+ base::Passed(on_finish.Pass())));
+}
+
+void WallpaperManager::SaveLastLoadTime(const base::TimeDelta elapsed) {
+ while (last_load_times_.size() >= kLastLoadsStatsMsMaxSize)
+ last_load_times_.pop_front();
+
+ if (elapsed > base::TimeDelta::FromMicroseconds(0)) {
+ last_load_times_.push_back(elapsed);
+ last_load_finished_at_ = base::Time::Now();
+ }
+}
+
+base::TimeDelta WallpaperManager::GetWallpaperLoadDelay() const {
+ base::TimeDelta delay;
+
+ if (last_load_times_.size() == 0) {
+ delay = base::TimeDelta::FromMilliseconds(kLoadDefaultDelayMs);
+ } else {
+ delay = std::accumulate(last_load_times_.begin(),
+ last_load_times_.end(),
+ base::TimeDelta(),
+ std::plus<base::TimeDelta>()) /
+ last_load_times_.size();
+ }
+
+ if (delay < base::TimeDelta::FromMilliseconds(kLoadMinDelayMs))
+ delay = base::TimeDelta::FromMilliseconds(kLoadMinDelayMs);
+ else if (delay > base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs))
+ delay = base::TimeDelta::FromMilliseconds(kLoadMaxDelayMs);
+
+ // If we had ever loaded wallpaper, adjust wait delay by time since last load.
+ if (!last_load_finished_at_.is_null()) {
+ const base::TimeDelta interval = base::Time::Now() - last_load_finished_at_;
+ if (interval > delay)
+ delay = base::TimeDelta::FromMilliseconds(0);
+ else if (interval > base::TimeDelta::FromMilliseconds(0))
+ delay -= interval;
+ }
+ return delay;
+}
+
+WallpaperManager::PendingWallpaper* WallpaperManager::GetPendingWallpaper(
+ const std::string& username,
+ bool delayed) {
+ if (!pending_inactive_) {
+ loading_.push_back(new WallpaperManager::PendingWallpaper(
+ (delayed ? GetWallpaperLoadDelay()
+ : base::TimeDelta::FromMilliseconds(0)),
+ username));
+ pending_inactive_ = loading_.back();
+ }
+ return pending_inactive_;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h
index ac8379c..916a7a2 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/wallpaper_manager.h
@@ -5,7 +5,9 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WALLPAPER_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WALLPAPER_MANAGER_H_
+#include <deque>
#include <string>
+#include <vector>
#include "ash/desktop_background/desktop_background_controller.h"
#include "base/files/file_path.h"
@@ -45,6 +47,9 @@ struct WallpaperInfo {
}
};
+class MovableOnDestroyCallback;
+typedef scoped_ptr<MovableOnDestroyCallback> MovableOnDestroyCallbackHolder;
+
class WallpaperManagerBrowserTest;
class UserImage;
@@ -87,6 +92,72 @@ class WallpaperManager: public content::NotificationObserver {
virtual void OnWallpaperAnimationFinished(const std::string& email) = 0;
};
+ // This is "wallpaper either scheduled to load, or loading right now".
+ //
+ // While enqueued, it defines moment in the future, when it will be loaded.
+ // Enqueued but not started request might be updated by subsequent load
+ // request. Therefore it's created empty, and updated being enqueued.
+ //
+ // PendingWallpaper is owned by WallpaperManager, but reference to this object
+ // is passed to other threads by PoskTask() calls, therefore it is
+ // RefCountedThreadSafe.
+ class PendingWallpaper : public base::RefCountedThreadSafe<PendingWallpaper> {
+ public:
+ // Do LoadWallpaper() - image not found in cache.
+ PendingWallpaper(const base::TimeDelta delay, const std::string& username);
+
+ // There are 4 cases in SetUserWallpaper:
+ // 1) gfx::ImageSkia is found in cache.
+ // - Schedule task to (probably) resize it and install:
+ // call ash::Shell::GetInstance()->desktop_background_controller()->
+ // SetCustomWallpaper(user_wallpaper, layout);
+ // 2) WallpaperInfo is found in cache
+ // - need to LoadWallpaper(), resize and install.
+ // 3) wallpaper path is not NULL, load image URL, then resize, etc...
+ // 4) SetDefaultWallpaper (either on some error, or when user is new).
+ void ResetSetWallpaperImage(const gfx::ImageSkia& user_wallpaper,
+ const WallpaperInfo& info);
+ void ResetLoadWallpaper(const WallpaperInfo& info);
+ void ResetSetCustomWallpaper(const WallpaperInfo& info,
+ const base::FilePath& wallpaper_path);
+ void ResetSetDefaultWallpaper();
+
+ private:
+ friend class base::RefCountedThreadSafe<PendingWallpaper>;
+
+ ~PendingWallpaper();
+
+ // All Reset*() methods use SetMode() to set object to new state.
+ void SetMode(const gfx::ImageSkia& user_wallpaper,
+ const WallpaperInfo& info,
+ const base::FilePath& wallpaper_path,
+ const bool is_default);
+
+ // This method is usually triggered by timer to actually load request.
+ void ProcessRequest();
+
+ // This method is called by callback, when load request is finished.
+ void OnWallpaperSet();
+
+ std::string username_;
+ WallpaperInfo info_;
+ gfx::ImageSkia user_wallpaper_;
+ base::FilePath wallpaper_path_;
+
+ // Load default wallpaper instead of user image.
+ bool default_;
+
+ // This is "on destroy" callback that will call OnWallpaperSet() when
+ // image will be loaded.
+ MovableOnDestroyCallbackHolder on_finish_;
+ base::OneShotTimer<WallpaperManager::PendingWallpaper> timer;
+
+ // Load start time to calculate duration.
+ base::Time started_load_at_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingWallpaper);
+ };
+
static WallpaperManager* Get();
WallpaperManager();
@@ -168,12 +239,16 @@ class WallpaperManager: public content::NotificationObserver {
User::WallpaperType type,
const UserImage& wallpaper);
- // Sets wallpaper to default wallpaper.
- void SetDefaultWallpaper();
+ // Sets wallpaper to default wallpaper (asynchronously with zero delay).
+ void SetDefaultWallpaperNow();
- // Sets one of the default wallpapers for the specified user and saves this
+ // Sets wallpaper to default wallpaper (asynchronously with default delay).
+ void SetDefaultWallpaperDelayed();
+
+ // Initialize wallpaper for the specified user to default and saves this
// settings in local state.
- void SetInitialUserWallpaper(const std::string& username, bool is_persistent);
+ void InitInitialUserWallpaper(const std::string& username,
+ bool is_persistent);
// Sets selected wallpaper information for |username| and saves it to Local
// State if |is_persistent| is true.
@@ -184,15 +259,18 @@ class WallpaperManager: public content::NotificationObserver {
// Sets last selected user on user pod row.
void SetLastSelectedUser(const std::string& last_selected_user);
- // Sets |email|'s wallpaper.
- void SetUserWallpaper(const std::string& email);
+ // Sets |email|'s wallpaper (asynchronously with zero delay).
+ void SetUserWallpaperNow(const std::string& email);
+
+ // Sets |email|'s wallpaper (asynchronously with default delay).
+ void SetUserWallpaperDelayed(const std::string& email);
- // Sets wallpaper to |wallpaper|.
+ // Sets wallpaper to |wallpaper| (asynchronously with zero delay).
void SetWallpaperFromImageSkia(const gfx::ImageSkia& wallpaper,
ash::WallpaperLayout layout);
// Updates current wallpaper. It may switch the size of wallpaper based on the
- // current display's resolution.
+ // current display's resolution. (asynchronously with zero delay)
void UpdateWallpaper();
// Adds given observer to the list.
@@ -252,7 +330,8 @@ class WallpaperManager: public content::NotificationObserver {
// to the loaded wallpaper.
void LoadWallpaper(const std::string& email,
const WallpaperInfo& info,
- bool update_wallpaper);
+ bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish);
// Moves custom wallpapers from |email| directory to |user_id_hash|
// directory.
@@ -276,7 +355,8 @@ class WallpaperManager: public content::NotificationObserver {
void GetCustomWallpaperInternal(const std::string& email,
const WallpaperInfo& info,
const base::FilePath& wallpaper_path,
- bool update_wallpaper);
+ bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish);
// Gets wallpaper information of |email| from Local State or memory. Returns
// false if wallpaper information is not found.
@@ -287,6 +367,7 @@ class WallpaperManager: public content::NotificationObserver {
void OnWallpaperDecoded(const std::string& email,
ash::WallpaperLayout layout,
bool update_wallpaper,
+ MovableOnDestroyCallbackHolder on_finish,
const UserImage& wallpaper);
// Generates thumbnail of custom wallpaper on wallpaper sequenced worker
@@ -312,16 +393,38 @@ class WallpaperManager: public content::NotificationObserver {
void SaveWallpaperInternal(const base::FilePath& path, const char* data,
int size);
+ // Creates new PendingWallpaper request (or updates currently pending).
+ void ScheduleSetUserWallpaper(const std::string& email, bool delayed);
+
+ // Sets wallpaper to default.
+ void DoSetDefaultWallpaper(MovableOnDestroyCallbackHolder on_finish);
+
// Starts to load wallpaper at |wallpaper_path|. If |wallpaper_path| is the
// same as |current_wallpaper_path_|, do nothing. Must be called on UI thread.
void StartLoad(const std::string& email,
const WallpaperInfo& info,
bool update_wallpaper,
- const base::FilePath& wallpaper_path);
+ const base::FilePath& wallpaper_path,
+ MovableOnDestroyCallbackHolder on_finish);
+
+ // After completed load operation, update average load time.
+ void SaveLastLoadTime(const base::TimeDelta elapsed);
// Notify all registed observers.
void NotifyAnimationFinished();
+ // Returns modifiable PendingWallpaper.
+ // Returns pending_inactive_ or creates new PendingWallpaper if necessary.
+ PendingWallpaper* GetPendingWallpaper(const std::string& username,
+ bool delayed);
+
+ // Calculate delay for next wallpaper load.
+ // It is usually average wallpaper load time.
+ // If last wallpaper load happened long ago, timeout should be reduced by
+ // the time passed after last wallpaper load. So usual user experience results
+ // in zero delay.
+ base::TimeDelta GetWallpaperLoadDelay() const;
+
// The number of loaded wallpapers.
int loaded_wallpapers_;
@@ -360,6 +463,24 @@ class WallpaperManager: public content::NotificationObserver {
ObserverList<Observer> observers_;
+ // These members are for the scheduler:
+
+ // When last load attempt finished.
+ base::Time last_load_finished_at_;
+
+ // last N wallpaper loads times.
+ std::deque<base::TimeDelta> last_load_times_;
+
+ // Pointer to last inactive (waiting) entry of 'loading_' list.
+ // NULL when there is no inactive request.
+ PendingWallpaper* pending_inactive_;
+
+ // Owns PendingWallpaper.
+ // PendingWallpaper deletes itself from here on load complete.
+ // All pending will be finally deleted on destroy.
+ typedef std::vector<scoped_refptr<PendingWallpaper> > PendingList;
+ PendingList loading_;
+
DISALLOW_COPY_AND_ASSIGN(WallpaperManager);
};
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
index 191d992..a265a6b 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
@@ -85,8 +85,16 @@ class WallpaperManagerBrowserTest : public InProcessBrowserTest,
display_manager_test_api.UpdateDisplay(display_specs);
}
- void WaitAsyncWallpaperLoad() {
- base::MessageLoop::current()->Run();
+ void WaitAsyncWallpaperLoadStarted() {
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ void WaitAsyncWallpaperLoadFinished() {
+ base::MessageLoop::current()->RunUntilIdle();
+ while (WallpaperManager::Get()->loading_.size()) {
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+ base::MessageLoop::current()->RunUntilIdle();
+ }
}
virtual void OnWallpaperDataChanged() OVERRIDE {
@@ -111,6 +119,7 @@ class WallpaperManagerBrowserTest : public InProcessBrowserTest,
// Logs in |username|.
void LogIn(const std::string& username, const std::string& username_hash) {
UserManager::Get()->UserLoggedIn(username, username_hash, false);
+ WaitAsyncWallpaperLoadStarted();
}
// Saves bitmap |resource_id| to disk.
@@ -143,8 +152,6 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
LoadCustomLargeWallpaperForLargeExternalScreen) {
WallpaperManager* wallpaper_manager = WallpaperManager::Get();
LogIn(kTestUser1, kTestUser1Hash);
- // Wait for default wallpaper loaded.
- WaitAsyncWallpaperLoad();
std::string id = base::Int64ToString(base::Time::Now().ToInternalValue());
base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
kSmallWallpaperSubDir,
@@ -173,8 +180,8 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true);
// Set the wallpaper for |kTestUser1|.
- wallpaper_manager->SetUserWallpaper(kTestUser1);
- WaitAsyncWallpaperLoad();
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadFinished();
gfx::ImageSkia wallpaper = controller_->GetWallpaper();
// Display is initialized to 800x600. The small resolution custom wallpaper is
@@ -194,7 +201,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
// Hook up a 2000x2000 display. The large resolution custom wallpaper should
// be loaded.
UpdateDisplay("800x600,2000x2000");
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
wallpaper = controller_->GetWallpaper();
// The large resolution custom wallpaper is expected.
@@ -206,7 +213,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
// Hook up the 2000x2000 display again. The large resolution default wallpaper
// should persist. Test for crbug/165788.
UpdateDisplay("800x600,2000x2000");
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
wallpaper = controller_->GetWallpaper();
// The large resolution custom wallpaper is expected.
@@ -225,12 +232,13 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
EXPECT_EQ(1, LoadedWallpapers());
// Loads the same wallpaper before the initial one finished. It should be
// prevented.
- wallpaper_manager->SetUserWallpaper(kTestUser1);
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadFinished();
EXPECT_EQ(1, LoadedWallpapers());
- WaitAsyncWallpaperLoad();
// Loads the same wallpaper after the initial one finished. It should be
// prevented.
- wallpaper_manager->SetUserWallpaper(kTestUser1);
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadFinished();
EXPECT_EQ(1, LoadedWallpapers());
wallpaper_manager->ClearWallpaperCache();
@@ -253,14 +261,16 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
};
wallpaper_manager->SetUserWallpaperInfo(kTestUser1, info, true);
- wallpaper_manager->SetUserWallpaper(kTestUser1);
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadStarted();
EXPECT_EQ(2, LoadedWallpapers());
// Loads the same wallpaper before the initial one finished. It should be
// prevented.
- wallpaper_manager->SetUserWallpaper(kTestUser1);
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadStarted();
EXPECT_EQ(2, LoadedWallpapers());
- WaitAsyncWallpaperLoad();
- wallpaper_manager->SetUserWallpaper(kTestUser1);
+ wallpaper_manager->SetUserWallpaperNow(kTestUser1);
+ WaitAsyncWallpaperLoadFinished();
EXPECT_EQ(2, LoadedWallpapers());
}
@@ -272,7 +282,6 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
PRE_UseMigratedWallpaperInfo) {
// New user log in, a default wallpaper is loaded.
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
// Old wallpaper migration code doesn't exist in codebase anymore. Modify user
// wallpaper info directly to simulate the wallpaper migration. See
// crosbug.com/38429 for details about why we modify wallpaper info this way.
@@ -292,7 +301,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
UseMigratedWallpaperInfo) {
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
// This test should finish normally. If timeout, it is probably because
// migrated wallpaper is somehow not loaded. Bad things can happen if
// wallpaper is not loaded at login screen. One example is: crosbug.com/38429.
@@ -304,7 +313,6 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
PRE_UsePreMigrationWallpaperInfo) {
// New user log in, a default wallpaper is loaded.
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
// Old wallpaper migration code doesn't exist in codebase anymore. So if
// user's profile is not migrated, it is the same as no wallpaper info. To
// simulate this, we remove user's wallpaper info here.
@@ -314,7 +322,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
UsePreMigrationWallpaperInfo) {
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
// This test should finish normally. If timeout, it is probably because chrome
// can not handle pre migrated user profile (M21 profile or older).
}
@@ -325,13 +333,13 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest,
HotPlugInScreenAtGAIALoginScreen) {
UpdateDisplay("800x600");
// Set initial wallpaper to the default wallpaper.
- WallpaperManager::Get()->SetDefaultWallpaper();
- WaitAsyncWallpaperLoad();
+ WallpaperManager::Get()->SetDefaultWallpaperNow();
+ WaitAsyncWallpaperLoadFinished();
// Hook up a 2000x2000 display. The large resolution custom wallpaper should
// be loaded.
UpdateDisplay("800x600,2000x2000");
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
}
class WallpaperManagerBrowserTestNoAnimation
@@ -351,7 +359,6 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
PRE_UseMigratedWallpaperInfo) {
// New user log in, a default wallpaper is loaded.
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
// Old wallpaper migration code doesn't exist in codebase anymore. Modify user
// wallpaper info directly to simulate the wallpaper migration. See
// crosbug.com/38429 for details about why we modify wallpaper info this way.
@@ -371,7 +378,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
UseMigratedWallpaperInfo) {
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
// This test should finish normally. If timeout, it is probably because
// migrated wallpaper is somehow not loaded. Bad things can happen if
// wallpaper is not loaded at login screen. One example is: crosbug.com/38429.
@@ -383,7 +390,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
PRE_UsePreMigrationWallpaperInfo) {
// New user log in, a default wallpaper is loaded.
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
// Old wallpaper migration code doesn't exist in codebase anymore. So if
// user's profile is not migrated, it is the same as no wallpaper info. To
// simulate this, we remove user's wallpaper info here.
@@ -393,7 +400,7 @@ IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestNoAnimation,
UsePreMigrationWallpaperInfo) {
LogIn(kTestUser1, kTestUser1Hash);
- WaitAsyncWallpaperLoad();
+ WaitAsyncWallpaperLoadFinished();
// This test should finish normally. If timeout, it is probably because chrome
// can not handle pre migrated user profile (M21 profile or older).
}
@@ -414,6 +421,7 @@ class WallpaperManagerBrowserTestCrashRestore
IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
PRE_RestoreWallpaper) {
LogIn(kTestUser1, kTestUser1Hash);
+ WaitAsyncWallpaperLoadFinished();
}
// Test for crbug.com/270278. It simulates a browser crash and verifies if user
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
index 8f3391b..bedc829 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
@@ -82,6 +82,10 @@ class WallpaperManagerTest : public test::AshTestBase {
WallpaperManager::Get()->set_command_line_for_testing(&command_line_);
}
+ void WaitAsyncWallpaperLoad() {
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
protected:
CommandLine command_line_;
@@ -123,6 +127,7 @@ TEST_F(WallpaperManagerTest, GuestUserUseGuestWallpaper) {
EXPECT_TRUE(test_api->current_wallpaper_path().empty());
UserManager::Get()->UserLoggedIn(UserManager::kGuestUserName,
UserManager::kGuestUserName, false);
+ WaitAsyncWallpaperLoad();
EXPECT_FALSE(ash::Shell::GetInstance()->desktop_background_controller()->
SetDefaultWallpaper(true));
}
diff --git a/chrome/browser/chromeos/login/webui_login_display.cc b/chrome/browser/chromeos/login/webui_login_display.cc
index 94b7a20..6cb1ffb 100644
--- a/chrome/browser/chromeos/login/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/webui_login_display.cc
@@ -287,11 +287,11 @@ void WebUILoginDisplay::MigrateUserData(const std::string& old_password) {
}
void WebUILoginDisplay::LoadWallpaper(const std::string& username) {
- WallpaperManager::Get()->SetUserWallpaper(username);
+ WallpaperManager::Get()->SetUserWallpaperDelayed(username);
}
void WebUILoginDisplay::LoadSigninWallpaper() {
- WallpaperManager::Get()->SetDefaultWallpaper();
+ WallpaperManager::Get()->SetDefaultWallpaperDelayed();
}
void WebUILoginDisplay::OnSigninScreenReady() {
diff --git a/chrome/browser/resources/chromeos/login/screen_account_picker.js b/chrome/browser/resources/chromeos/login/screen_account_picker.js
index caf4cce..49cad85 100644
--- a/chrome/browser/resources/chromeos/login/screen_account_picker.js
+++ b/chrome/browser/resources/chromeos/login/screen_account_picker.js
@@ -27,7 +27,6 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
'forceOnlineSignin',
'setCapsLockState',
'forceLockedUserPodFocus',
- 'onWallpaperLoaded',
'removeUser',
'showBannerMessage',
'showUserPodButton',
@@ -224,13 +223,6 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
},
/**
- * Mark wallpaper loaded
- */
- onWallpaperLoaded: function(username) {
- $('pod-row').onWallpaperLoaded(username);
- },
-
- /**
* Remove given user from pod row if it is there.
* @param {string} user name.
*/
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index 5e95d81..460c121 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-<include src="wallpaper_loader.js"></include>
-
/**
* @fileoverview User pod row implementation.
*/
@@ -1010,9 +1008,6 @@ cr.define('login', function() {
// Pod that was most recently focused, if any.
lastFocusedPod_: undefined,
- // Note: created only in decorate() !
- wallpaperLoader_: undefined,
-
// Pods whose initial images haven't been loaded yet.
podsWithPendingImages_: [],
@@ -1026,7 +1021,6 @@ cr.define('login', function() {
mousemove: [this.handleMouseMove_.bind(this), false],
keydown: [this.handleKeyDown.bind(this), false]
};
- this.wallpaperLoader_ = new login.WallpaperLoader();
},
/**
@@ -1357,7 +1351,6 @@ cr.define('login', function() {
}
this.insideFocusPod_ = true;
- this.wallpaperLoader_.reset();
for (var i = 0, pod; pod = this.pods[i]; ++i) {
if (!this.isSinglePod) {
pod.isActionBoxMenuActive = false;
@@ -1380,9 +1373,8 @@ cr.define('login', function() {
podToFocus.classList.remove('faded');
podToFocus.classList.add('focused');
podToFocus.reset(true); // Reset and give focus.
+ // focusPod() automatically loads wallpaper
chrome.send('focusPod', [podToFocus.user.username]);
-
- this.wallpaperLoader_.scheduleLoad(podToFocus.user.username, opt_force);
this.firstShown_ = false;
this.lastFocusedPod_ = podToFocus;
}
@@ -1406,16 +1398,7 @@ cr.define('login', function() {
*/
loadLastWallpaper: function() {
if (this.lastFocusedPod_)
- this.wallpaperLoader_.scheduleLoad(this.lastFocusedPod_.user.username,
- true /* force */);
- },
-
- /**
- * Handles 'onWallpaperLoaded' event. Recalculates statistics and
- * [re]schedules next wallpaper load.
- */
- onWallpaperLoaded: function(username) {
- this.wallpaperLoader_.onWallpaperLoaded(username);
+ chrome.send('loadWallpaper', [this.lastFocusedPod_.user.username]);
},
/**
@@ -1685,8 +1668,7 @@ cr.define('login', function() {
focusedPod.reset(true);
// Notify screen that it is ready.
screen.onShow();
- self.wallpaperLoader_.scheduleLoad(focusedPod.user.username,
- true /* force */);
+ chrome.send('loadWallpaper', [focusedPod.user.username]);
}
});
// Guard timer for 1 second -- it would conver all possible animations.
diff --git a/chrome/browser/resources/chromeos/login/wallpaper_loader.js b/chrome/browser/resources/chromeos/login/wallpaper_loader.js
deleted file mode 100644
index 4903bf5..0000000
--- a/chrome/browser/resources/chromeos/login/wallpaper_loader.js
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2013 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.
-
-cr.define('login', function() {
-
- /**
- * Minimum wallpaper load delay in milliseconds.
- * @type {number}
- * @const
- */
- var WALLPAPER_LOAD_MIN_DELAY_MS = 100;
-
- /**
- * If last walpaper load time cannot be calculated, assume this value.
- * @type {number}
- * @const
- */
- var WALLPAPER_DEFAULT_LOAD_TIME_MS = 200;
-
- /**
- * Min and Max average wallpaper load time.
- * Delay to next wallpaper load is 2 * <average load time>.
- * @type {number}
- * @const
- */
- var WALLPAPER_MIN_LOAD_TIME_MS = 50;
- var WALLPAPER_MAX_LOAD_TIME_MS = 2000;
-
- /**
- * Number last wallpaper load times to remember.
- * @type {number}
- * @const
- */
- var WALLPAPER_LOAD_STATS_MAX_LENGTH = 4;
-
-
- /**
- * Creates a new pod row element.
- * @constructor
- * @extends {HTMLDivElement}
- */
- var WallpaperLoader = function() {
- this.wallpaperLoadInProgress_ = {
- name: '',
- date: undefined
- };
- this.loadStats_ = [];
- };
-
- WallpaperLoader.prototype = {
- // When moving through users quickly at login screen, set a timeout to
- // prevent loading intermediate wallpapers.
- beforeLoadTimeout_: null,
-
- // If we do not receive notification on WallpaperLoaded within timeout,
- // probably an error happened and the wallpaper is just bad. Skip it
- // and unblock loader.
- loadTimeout_: null,
-
- // When waiting for wallpaper load, remember load start time.
- // wallpaperLoadInProgress_: { name: '', date: undefined }
- wallpaperLoadInProgress_: undefined,
-
- // Wait a delay and then load this wallpaper. Value = username.
- wallpaperLoadPending_: undefined,
-
- // Wait untill this Date before loading next wallpaper.
- wallpaperLoadTryNextAfter_: undefined,
-
- // Username, owner of current wallpaper.
- currentWallpaper_: '',
-
- // Array of times (in milliseconds) of last wallpaper load attempts.
- // Length is limited by WALLPAPER_LOAD_STATS_MAX_LENGTH.
- loadStats_: undefined,
-
- // Force next load request even if requested wallpaper is already loaded.
- forceLoad_: false,
-
- /**
- * Stop load timer. Clear pending record.
- */
- reset: function() {
- delete this.wallpaperLoadPending_;
-
- if (this.beforeLoadTimeout_ != null)
- window.clearTimeout(this.beforeLoadTimeout_);
- this.beforeLoadTimeout_ = null;
-
- if (this.loadTimeout_ != null)
- window.clearTimeout(this.loadTimeout_);
- this.loadTimeout_ = null;
-
- this.wallpaperLoadInProgress_.name = '';
- },
-
- /**
- * Schedules wallpaper load.
- */
- scheduleLoad: function(email, force) {
- if (force || this.forceLoad_) {
- this.forceLoad_ = true;
- } else {
- if (this.wallpaperLoadPending_ && this.wallpaperLoadPending_ == email)
- return;
- if ((this.wallpaperLoadInProgress_.name == '') &&
- (this.currentWallpaper_ == email))
- return;
- }
- this.reset();
-
- this.wallpaperLoadPending_ = email;
- var now = new Date();
- var timeout = WALLPAPER_LOAD_MIN_DELAY_MS;
- if (this.wallpaperLoadTryNextAfter_)
- timeout = Math.max(timeout, this.wallpaperLoadTryNextAfter_ - now);
-
- this.beforeLoadTimeout_ = window.setTimeout(
- this.loadWallpaper_.bind(this), timeout);
- },
-
-
- /**
- * Loads pending wallpaper, if any.
- * @private
- */
- loadWallpaper_: function() {
- this.beforeLoadTimeout_ = null;
- if (!this.wallpaperLoadPending_)
- return;
- if (!this.forceLoad_ && this.wallpaperLoadInProgress_.name != '')
- return;
- var email = this.wallpaperLoadPending_;
- delete this.wallpaperLoadPending_;
- if (!this.forceLoad_ && email == this.currentWallpaper_)
- return;
- this.wallpaperLoadInProgress_.name = email;
- this.wallpaperLoadInProgress_.date = new Date();
- this.forceLoad_ = false;
- chrome.send('loadWallpaper', [email]);
-
- var timeout = 3 * this.getWallpaperLoadTime_();
- this.loadTimeout_ = window.setTimeout(
- this.loadTimeoutFired_.bind(this), timeout);
- },
-
- /**
- * Calculates average wallpaper load time.
- */
- calcLoadStatsAvg: function() {
- return this.loadStats_.reduce(
- function(previousValue, currentValue) {
- return previousValue + currentValue;
- }) / this.loadStats_.length;
- },
-
- /**
- * Calculates average next wallpaper load delay time.
- */
- getWallpaperLoadTime_: function() {
- var avg = WALLPAPER_DEFAULT_LOAD_TIME_MS;
-
- if (this.loadStats_.length == 0)
- return avg;
-
- avg = this.calcLoadStatsAvg();
- if (avg < WALLPAPER_MIN_LOAD_TIME_MS)
- avg = WALLPAPER_MIN_LOAD_TIME_MS;
-
- if (avg > WALLPAPER_MAX_LOAD_TIME_MS)
- avg = WALLPAPER_MAX_LOAD_TIME_MS;
-
- return avg;
- },
-
- /**
- * Handles 'onWallpaperLoaded' event. Recalculates statistics and
- * [re]schedules next wallpaper load.
- */
- onWallpaperLoaded: function(email) {
- this.currentWallpaper_ = email;
- if (email != this.wallpaperLoadInProgress_.name)
- return;
-
- window.clearTimeout(this.loadTimeout_);
- this.loadTimeout_ = null;
-
- this.wallpaperLoadInProgress_.name = '';
- var started = this.wallpaperLoadInProgress_.date;
- var finished = new Date();
- var elapsed = started ? finished - started :
- WALLPAPER_DEFAULT_LOAD_TIME_MS;
- this.loadStats_.push(elapsed);
- if (this.loadStats_.length > WALLPAPER_LOAD_STATS_MAX_LENGTH)
- this.loadStats_.shift();
-
- this.wallpaperLoadTryNextAfter_ = new Date(Date.now() + 2 *
- this.getWallpaperLoadTime_());
- if (this.wallpaperLoadPending_) {
- var newWallpaperEmail = this.wallpaperLoadPending_;
- this.reset();
- this.scheduleLoad(newWallpaperEmail, this.forceLoad_);
- }
- },
-
- /**
- * Handles timeout of wallpaper load. Pretends load is completed to unblock
- * loader.
- */
- loadTimeoutFired_: function() {
- var email = this.wallpaperLoadInProgress_.name;
- this.loadTimeout_ = null;
- if (email == '')
- return;
- this.onWallpaperLoaded(email);
- }
- };
-
- return {
- WallpaperLoader: WallpaperLoader
- };
-});
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 93132d9..824c74f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -277,7 +277,7 @@ void ChromeLauncherControllerUserSwitchObserverChromeOS::ActiveUserChanged(
// TODO(skuhne): At the moment the login screen does the wallpaper management
// and wallpapers are not synchronized across multiple desktops.
if (chromeos::WallpaperManager::Get())
- chromeos::WallpaperManager::Get()->SetUserWallpaper(user_email);
+ chromeos::WallpaperManager::Get()->SetUserWallpaperDelayed(user_email);
}
void ChromeLauncherControllerUserSwitchObserverChromeOS::UserAddedToSession(
diff --git a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
index fc13c12..c9c4963 100644
--- a/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/locally_managed_user_creation_screen_handler.cc
@@ -259,7 +259,7 @@ void LocallyManagedUserCreationScreenHandler::HandleManagerSelected(
const std::string& manager_id) {
if (!delegate_)
return;
- WallpaperManager::Get()->SetUserWallpaper(manager_id);
+ WallpaperManager::Get()->SetUserWallpaperNow(manager_id);
}
void LocallyManagedUserCreationScreenHandler::HandleImportUserSelected(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 420ea9d..61b42d9 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -31,6 +31,7 @@
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/net/network_portal_detector.h"
@@ -296,12 +297,9 @@ SigninScreenHandler::SigninScreenHandler(
registrar_.Add(this,
chrome::NOTIFICATION_AUTH_CANCELLED,
content::NotificationService::AllSources());
-
- WallpaperManager::Get()->AddObserver(this);
}
SigninScreenHandler::~SigninScreenHandler() {
- WallpaperManager::Get()->RemoveObserver(this);
weak_factory_.InvalidateWeakPtrs();
SystemKeyEventListener* key_event_listener =
SystemKeyEventListener::GetInstance();
@@ -1098,11 +1096,6 @@ void SigninScreenHandler::HandleLoadWallpaper(const std::string& email) {
delegate_->LoadWallpaper(email);
}
-void SigninScreenHandler::OnWallpaperAnimationFinished(
- const std::string& email) {
- CallJS("login.AccountPickerScreen.onWallpaperLoaded", email);
-}
-
void SigninScreenHandler::HandleRebootSystem() {
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
}
@@ -1440,6 +1433,7 @@ void SigninScreenHandler::HandleUpdateOfflineLogin(bool offline_login_active) {
void SigninScreenHandler::HandleFocusPod(const std::string& user_id) {
SetUserInputMethod(user_id);
+ WallpaperManager::Get()->SetUserWallpaperDelayed(user_id);
}
void SigninScreenHandler::HandleCustomButtonClicked(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index 4e0c576..727a82b 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -19,7 +19,6 @@
#include "chrome/browser/chromeos/login/login_display.h"
#include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/chromeos/net/network_portal_detector.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/system_key_event_listener.h"
@@ -201,8 +200,7 @@ class SigninScreenHandler
public LoginDisplayWebUIHandler,
public SystemKeyEventListener::CapsLockObserver,
public content::NotificationObserver,
- public NetworkStateInformer::NetworkStateInformerObserver,
- public WallpaperManager::Observer {
+ public NetworkStateInformer::NetworkStateInformerObserver {
public:
SigninScreenHandler(
const scoped_refptr<NetworkStateInformer>& network_state_informer,
@@ -235,9 +233,6 @@ class SigninScreenHandler
kiosk_enable_flow_aborted_callback_for_test_ = callback;
}
- // From WallpaperManager::Observer
- virtual void OnWallpaperAnimationFinished(const std::string& email) OVERRIDE;
-
private:
enum UIState {
UI_STATE_UNKNOWN = 0,