Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(851)

Unified Diff: chrome/browser/chromeos/login/wallpaper_manager.cc

Issue 10832019: Speed up custom wallpaper switching time and wallpaper manager code refactor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/login/wallpaper_manager.cc
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index c4be12938a6da3683fa966bfd9449187da84ac82..03632e6d6b5d08da01399852cea7f53e05e04ecf 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -5,9 +5,13 @@
#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "ash/desktop_background/desktop_background_controller.h"
-#include "ash/desktop_background/desktop_background_resources.h"
#include "ash/shell.h"
+#include "base/command_line.h"
#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
@@ -15,12 +19,43 @@
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/user_manager_impl.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager_client.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/zlib/zlib.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/skia_util.h"
+
+using content::BrowserThread;
namespace {
+
const int kWallpaperUpdateIntervalSec = 24 * 60 * 60;
+
+const char kWallpaperTypeNodeName[] = "type";
+const char kWallpaperIndexNodeName[] = "index";
+const char kWallpaperDateNodeName[] = "date";
+
+const int kThumbnailWidth = 128;
+const int kThumbnailHeight = 80;
+
+// Default wallpaper index used in OOBE (first boot).
+// Defined here because Chromium default index differs.
+// Also see ash::WallpaperInfo kDefaultWallpapers in
+// desktop_background_resources.cc
+#if defined(GOOGLE_CHROME_BUILD)
+const int kDefaultOOBEWallpaperIndex = 16; // IDR_AURA_WALLPAPERS_3_URBAN0
+#else
+const int kDefaultOOBEWallpaperIndex = 0; // IDR_AURA_WALLPAPERS_ROMAINGUY_0
+#endif
+
} // namespace
namespace chromeos {
@@ -36,9 +71,18 @@ WallpaperManager* WallpaperManager::Get() {
return g_wallpaper_manager;
}
-WallpaperManager::WallpaperManager() : last_selected_user_("") {
+WallpaperManager::WallpaperManager()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(wallpaper_loader_(new WallpaperLoader)),
+ current_user_wallpaper_type_(User::UNKNOWN),
+ ALLOW_THIS_IN_INITIALIZER_LIST(current_user_wallpaper_index_(
+ ash::GetInvalidWallpaperIndex())),
+ last_selected_user_(""),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
system::TimezoneSettings::GetInstance()->AddObserver(this);
RestartTimer();
+ registrar_.Add(this,
+ chrome::NOTIFICATION_LOGIN_USER_CHANGED,
+ content::NotificationService::AllSources());
}
void WallpaperManager::AddPowerManagerClientObserver() {
@@ -46,6 +90,120 @@ void WallpaperManager::AddPowerManagerClientObserver() {
DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
}
+void WallpaperManager::CacheIfCustomWallpaper(const std::string& email) {
+ User::WallpaperType type;
+ int index;
+ base::Time date;
+ GetUserWallpaperProperties(email, &type, &index, &date);
+ if (type == User::CUSTOMIZED) {
+ // Uses WeakPtr here to make the request cancelable.
+ LoadedCallback loaded_cb = base::Bind(&WallpaperManager::CacheCallback,
Ivan Korotkov 2012/07/27 23:02:02 Here and below: there is no point in storing a cal
bshe 2012/07/31 14:27:54 Done.
+ weak_factory_.GetWeakPtr(), email);
+ LoadCustomWallpaperFromFile(email, loaded_cb);
+ }
+}
+
+void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() {
+ User::WallpaperType type;
+ int index;
+ base::Time last_modification_date;
+ GetLoggedInUserWallpaperProperties(&type, &index, &last_modification_date);
+
+ if (type != current_user_wallpaper_type_ ||
+ index != current_user_wallpaper_index_) {
+ UserSelected(UserManager::Get()->GetLoggedInUser().email());
Ivan Korotkov 2012/07/27 23:02:02 Please don't make manual call of event handlers (l
bshe 2012/07/31 14:27:54 Done.
+ }
+}
+
+void WallpaperManager::FetchCustomWallpaper(const std::string& email) {
+ User::WallpaperType type;
+ int index;
+ base::Time date;
+ GetUserWallpaperProperties(email, &type, &index, &date);
+ ash::WallpaperLayout layout = static_cast<ash::WallpaperLayout>(index);
+ LoadedCallback loaded_cb = base::Bind(&WallpaperManager::FetchCallback,
+ base::Unretained(this), email, layout);
+ LoadCustomWallpaperFromFile(email, loaded_cb);
+}
+
+bool WallpaperManager::GetCustomWallpaperFromCache(const std::string& email,
+ SkBitmap* wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ CustomWallpaperMap::iterator it = custom_wallpaper_cache_.find(email);
Ivan Korotkov 2012/07/27 23:02:02 Here and below: const_iterator
bshe 2012/07/31 14:27:54 Done.
+ if (it != custom_wallpaper_cache_.end()) {
+ *wallpaper = (*it).second;
+ return true;
+ } else {
Ivan Korotkov 2012/07/27 23:02:02 Chrome's style is "no else after return"
bshe 2012/07/31 14:27:54 Done.
+ return false;
+ }
+}
+
+SkBitmap WallpaperManager::GetCustomWallpaperThumbnail(
+ const std::string& email) {
+ CustomWallpaperMap::iterator it =
+ custom_wallpaper_thumbnail_cache_.find(email);
+ if (it != custom_wallpaper_cache_.end())
+ return (*it).second;
+ else
+ return SkBitmap();
+}
+
+void WallpaperManager::GetLoggedInUserWallpaperProperties(
+ User::WallpaperType* type,
+ int* index,
+ base::Time* last_modification_date) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (UserManager::Get()->IsLoggedInAsStub()) {
+ *type = current_user_wallpaper_type_ = User::DEFAULT;
+ *index = current_user_wallpaper_index_ = ash::GetInvalidWallpaperIndex();
+ return;
+ }
+
+ GetUserWallpaperProperties(UserManager::Get()->GetLoggedInUser().email(),
+ type, index, last_modification_date);
+}
+
+void WallpaperManager::InitializeWallpaper() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ UserManager* user_manager = UserManager::Get();
+ if (!user_manager->IsUserLoggedIn()) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableNewOobe)) {
+ if (!WizardController::IsDeviceRegistered() &&
+ !WizardController::IsZeroDelayEnabled()) {
+ // TODO(nkostylev): Add switch to disable wallpaper transition on OOBE.
+ // Should be used on test images so that they are not slowed down.
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetDefaultWallpaper(kDefaultOOBEWallpaperIndex);
+ } else {
+ bool show_users = true;
+ bool result = CrosSettings::Get()->GetBoolean(
+ kAccountsPrefShowUserNamesOnSignIn, &show_users);
+ DCHECK(result) << "Unable to fetch setting "
+ << kAccountsPrefShowUserNamesOnSignIn;
+ if (!show_users) {
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetDefaultWallpaper(ash::GetSolidColorIndex());
+ }
+ }
+ }
+ return;
+ }
+ UserSelected(user_manager->GetLoggedInUser().email());
Ivan Korotkov 2012/07/27 23:02:02 Same note about calling event handler.
bshe 2012/07/31 14:27:54 Done.
+}
+
+void WallpaperManager::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) {
+ // Cancel callback for previous cache requests.
+ weak_factory_.InvalidateWeakPtrs();
+ custom_wallpaper_cache_.clear();
+ }
+}
+
void WallpaperManager::RestartTimer() {
timer_.Stop();
base::Time midnight = base::Time::Now().LocalMidnight();
@@ -62,6 +220,76 @@ void WallpaperManager::RestartTimer() {
}
}
+void WallpaperManager::SaveUserWallpaperProperties(const std::string& email,
+ User::WallpaperType type,
+ int index) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ current_user_wallpaper_type_ = type;
+ current_user_wallpaper_index_ = index;
+ // Ephemeral users can not save data to local state. We just cache the index
+ // in memory for them.
+ if (UserManager::Get()->IsCurrentUserEphemeral()) {
+ return;
+ }
+
+ PrefService* local_state = g_browser_process->local_state();
+ DictionaryPrefUpdate wallpaper_update(local_state,
+ UserManager::kUserWallpapersProperties);
+
+ base::DictionaryValue* wallpaper_properties = new base::DictionaryValue();
+ wallpaper_properties->Set(kWallpaperTypeNodeName,
+ new base::FundamentalValue(type));
+ wallpaper_properties->Set(kWallpaperIndexNodeName,
+ new base::FundamentalValue(index));
+ wallpaper_properties->SetString(kWallpaperDateNodeName,
+ base::Int64ToString(base::Time::Now().LocalMidnight().ToInternalValue()));
+ wallpaper_update->SetWithoutPathExpansion(email, wallpaper_properties);
+}
+
+void WallpaperManager::SetUserWallpaperFromFile(
+ const std::string& username,
+ const FilePath& path,
+ ash::WallpaperLayout layout,
+ base::WeakPtr<WallpaperDelegate> delegate) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // TODO(bshe): Refactor GetWallpaperPathForUser to this class.
+ std::string wallpaper_path =
+ static_cast<UserManagerImpl*>(UserManager::Get())->
+ GetWallpaperPathForUser(username, false).value();
+ // need to expose ephemeral user.
+ bool save_raw_file = true;
+
+ // For wallpapers, save the image without resizing.
+ wallpaper_loader_->Start(
+ path.value(), save_raw_file, wallpaper_path,
+ base::Bind(&WallpaperManager::SetCallback,
+ base::Unretained(this), username, layout, User::CUSTOMIZED,
+ delegate));
+}
+
+void WallpaperManager::SetInitialUserWallpaper(const std::string& username) {
+ current_user_wallpaper_type_ = User::DEFAULT;
+ // TODO(bshe): Ideally, wallpaper should start to load as soon as user click
+ // "Add user".
+ if (username == kGuestUser)
+ current_user_wallpaper_index_ = ash::GetGuestWallpaperIndex();
+ else
+ current_user_wallpaper_index_ = ash::GetDefaultWallpaperIndex();
+ SaveUserWallpaperProperties(username,
+ current_user_wallpaper_type_,
+ current_user_wallpaper_index_);
+
+ // Some browser tests do not have shell instance. And it is not necessary to
+ // create a wallpaper for these tests. Add HasInstance check to prevent tests
+ // crash and speed up the tests by avoid loading wallpaper.
+ if (ash::Shell::HasInstance()) {
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetDefaultWallpaper(current_user_wallpaper_index_);
+ }
+}
+
void WallpaperManager::SetLastSelectedUser(
const std::string& last_selected_user) {
last_selected_user_ = last_selected_user;
@@ -75,6 +303,35 @@ void WallpaperManager::UserDeselected() {
}
}
+void WallpaperManager::UserSelected(const std::string& email) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (UserManager::Get()->IsKnownUser(email)) {
+ User::WallpaperType type;
+ int index;
+ base::Time date;
+ GetUserWallpaperProperties(email, &type, &index, &date);
+ if (type == User::DAILY && date != base::Time::Now().LocalMidnight()) {
+ index = ash::GetNextWallpaperIndex(index);
+ SaveUserWallpaperProperties(email, User::DAILY, index);
+ } else if (type == User::CUSTOMIZED) {
+ SkBitmap custom_wallpaper;
+ if (GetCustomWallpaperFromCache(email, &custom_wallpaper)) {
+ // In customized mode, we use index pref to save the user selected
+ // wallpaper layout. See function SaveWallpaperToLocalState().
+ ash::WallpaperLayout layout = static_cast<ash::WallpaperLayout>(index);
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetCustomWallpaper(custom_wallpaper, layout);
+ } else {
+ FetchCustomWallpaper(email);
+ }
+ return;
+ }
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetDefaultWallpaper(index);
+ SetLastSelectedUser(email);
+ }
+}
+
// WallpaperManager, private: --------------------------------------------------
WallpaperManager::~WallpaperManager() {
@@ -96,32 +353,175 @@ void WallpaperManager::BatchUpdateWallpaper() {
for (UserList::const_iterator it = users.begin();
it != users.end(); ++it) {
std::string email = (*it)->email();
- // TODO(bshe): Move GetUserWallpaperProperties() to this class.
- static_cast<UserManagerImpl*>(user_manager)->
- GetUserWallpaperProperties(email, &type, &index,
- &last_modification_date);
+ GetUserWallpaperProperties(email, &type, &index, &last_modification_date);
base::Time current_date = base::Time::Now().LocalMidnight();
if (type == User::DAILY && current_date != last_modification_date) {
index = ash::GetNextWallpaperIndex(index);
- // TODO(bshe): Move SaveUserWallpaperProperties() to this class.
- static_cast<UserManagerImpl*>(user_manager)->
- SaveUserWallpaperProperties(email, type, index);
+ SaveUserWallpaperProperties(email, type, index);
}
// Force a wallpaper update for logged in / last selected user.
// TODO(bshe): Notify lock screen, wallpaper picker UI to update wallpaper
// as well.
if (user_manager->IsUserLoggedIn() &&
email == user_manager->GetLoggedInUser().email()) {
- user_manager->UserSelected(email);
+ UserSelected(email);
} else if (show_users &&
email == last_selected_user_) {
- user_manager->UserSelected(email);
+ UserSelected(email);
}
}
}
RestartTimer();
}
+void WallpaperManager::CacheCallback(const std::string& email,
+ const SkBitmap& wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (custom_wallpaper_cache_.find(email) != custom_wallpaper_cache_.end()) {
+ LOG(ERROR) << "Try to cache a wallpaper for the same user twice.";
Ivan Korotkov 2012/07/27 23:02:02 No need in braces
Ivan Korotkov 2012/07/27 23:02:02 "Attemped to cache wallpaper for the same user twi
Ivan Korotkov 2012/07/27 23:02:02 If this can happen only due to incorrect programmi
bshe 2012/07/31 14:27:54 Done. Using a DCHECK instead. On 2012/07/27 23:02
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&WallpaperManager::CacheThumbnail,
+ base::Unretained(this), email, wallpaper));
+
+ custom_wallpaper_cache_.insert(std::make_pair(email, wallpaper));
+}
+
+void WallpaperManager::CacheThumbnail(const std::string& email,
+ const SkBitmap& wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ SkBitmap thumbnail =
+ skia::ImageOperations::Resize(wallpaper,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ kThumbnailWidth, kThumbnailHeight);
+ CustomWallpaperMap::iterator it =
Ivan Korotkov 2012/07/27 23:02:02 Just custom_wallpaper_thumbnail_cache_[email] = th
bshe 2012/07/31 14:27:54 Done.
+ custom_wallpaper_thumbnail_cache_.find(email);
+ if (it != custom_wallpaper_thumbnail_cache_.end())
+ it->second = thumbnail;
+ else
+ custom_wallpaper_thumbnail_cache_.insert(std::make_pair(email, thumbnail));
+}
+
+void WallpaperManager::FetchCallback(const std::string& email,
+ ash::WallpaperLayout layout,
+ const SkBitmap& wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&WallpaperManager::CacheThumbnail,
+ base::Unretained(this), email, wallpaper));
+
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetCustomWallpaper(wallpaper, layout);
+}
+
+void WallpaperManager::GetUserWallpaperProperties(const std::string& email,
+ User::WallpaperType* type,
+ int* index,
+ base::Time* last_modification_date) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Default to the values cached in memory.
+ *type = current_user_wallpaper_type_;
+ *index = current_user_wallpaper_index_;
+
+ // Override with values found in local store, if any.
+ if (!email.empty()) {
+ const DictionaryValue* user_wallpapers = g_browser_process->local_state()->
+ GetDictionary(UserManager::kUserWallpapersProperties);
+ base::DictionaryValue* wallpaper_properties;
+ if (user_wallpapers->GetDictionaryWithoutPathExpansion(
+ email,
+ &wallpaper_properties)) {
+ *type = User::UNKNOWN;
+ *index = ash::GetInvalidWallpaperIndex();
+ wallpaper_properties->GetInteger(kWallpaperTypeNodeName,
+ reinterpret_cast<int*>(type));
+ wallpaper_properties->GetInteger(kWallpaperIndexNodeName, index);
+ std::string date_string;
+ int64 val;
+ if (!(wallpaper_properties->GetString(kWallpaperDateNodeName,
+ &date_string) &&
+ base::StringToInt64(date_string, &val)))
+ val = 0;
+ *last_modification_date = base::Time::FromInternalValue(val);
+ }
+ }
+}
+
+void WallpaperManager::GenerateUserWallpaperThumbnail(
+ const std::string& email,
+ User::WallpaperType type,
+ base::WeakPtr<WallpaperDelegate> delegate,
+ const SkBitmap& wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ SkBitmap thumbnail =
+ skia::ImageOperations::Resize(wallpaper,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ kThumbnailWidth, kThumbnailHeight);
+
+ CustomWallpaperMap::iterator it =
Ivan Korotkov 2012/07/27 23:02:02 ditto
bshe 2012/07/31 14:27:54 Done.
+ custom_wallpaper_thumbnail_cache_.find(email);
+ if (it != custom_wallpaper_thumbnail_cache_.end())
+ it->second = thumbnail;
+ else
+ custom_wallpaper_thumbnail_cache_.insert(std::make_pair(email, thumbnail));
+
+ // Notify thumbnail is ready.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&WallpaperManager::OnThumbnailUpdated,
+ base::Unretained(this), delegate));
+}
+
+void WallpaperManager::LoadCustomWallpaperFromFile(const std::string& email,
+ const LoadedCallback& loaded_cb) {
+ // TODO(bshe): Refactor GetWallpaperPathForUser to this class.
Ivan Korotkov 2012/07/27 23:02:02 Time to do it maybe? :) Or put it into UserManager
bshe 2012/07/31 14:27:54 Done.
+ std::string wallpaper_path =
+ static_cast<UserManagerImpl*>(UserManager::Get())->
+ GetWallpaperPathForUser(email, false).value();
+ // Load user wallpaper asynchronously.
+ wallpaper_loader_->Start(wallpaper_path, false, std::string(),
+ base::Bind(loaded_cb));
Ivan Korotkov 2012/07/27 23:02:02 Should be no need in empty Bind
bshe 2012/07/31 14:27:54 Done.
+}
+
+void WallpaperManager::OnThumbnailUpdated(
+ base::WeakPtr<WallpaperDelegate> delegate) {
+ if (delegate)
+ delegate->SetCustomWallpaperThumbnail();
+}
+
+void WallpaperManager::SetCallback(const std::string& username,
+ ash::WallpaperLayout layout,
+ User::WallpaperType type,
+ base::WeakPtr<WallpaperDelegate> delegate,
+ const SkBitmap& wallpaper) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&WallpaperManager::GenerateUserWallpaperThumbnail,
+ base::Unretained(this), username, type, delegate, wallpaper));
+
+ ash::Shell::GetInstance()->desktop_background_controller()->
+ SetCustomWallpaper(wallpaper, layout);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&WallpaperManager::SaveUserWallpaperProperties,
+ base::Unretained(this),
+ username, type, layout));
+}
+
void WallpaperManager::SystemResumed() {
BatchUpdateWallpaper();
}

Powered by Google App Engine
This is Rietveld 408576698