From 2f5b48321398324f5a17e1a735099dca3d95024e Mon Sep 17 00:00:00 2001 From: "bshe@chromium.org" Date: Tue, 15 May 2012 21:41:37 +0000 Subject: [PATCH] Implement user selected wallpaper feature. BUG=123612, 122791 TEST=Verify if custom wallpaper is supported Review URL: https://chromiumcodereview.appspot.com/10375010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137258 0039d316-1c4b-4281-b951-d872f2087c98 --- .../desktop_background_controller.cc | 19 +- .../desktop_background_controller.h | 31 +-- .../desktop_background_resources.h | 4 +- .../desktop_background_view.cc | 16 +- .../desktop_background_view.h | 5 +- ash/shell_factory.h | 3 +- chrome/app/generated_resources.grd | 12 + .../chromeos/login/mock_user_manager.h | 6 + chrome/browser/chromeos/login/user.cc | 4 + chrome/browser/chromeos/login/user.h | 7 + chrome/browser/chromeos/login/user_manager.h | 25 +- .../chromeos/login/user_manager_impl.cc | 218 ++++++++++++++++-- .../chromeos/login/user_manager_impl.h | 54 +++++ .../chromeos/set_wallpaper_options.html | 5 +- .../chromeos/set_wallpaper_options.js | 127 +++++++++- .../set_wallpaper_options_handler2.cc | 115 ++++++++- .../chromeos/set_wallpaper_options_handler2.h | 38 ++- .../chromeos/wallpaper_thumbnail_source2.cc | 27 ++- 18 files changed, 655 insertions(+), 61 deletions(-) diff --git a/ash/desktop_background/desktop_background_controller.cc b/ash/desktop_background/desktop_background_controller.cc index f95c32e9391c..5b2562e39f8f 100644 --- a/ash/desktop_background/desktop_background_controller.cc +++ b/ash/desktop_background/desktop_background_controller.cc @@ -41,10 +41,8 @@ class DesktopBackgroundController::WallpaperOperation void LoadingWallpaper() { if (cancel_flag_.IsSet()) return; - wallpaper_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed( GetWallpaperInfo(index_).id).ToSkBitmap(); - if (cancel_flag_.IsSet()) return; layout_ = GetWallpaperInfo(index_).layout; @@ -58,7 +56,7 @@ class DesktopBackgroundController::WallpaperOperation return wallpaper_; } - ImageLayout image_layout() { + WallpaperLayout wallpaper_layout() { return layout_; } @@ -69,12 +67,11 @@ class DesktopBackgroundController::WallpaperOperation private: friend class base::RefCountedThreadSafe< DesktopBackgroundController::WallpaperOperation>; - ~WallpaperOperation(){}; base::CancellationFlag cancel_flag_; const SkBitmap* wallpaper_; - ImageLayout layout_; + WallpaperLayout layout_; int index_; DISALLOW_COPY_AND_ASSIGN(WallpaperOperation); @@ -93,6 +90,7 @@ DesktopBackgroundController::~DesktopBackgroundController() { void DesktopBackgroundController::SetDefaultWallpaper(int index) { if (previous_index_ == index) return; + CancelPendingWallpaperOperation(); wallpaper_op_ = new WallpaperOperation(index); @@ -105,6 +103,15 @@ void DesktopBackgroundController::SetDefaultWallpaper(int index) { true /* task_is_slow */); } +void DesktopBackgroundController::SetCustomWallpaper(const SkBitmap& wallpaper, + WallpaperLayout layout) { + internal::RootWindowLayoutManager* root_window_layout = + Shell::GetInstance()->root_window_layout(); + root_window_layout->SetBackgroundLayer(NULL); + internal::CreateDesktopBackground(wallpaper, layout); + desktop_background_mode_ = BACKGROUND_IMAGE; +} + void DesktopBackgroundController::CancelPendingWallpaperOperation() { // Set canceled flag of previous request to skip unneeded loading. if (wallpaper_op_.get()) @@ -148,7 +155,7 @@ void DesktopBackgroundController::SetDesktopBackgroundImageMode( Shell::GetInstance()->root_window_layout(); root_window_layout->SetBackgroundLayer(NULL); if(wo->wallpaper()) { - internal::CreateDesktopBackground(*wo->wallpaper(), wo->image_layout()); + internal::CreateDesktopBackground(*wo->wallpaper(), wo->wallpaper_layout()); desktop_background_mode_ = BACKGROUND_IMAGE; } } diff --git a/ash/desktop_background/desktop_background_controller.h b/ash/desktop_background/desktop_background_controller.h index b31a21464120..a531001f57bc 100644 --- a/ash/desktop_background/desktop_background_controller.h +++ b/ash/desktop_background/desktop_background_controller.h @@ -22,7 +22,7 @@ class UserWallpaperDelegate { // Gets the index of user selected wallpaper. virtual const int GetUserWallpaperIndex() = 0; - // Open the set wallpaper page in the browser. + // Opens the set wallpaper page in the browser. virtual void OpenSetWallpaperPage() = 0; // Returns true if user can open set wallpaper page. Only guest user returns @@ -30,8 +30,8 @@ class UserWallpaperDelegate { virtual bool CanOpenSetWallpaperPage() = 0; }; -// A class to listen for login and desktop background change events and set the -// corresponding default wallpaper in Aura shell. +// Loads selected desktop wallpaper from file system asynchronously and updates +// background layer if loaded successfully. class ASH_EXPORT DesktopBackgroundController { public: enum BackgroundMode { @@ -42,39 +42,44 @@ class ASH_EXPORT DesktopBackgroundController { DesktopBackgroundController(); virtual ~DesktopBackgroundController(); - // Get the desktop background mode. + // Gets the desktop background mode. BackgroundMode desktop_background_mode() const { return desktop_background_mode_; } - // Load default wallpaper at |index| asynchronously and set to current + // Loads default wallpaper at |index| asynchronously and sets to current // wallpaper after loaded. void SetDefaultWallpaper(int index); - // Cancel the current wallpaper loading operation. + // Sets the user selected custom wallpaper. Called when user selected a file + // from file system or changed the layout of wallpaper. + void SetCustomWallpaper(const SkBitmap& wallpaper, WallpaperLayout layout); + + // Cancels the current wallpaper loading operation. void CancelPendingWallpaperOperation(); - // Load logged in user wallpaper asynchronously and set to current wallpaper + // Loads logged in user wallpaper asynchronously and sets to current wallpaper // after loaded. void SetLoggedInUserWallpaper(); - // Sets the desktop background to solid color mode and create a solid color + // Sets the desktop background to solid color mode and creates a solid color // layout. void SetDesktopBackgroundSolidColorMode(); private: - // An operation to asynchronously load wallpaper. + // An operation to asynchronously loads wallpaper. class WallpaperOperation; - // Sets the desktop background to image mode and create a new background - // widget with user selected wallpaper or default wallpaper. Delete the old + // Sets the desktop background to image mode and creates a new background + // widget with user selected wallpaper or default wallpaper. Deletes the old // widget if any. void SetDesktopBackgroundImageMode(scoped_refptr wo); - // Default wallpapper loaded, set the background mode to image mode. + // Creates a new background widget and sets the background mode to image mode. + // Called after wallpaper loaded successfully. void OnWallpaperLoadCompleted(scoped_refptr wo); - // Create an empty wallpaper. Some tests require a wallpaper widget is ready + // Creates an empty wallpaper. Some tests require a wallpaper widget is ready // when running. However, the wallpaper widgets are now created asynchronously // . If loading a real wallpaper, there are cases that these tests crash // because the required widget is not ready. This function synchronously diff --git a/ash/desktop_background/desktop_background_resources.h b/ash/desktop_background/desktop_background_resources.h index 19f23d079496..4b48e9dcb952 100644 --- a/ash/desktop_background/desktop_background_resources.h +++ b/ash/desktop_background/desktop_background_resources.h @@ -11,7 +11,7 @@ class SkBitmap; namespace ash { -enum ImageLayout { +enum WallpaperLayout { CENTER, CENTER_CROPPED, STRETCH, @@ -21,7 +21,7 @@ enum ImageLayout { struct ASH_EXPORT WallpaperInfo { int id; int thumb_id; - ImageLayout layout; + WallpaperLayout layout; // TODO(bshe): author member should be encoded to UTF16. We need to use i18n // string for this member after M19. const char* author; diff --git a/ash/desktop_background/desktop_background_view.cc b/ash/desktop_background/desktop_background_view.cc index 80e3ce059109..c1c08d8235f8 100644 --- a/ash/desktop_background/desktop_background_view.cc +++ b/ash/desktop_background/desktop_background_view.cc @@ -61,9 +61,9 @@ static int RoundPositive(double x) { // DesktopBackgroundView, public: DesktopBackgroundView::DesktopBackgroundView(const SkBitmap& wallpaper, - ImageLayout layout) { + WallpaperLayout wallpaper_layout) { wallpaper_ = wallpaper; - image_layout_ = layout; + wallpaper_layout_ = wallpaper_layout; wallpaper_.buildMipMap(false); } @@ -80,7 +80,7 @@ void DesktopBackgroundView::OnPaint(gfx::Canvas* canvas) { // streching to avoid upsampling artifacts (Note that we could tile too, but // decided not to do this at the moment). gfx::Rect wallpaper_rect(0, 0, wallpaper_.width(), wallpaper_.height()); - if (image_layout_ == ash::CENTER_CROPPED && wallpaper_.width() > width() + if (wallpaper_layout_ == ash::CENTER_CROPPED && wallpaper_.width() > width() && wallpaper_.height() > height()) { // The dimension with the smallest ratio must be cropped, the other one // is preserved. Both are set in gfx::Size cropped_size. @@ -105,9 +105,9 @@ void DesktopBackgroundView::OnPaint(gfx::Canvas* canvas) { wallpaper_cropped_rect.width(), wallpaper_cropped_rect.height(), 0, 0, width(), height(), true); - } else if (image_layout_ == ash::TILE) { + } else if (wallpaper_layout_ == ash::TILE) { canvas->TileImageInt(wallpaper_, 0, 0, width(), height()); - } else if (image_layout_ == ash::STRETCH) { + } else if (wallpaper_layout_ == ash::STRETCH) { // This is generally not recommended as it may show artifacts. canvas->DrawBitmapInt(wallpaper_, 0, 0, wallpaper_.width(), wallpaper_.height(), 0, 0, width(), height(), true); @@ -127,11 +127,13 @@ void DesktopBackgroundView::OnMouseReleased(const views::MouseEvent& event) { Shell::GetInstance()->ShowBackgroundMenu(GetWidget(), event.location()); } -void CreateDesktopBackground(const SkBitmap& wallpaper, ImageLayout layout) { +void CreateDesktopBackground(const SkBitmap& wallpaper, + WallpaperLayout wallpaper_layout) { views::Widget* desktop_widget = new views::Widget; views::Widget::InitParams params( views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - DesktopBackgroundView* view = new DesktopBackgroundView(wallpaper, layout); + DesktopBackgroundView* view = new DesktopBackgroundView(wallpaper, + wallpaper_layout); params.delegate = view; params.parent = Shell::GetInstance()->GetContainer( diff --git a/ash/desktop_background/desktop_background_view.h b/ash/desktop_background/desktop_background_view.h index 3effb1f382c9..4a5b67694247 100644 --- a/ash/desktop_background/desktop_background_view.h +++ b/ash/desktop_background/desktop_background_view.h @@ -16,7 +16,8 @@ namespace internal { class DesktopBackgroundView : public views::WidgetDelegateView { public: - DesktopBackgroundView(const SkBitmap& wallpaper, ImageLayout layout); + DesktopBackgroundView(const SkBitmap& wallpaper, + WallpaperLayout wallpaper_layout); virtual ~DesktopBackgroundView(); private: @@ -26,7 +27,7 @@ class DesktopBackgroundView : public views::WidgetDelegateView { virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE; SkBitmap wallpaper_; - ImageLayout image_layout_; + WallpaperLayout wallpaper_layout_; DISALLOW_COPY_AND_ASSIGN(DesktopBackgroundView); }; diff --git a/ash/shell_factory.h b/ash/shell_factory.h index 03b8170b7ea2..c1ebf51eb055 100644 --- a/ash/shell_factory.h +++ b/ash/shell_factory.h @@ -21,7 +21,8 @@ class Widget; namespace ash { namespace internal { -void CreateDesktopBackground(const SkBitmap& wallpaper, ImageLayout layout); +void CreateDesktopBackground(const SkBitmap& wallpaper, + WallpaperLayout wallpaper_layout); ASH_EXPORT views::Widget* CreateStatusArea(views::View* contents); } // namespace internal diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 974becfc6c33..ceca612f839f 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -13333,6 +13333,18 @@ Press any key to continue exploring. I'm feeling lucky + + Center + + + Center Cropped + + + Stretch + + + Custom... + Change picture... diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h index a1dc5305f4d3..c99475d7a82e 100644 --- a/chrome/browser/chromeos/login/mock_user_manager.h +++ b/chrome/browser/chromeos/login/mock_user_manager.h @@ -42,8 +42,14 @@ class MockUserManager : public UserManager { MOCK_CONST_METHOD1(GetUserDisplayEmail, std::string(const std::string&)); MOCK_METHOD2(SaveUserDefaultImageIndex, void(const std::string&, int)); MOCK_METHOD2(SaveUserImage, void(const std::string&, const SkBitmap&)); + MOCK_METHOD1(SetLoggedInUserCustomWallpaperLayout,void( + ash::WallpaperLayout)); MOCK_METHOD2(SaveUserImageFromFile, void(const std::string&, const FilePath&)); + MOCK_METHOD4(SaveUserWallpaperFromFile, void(const std::string&, + const FilePath&, + ash::WallpaperLayout, + WallpaperDelegate*)); MOCK_METHOD1(SaveUserImageFromProfileImage, void(const std::string&)); MOCK_METHOD1(DownloadProfileImage, void(const std::string&)); MOCK_CONST_METHOD0(IsCurrentUserOwner, bool(void)); diff --git a/chrome/browser/chromeos/login/user.cc b/chrome/browser/chromeos/login/user.cc index 833dcc18a3b8..80d10e278842 100644 --- a/chrome/browser/chromeos/login/user.cc +++ b/chrome/browser/chromeos/login/user.cc @@ -61,6 +61,10 @@ void User::SetStubImage(int image_index) { image_is_stub_ = true; } +void User::SetWallpaperThumbnail(const SkBitmap& wallpaper_thumbnail) { + wallpaper_thumbnail_ = wallpaper_thumbnail; +} + std::string User::GetAccountName() const { return GetUserName(email_); } diff --git a/chrome/browser/chromeos/login/user.h b/chrome/browser/chromeos/login/user.h index 5115d8d2dae0..24a926b6b8aa 100644 --- a/chrome/browser/chromeos/login/user.h +++ b/chrome/browser/chromeos/login/user.h @@ -65,6 +65,9 @@ class User { const SkBitmap& image() const { return image_; } int image_index() const { return image_index_; } + // The thumbnail of user custom wallpaper. + const SkBitmap& wallpaper_thumbnail() const { return wallpaper_thumbnail_; } + // True if user image is a stub (while real image is being loaded from file). bool image_is_stub() const { return image_is_stub_; } @@ -92,6 +95,9 @@ class User { // one of |kExternalImageIndex| or |kProfileImageIndex|. void SetStubImage(int image_index); + // Set thumbnail of user custom wallpaper. + void SetWallpaperThumbnail(const SkBitmap& wallpaper_thumbnail); + void set_oauth_token_status(OAuthTokenStatus status) { oauth_token_status_ = status; } @@ -105,6 +111,7 @@ class User { std::string display_email_; SkBitmap image_; OAuthTokenStatus oauth_token_status_; + SkBitmap wallpaper_thumbnail_; // Either index of a default image for the user, |kExternalImageIndex| or // |kProfileImageIndex|. diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h index 7d710defa494..e50431747893 100644 --- a/chrome/browser/chromeos/login/user_manager.h +++ b/chrome/browser/chromeos/login/user_manager.h @@ -11,6 +11,7 @@ #include "ash/desktop_background/desktop_background_resources.h" #include "base/memory/singleton.h" #include "chrome/browser/chromeos/login/user.h" +#include "chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h" class SkBitmap; class FilePath; @@ -140,7 +141,7 @@ class UserManager { const std::string& username, User::OAuthTokenStatus oauth_token_status) = 0; - // Save user's displayed (non-canonical) email in local state preferences. + // Saves user's displayed (non-canonical) email in local state preferences. // Ignored If there is no such user. virtual void SaveUserDisplayEmail(const std::string& username, const std::string& display_email) = 0; @@ -152,16 +153,16 @@ class UserManager { const std::string& username) const = 0; // Returns the index of the default wallpapers saved in local state for login - // user if it is known (was previousely set by |SaveWallpaperToLocalState| + // user if it is known (was previously set by |SaveWallpaperToLocalState| // call). Otherwise, returns the default wallpaper index. virtual int GetLoggedInUserWallpaperIndex() = 0; - // Set |type| and |index| to the value saved in local state for logged in + // Sets |type| and |index| to the value saved in local state for logged in // user. virtual void GetLoggedInUserWallpaperProperties(User::WallpaperType* type, int* index) = 0; - // Save |type| and |index| chose by logged in user to Local State. + // Saves |type| and |index| chose by logged in user to Local State. virtual void SaveLoggedInUserWallpaperProperties(User::WallpaperType type, int index) = 0; @@ -175,22 +176,34 @@ class UserManager { virtual void SaveUserImage(const std::string& username, const SkBitmap& image) = 0; + // Updates custom wallpaper to selected layout and saves layout to Local + // State. + virtual void SetLoggedInUserCustomWallpaperLayout( + ash::WallpaperLayout layout) = 0; + // Tries to load user image from disk; if successful, sets it for the user, // sends LOGIN_USER_IMAGE_CHANGED notification and updates Local State. virtual void SaveUserImageFromFile(const std::string& username, const FilePath& path) = 0; + // Tries to load user image from disk; if successful, sets it for the user, + // and updates Local State. + virtual void SaveUserWallpaperFromFile(const std::string& username, + const FilePath& path, + ash::WallpaperLayout layout, + WallpaperDelegate* delegate) = 0; + // Sets profile image as user image for |username|, sends // LOGIN_USER_IMAGE_CHANGED notification and updates Local State. If the user // is not logged-in or the last |DownloadProfileImage| call has failed, a // default grey avatar will be used until the user logs in and profile image - // is downloaded successfuly. + // is downloaded successfully. virtual void SaveUserImageFromProfileImage(const std::string& username) = 0; // Starts downloading the profile image for the logged-in user. // If user's image index is |kProfileImageIndex|, newly downloaded image // is immediately set as user's current picture. - // |reason| is an arbitraty string (used to report UMA histograms with + // |reason| is an arbitrary string (used to report UMA histograms with // download times). virtual void DownloadProfileImage(const std::string& reason) = 0; diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc index 9375ca12b5db..a0d4ba2eef6c 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.cc +++ b/chrome/browser/chromeos/login/user_manager_impl.cc @@ -50,6 +50,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/common/url_constants.h" +#include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/codec/png_codec.h" @@ -75,6 +76,9 @@ const char kImageIndexNodeName[] = "index"; const char kWallpaperTypeNodeName[] = "type"; const char kWallpaperIndexNodeName[] = "index"; +const int kThumbnailWidth = 128; +const int kThumbnailHeight = 80; + // Index of the default image used for the |kStubUser| user. const int kStubDefaultImageIndex = 0; @@ -361,6 +365,18 @@ void UserManagerImpl::UserSelected(const std::string& email) { // RANDOM wallpaper. index = ash::GetRandomWallpaperIndex(); SaveUserWallpaperProperties(email, User::RANDOM, index); + } else if (type == User::CUSTOMIZED) { + std::string wallpaper_path = + GetWallpaperPathForUser(email, false).value(); + // In customized mode, we use index pref to save the user selected + // wallpaper layout. See function SaveWallpaperToLocalState(). + ash::WallpaperLayout layout = static_cast(index); + // Load user image asynchronously. + image_loader_->Start( + wallpaper_path, 0, + base::Bind(&UserManagerImpl::LoadCustomWallpaperThumbnail, + base::Unretained(this), email, layout)); + return; } ash::Shell::GetInstance()->desktop_background_controller()-> SetDefaultWallpaper(index); @@ -510,6 +526,23 @@ void UserManagerImpl::SaveUserImage(const std::string& username, SaveUserImageInternal(username, User::kExternalImageIndex, image); } +void UserManagerImpl::SetLoggedInUserCustomWallpaperLayout( + ash::WallpaperLayout layout) { + // TODO(bshe): We current disabled the customized wallpaper feature for + // Ephemeral user. As we dont want to keep a copy of customized wallpaper in + // memory. Need a smarter way to solve this. + if (IsCurrentUserEphemeral()) + return; + const chromeos::User& user = GetLoggedInUser(); + std::string username = user.email(); + DCHECK(!username.empty()); + + std::string file_path = GetWallpaperPathForUser(username, false).value(); + SaveWallpaperToLocalState(username, file_path, layout, User::CUSTOMIZED); + // Load wallpaper from file. + UserSelected(username); +} + void UserManagerImpl::SaveUserImageFromFile(const std::string& username, const FilePath& path) { image_loader_->Start( @@ -518,6 +551,18 @@ void UserManagerImpl::SaveUserImageFromFile(const std::string& username, base::Unretained(this), username)); } +void UserManagerImpl::SaveUserWallpaperFromFile(const std::string& username, + const FilePath& path, + ash::WallpaperLayout layout, + WallpaperDelegate* delegate) { + // For wallpapers, save the image without resizing. + image_loader_->Start( + path.value(), 0 /* Original size */, + base::Bind(&UserManagerImpl::SaveUserWallpaperInternal, + base::Unretained(this), username, layout, User::CUSTOMIZED, + delegate)); +} + void UserManagerImpl::SaveUserImageFromProfileImage( const std::string& username) { if (!downloaded_profile_image_.empty()) { @@ -655,6 +700,15 @@ FilePath UserManagerImpl::GetImagePathForUser(const std::string& username) { return user_data_dir.AppendASCII(filename); } +FilePath UserManagerImpl::GetWallpaperPathForUser(const std::string& username, + bool is_thumbnail) { + std::string filename = username + + (is_thumbnail ? "_wallpaper_thumb.png" : "_wallpaper.png"); + FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + return user_data_dir.AppendASCII(filename); +} + void UserManagerImpl::EnsureUsersLoaded() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!users_.empty()) @@ -842,7 +896,6 @@ void UserManagerImpl::SetInitialUserWallpaper(const std::string& username) { current_user_wallpaper_index_ = ash::GetGuestWallpaperIndex(); else current_user_wallpaper_index_ = ash::GetDefaultWallpaperIndex(); - SaveUserWallpaperProperties(username, current_user_wallpaper_type_, current_user_wallpaper_index_); @@ -1014,24 +1067,99 @@ void UserManagerImpl::SaveUserImageInternal(const std::string& username, username, image, image_path, image_index)); } -void UserManagerImpl::SaveImageToFile(const std::string& username, - const SkBitmap& image, - const FilePath& image_path, - int image_index) { +void UserManagerImpl::SaveUserWallpaperInternal(const std::string& username, + ash::WallpaperLayout layout, + User::WallpaperType type, + WallpaperDelegate* delegate, + const SkBitmap& wallpaper) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&UserManagerImpl::GenerateUserWallpaperThumbnail, + base::Unretained(this), username, type, delegate, wallpaper)); + + ash::Shell::GetInstance()->desktop_background_controller()-> + SetCustomWallpaper(wallpaper, layout); + + // Ignore for ephemeral users. + if (IsEphemeralUser(username)) + return; + + FilePath wallpaper_path = GetWallpaperPathForUser(username, false); + DVLOG(1) << "Saving user image to " << wallpaper_path.value(); + + last_image_set_async_ = true; + + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&UserManagerImpl::SaveWallpaperToFile, + base::Unretained(this), username, wallpaper, wallpaper_path, + layout, User::CUSTOMIZED)); +} + +void UserManagerImpl::LoadCustomWallpaperThumbnail(const std::string& email, + ash::WallpaperLayout layout, + const SkBitmap& wallpaper) { + ash::Shell::GetInstance()->desktop_background_controller()-> + SetCustomWallpaper(wallpaper, layout); + // Load wallpaper thumbnail + std::string wallpaper_path = GetWallpaperPathForUser(email, true).value(); + image_loader_->Start( + wallpaper_path, 0, + base::Bind(&UserManagerImpl::OnCustomWallpaperThumbnailLoaded, + base::Unretained(this), email)); +} + +void UserManagerImpl::OnCustomWallpaperThumbnailLoaded( + const std::string& email, + const SkBitmap& wallpaper) { + User* user = const_cast(FindUser(email)); + // User may have been removed by now. + if (user && !wallpaper.empty()) + user->SetWallpaperThumbnail(wallpaper); +} + +void UserManagerImpl::OnThumbnailUpdated(WallpaperDelegate* delegate) { + if (delegate) + delegate->SetCustomWallpaperThumbnail(); +} + +void UserManagerImpl::GenerateUserWallpaperThumbnail( + const std::string& username, + User::WallpaperType type, + WallpaperDelegate* delegate, + const SkBitmap& wallpaper) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + SkBitmap thumbnail = + skia::ImageOperations::Resize(wallpaper, + skia::ImageOperations::RESIZE_LANCZOS3, + kThumbnailWidth, kThumbnailHeight); + logged_in_user_->SetWallpaperThumbnail(thumbnail); - std::vector encoded_image; - if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &encoded_image)) { - LOG(ERROR) << "Failed to PNG encode the image."; + // Notify thumbnail is ready. + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&UserManagerImpl::OnThumbnailUpdated, + base::Unretained(this), delegate)); + + // Ignore for ephemeral users. + if (IsEphemeralUser(username)) return; - } - if (file_util::WriteFile(image_path, - reinterpret_cast(&encoded_image[0]), - encoded_image.size()) == -1) { - LOG(ERROR) << "Failed to save image to file."; + FilePath thumbnail_path = GetWallpaperPathForUser(username, true); + SaveBitmapToFile(thumbnail, thumbnail_path); +} + +void UserManagerImpl::SaveImageToFile(const std::string& username, + const SkBitmap& image, + const FilePath& image_path, + int image_index) { + if (!SaveBitmapToFile(image, image_path)) return; - } BrowserThread::PostTask( BrowserThread::UI, @@ -1041,6 +1169,24 @@ void UserManagerImpl::SaveImageToFile(const std::string& username, username, image_path.value(), image_index, true)); } +void UserManagerImpl::SaveWallpaperToFile(const std::string& username, + const SkBitmap& wallpaper, + const FilePath& wallpaper_path, + ash::WallpaperLayout layout, + User::WallpaperType type) { + // TODO(bshe): We should save the original file unchanged instead of + // re-encoding it and saving it. + if (!SaveBitmapToFile(wallpaper, wallpaper_path)) + return; + + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&UserManagerImpl::SaveWallpaperToLocalState, + base::Unretained(this), + username, wallpaper_path.value(), layout, type)); +} + void UserManagerImpl::SaveImageToLocalState(const std::string& username, const std::string& image_path, int image_index, @@ -1074,6 +1220,33 @@ void UserManagerImpl::SaveImageToLocalState(const std::string& username, NotifyLocalStateChanged(); } +void UserManagerImpl::SaveWallpaperToLocalState(const std::string& username, + const std::string& wallpaper_path, + ash::WallpaperLayout layout, + User::WallpaperType type) { + // TODO(bshe): We probably need to save wallpaper_path instead of index. + SaveUserWallpaperProperties(username, type, layout); +} + +bool UserManagerImpl::SaveBitmapToFile(const SkBitmap& image, + const FilePath& image_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + std::vector encoded_image; + if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &encoded_image)) { + LOG(ERROR) << "Failed to PNG encode the image."; + return false; + } + + if (file_util::WriteFile(image_path, + reinterpret_cast(&encoded_image[0]), + encoded_image.size()) == -1) { + LOG(ERROR) << "Failed to save image to file."; + return false; + } + return true; +} + void UserManagerImpl::InitDownloadedProfileImage() { DCHECK(logged_in_user_); if (downloaded_profile_image_.empty() && !logged_in_user_->image_is_stub()) { @@ -1220,6 +1393,23 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) { kUserWallpapersProperties); prefs_wallpapers_update->RemoveWithoutPathExpansion(email, NULL); + // Remove user wallpaper thumbnail + FilePath wallpaper_thumb_path = GetWallpaperPathForUser(email, true); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&UserManagerImpl::DeleteUserImage, + base::Unretained(this), + wallpaper_thumb_path)); + // Remove user wallpaper + FilePath wallpaper_path = GetWallpaperPathForUser(email, false); + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&UserManagerImpl::DeleteUserImage, + base::Unretained(this), + wallpaper_path)); + DictionaryPrefUpdate prefs_images_update(prefs, kUserImages); std::string image_path_string; prefs_images_update->GetStringWithoutPathExpansion(email, &image_path_string); diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h index aa1c7289c5cb..581f4e450e64 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.h +++ b/chrome/browser/chromeos/login/user_manager_impl.h @@ -74,8 +74,14 @@ class UserManagerImpl : public UserManager, int image_index) OVERRIDE; virtual void SaveUserImage(const std::string& username, const SkBitmap& image) OVERRIDE; + virtual void SetLoggedInUserCustomWallpaperLayout( + ash::WallpaperLayout layout) OVERRIDE; virtual void SaveUserImageFromFile(const std::string& username, const FilePath& path) OVERRIDE; + virtual void SaveUserWallpaperFromFile(const std::string& username, + const FilePath& path, + ash::WallpaperLayout layout, + WallpaperDelegate* delegate) OVERRIDE; virtual void SaveUserImageFromProfileImage( const std::string& username) OVERRIDE; virtual void DownloadProfileImage(const std::string& reason) OVERRIDE; @@ -106,6 +112,10 @@ class UserManagerImpl : public UserManager, // Returns image filepath for the given user. FilePath GetImagePathForUser(const std::string& username); + // Returns wallpaper/thumbnail filepath for the given user. + FilePath GetWallpaperPathForUser(const std::string& username, + bool is_thumbnail); + private: friend class UserManagerImplWrapper; friend class UserManagerTest; @@ -177,6 +187,32 @@ class UserManagerImpl : public UserManager, int image_index, const SkBitmap& image); + // Saves wallpaper to file, post task to generate thumbnail and updates local + // state preferences. + void SaveUserWallpaperInternal(const std::string& username, + ash::WallpaperLayout layout, + User::WallpaperType type, + WallpaperDelegate* delegate, + const SkBitmap& image); + + // Loads custom wallpaper thumbnail asynchronously. + void LoadCustomWallpaperThumbnail(const std::string& email, + ash::WallpaperLayout layout, + const SkBitmap& wallpaper); + + // Caches the loaded wallpaper for the given user. + void OnCustomWallpaperThumbnailLoaded(const std::string& email, + const SkBitmap& wallpaper); + + // Updates the custom wallpaper thumbnail in wallpaper picker UI. + void OnThumbnailUpdated(WallpaperDelegate* delegate); + + // Generates a 128x80 thumbnail and saves it to local file system. + void GenerateUserWallpaperThumbnail(const std::string& username, + User::WallpaperType type, + WallpaperDelegate* delegate, + const SkBitmap& wallpaper); + // Saves image to file with specified path and sends LOGIN_USER_IMAGE_CHANGED // notification. Runs on FILE thread. Posts task for saving image info to // Local State on UI thread. @@ -185,6 +221,14 @@ class UserManagerImpl : public UserManager, const FilePath& image_path, int image_index); + // Saves wallpaper to file with specified path. Runs on FILE thread. Posts + // task for saving wallpaper info to Local State on UI thread. + void SaveWallpaperToFile(const std::string& username, + const SkBitmap& wallpaper, + const FilePath& wallpaper_path, + ash::WallpaperLayout layout, + User::WallpaperType type); + // Stores path to the image and its index in local state. Runs on UI thread. // If |is_async| is true, it has been posted from the FILE thread after // saving the image. @@ -193,6 +237,16 @@ class UserManagerImpl : public UserManager, int image_index, bool is_async); + // Stores layout and type preference in local state. Runs on UI thread. + void SaveWallpaperToLocalState(const std::string& username, + const std::string& wallpaper_path, + ash::WallpaperLayout layout, + User::WallpaperType type); + + // Saves |image| to the specified |image_path|. Runs on FILE thread. + bool SaveBitmapToFile(const SkBitmap& image, + const FilePath& image_path); + // Initializes |downloaded_profile_picture_| with the picture of the logged-in // user. void InitDownloadedProfileImage(); diff --git a/chrome/browser/resources/options2/chromeos/set_wallpaper_options.html b/chrome/browser/resources/options2/chromeos/set_wallpaper_options.html index d4a435b44d7d..2148a96f2213 100644 --- a/chrome/browser/resources/options2/chromeos/set_wallpaper_options.html +++ b/chrome/browser/resources/options2/chromeos/set_wallpaper_options.html @@ -9,7 +9,7 @@

- +
@@ -23,6 +23,9 @@

+ +
diff --git a/chrome/browser/resources/options2/chromeos/set_wallpaper_options.js b/chrome/browser/resources/options2/chromeos/set_wallpaper_options.js index 2896fd250b4d..84a68bf4ae3b 100644 --- a/chrome/browser/resources/options2/chromeos/set_wallpaper_options.js +++ b/chrome/browser/resources/options2/chromeos/set_wallpaper_options.js @@ -7,6 +7,8 @@ cr.define('options', function() { var OptionsPage = options.OptionsPage; var UserImagesGrid = options.UserImagesGrid; + /** @const */ var CUSTOM_WALLPAPER_PREFIX = 'chrome://wallpaper/custom_'; + ///////////////////////////////////////////////////////////////////////////// // SetWallpaperOptions class: @@ -45,6 +47,9 @@ cr.define('options', function() { wallpaperGrid.addEventListener('activate', function() { OptionsPage.closeOverlay() }); + $('set-wallpaper-layout').addEventListener('change', + this.handleLayoutChange_); + $('set-custom-wallpaper').onclick = this.handleChooseFile_; $('use-random-wallpaper').onclick = this.handleCheckboxClick_.bind(this); $('set-wallpaper-overlay-confirm').onclick = function() { OptionsPage.closeOverlay(); @@ -53,6 +58,9 @@ cr.define('options', function() { // @type {Array.} this.wallpapers_ = []; + // @type {Object} Old user custom wallpaper thumbnail. + this.oldImage_ = null; + chrome.send('onSetWallpaperPageInitialized'); }, @@ -75,6 +83,11 @@ cr.define('options', function() { willHidePage: function() { var wallpaperGrid = $('wallpaper-grid'); wallpaperGrid.blur(); + if (this.oldImage_) { + wallpaperGrid.removeItem(this.oldImage_); + this.oldImage_ = null; + } + $('set-wallpaper-layout').innerText = ''; }, /** @@ -94,6 +107,44 @@ cr.define('options', function() { $('author-website').textContent = ''; }, + /** + * Populates the drop down box for custom wallpaper layouts. + * param {string} layouts Available wallpaper layouts. + * param {number} selectedLayout The value of selected/default layout. + * @private + */ + populateWallpaperLayouts_: function(layouts, selectedLayout) { + var wallpaperLayout = $('set-wallpaper-layout'); + var selectedIndex = -1; + for (var i = 0; i < layouts.length; i++) { + var option = new Option(layouts[i]['name'], layouts[i]['index']); + if (selectedLayout == option.value) + selectedIndex = i; + wallpaperLayout.appendChild(option); + } + if (selectedIndex >= 0) + wallpaperLayout.selectedIndex = selectedIndex; + }, + + /** + * Handles "Custom..." button activation. + * @private + */ + handleChooseFile_: function() { + chrome.send('chooseWallpaper'); + }, + + /** + * Handle the wallpaper layout setting change. + * @private + */ + handleLayoutChange_: function() { + var setWallpaperLayout = $('set-wallpaper-layout'); + var layout = setWallpaperLayout.options[ + setWallpaperLayout.selectedIndex].value; + chrome.send('changeWallpaperLayout', [layout]); + }, + /** * Handles image selection change. * @private @@ -103,8 +154,17 @@ cr.define('options', function() { var url = wallpaperGrid.selectedItemUrl; if (url && !wallpaperGrid.inProgramSelection) { + if (url.indexOf(CUSTOM_WALLPAPER_PREFIX) == 0) { + // User custom wallpaper is selected + this.isCustom = true; + // When users select the custom wallpaper thumbnail from picker UI, + // use the saved layout value and redraw the wallpaper. + this.handleLayoutChange_(); + } else { + this.isCustom = false; + chrome.send('selectDefaultWallpaper', [url]); + } this.setWallpaperAttribution_(url); - chrome.send('selectDefaultWallpaper', [url]); } }, @@ -129,8 +189,10 @@ cr.define('options', function() { var wallpaperGrid = $('wallpaper-grid'); if ($('use-random-wallpaper').checked) { wallpaperGrid.disabled = true; + $('attribution-label').hidden = false; chrome.send('selectRandomWallpaper'); wallpaperGrid.classList.add('grayout'); + $('set-wallpaper-layout').hidden = true; } else { wallpaperGrid.disabled = false; wallpaperGrid.classList.remove('grayout'); @@ -178,12 +240,73 @@ cr.define('options', function() { } }, + /** + * Display layout drop down box and disable random mode if enabled. Called + * when user select a valid file from file system. + */ + didSelectFile_: function() { + $('set-wallpaper-layout').hidden = false; + var wallpaperGrid = $('wallpaper-grid'); + if ($('use-random-wallpaper').checked) { + $('use-random-wallpaper').checked = false; + wallpaperGrid.disabled = false; + wallpaperGrid.classList.remove('grayout'); + } + }, + + /** + * Returns url of current user's custom wallpaper thumbnail. + * @private + */ + currentWallpaperImageUrl_: function() { + return CUSTOM_WALLPAPER_PREFIX + BrowserOptions.getLoggedInUsername() + + '?id=' + (new Date()).getTime(); + }, + + /** + * Updates the visibility of attribution-label and set-wallpaper-layout. + * @param {boolean} isCustom True if users select custom wallpaper. + */ + set isCustom(isCustom) { + if (isCustom) { + // Clear attributions for custom wallpaper. + $('attribution-label').hidden = true; + // Enable the layout drop down box when custom wallpaper is selected. + $('set-wallpaper-layout').hidden = false; + } else { + $('attribution-label').hidden = false; + $('set-wallpaper-layout').hidden = true; + } + }, + + /** + * Adds or updates custom user wallpaper thumbnail from file. + * @private + */ + setCustomImage_: function() { + var wallpaperGrid = $('wallpaper-grid'); + var url = this.currentWallpaperImageUrl_(); + if (this.oldImage_) { + this.oldImage_ = wallpaperGrid.updateItem(this.oldImage_, url); + } else { + // Insert to the end of wallpaper list. + var pos = wallpaperGrid.length; + this.oldImage_ = wallpaperGrid.addItem(url, undefined, undefined, pos); + } + + this.isCustom = true; + this.setWallpaperAttribution_(''); + wallpaperGrid.selectedItem = this.oldImage_; + }, }; // Forward public APIs to private implementations. [ 'setDefaultImages', - 'setSelectedImage' + 'setSelectedImage', + 'populateWallpaperLayouts', + 'didSelectFile', + 'setCustomImage' ].forEach(function(name) { SetWallpaperOptions[name] = function() { var instance = SetWallpaperOptions.getInstance(); diff --git a/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.cc b/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.cc index d71105f44a26..e2dc781b8329 100644 --- a/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.cc +++ b/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.cc @@ -5,7 +5,6 @@ #include "chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h" #include "ash/desktop_background/desktop_background_controller.h" -#include "ash/desktop_background/desktop_background_resources.h" #include "ash/shell.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -19,8 +18,8 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/webui/options2/chromeos/wallpaper_thumbnail_source2.h" -#include "chrome/common/chrome_notification_types.h" -#include "content/public/browser/notification_service.h" +#include "chrome/browser/ui/webui/web_ui_util.h" +#include "chrome/common/chrome_paths.h" #include "content/public/browser/web_ui.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" @@ -30,11 +29,30 @@ namespace chromeos { namespace options2 { +namespace { + +// Returns info about extensions for files we support as wallpaper images. +SelectFileDialog::FileTypeInfo GetUserImageFileTypeInfo() { + SelectFileDialog::FileTypeInfo file_type_info; + file_type_info.extensions.resize(3); + + file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("jpg")); + file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("jpeg")); + + file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("png")); + + return file_type_info; +} + +} // namespace + SetWallpaperOptionsHandler::SetWallpaperOptionsHandler() : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { } SetWallpaperOptionsHandler::~SetWallpaperOptionsHandler() { + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); } void SetWallpaperOptionsHandler::GetLocalizedValues( @@ -48,6 +66,8 @@ void SetWallpaperOptionsHandler::GetLocalizedValues( l10n_util::GetStringUTF16(IDS_OPTIONS_SET_WALLPAPER_AUTHOR_TEXT)); localized_strings->SetString("randomCheckbox", l10n_util::GetStringUTF16(IDS_OPTIONS_SET_WALLPAPER_RANDOM)); + localized_strings->SetString("customWallpaper", + l10n_util::GetStringUTF16(IDS_OPTIONS_CUSTOME_WALLPAPER)); } void SetWallpaperOptionsHandler::RegisterMessages() { @@ -63,6 +83,27 @@ void SetWallpaperOptionsHandler::RegisterMessages() { web_ui()->RegisterMessageCallback("selectRandomWallpaper", base::Bind(&SetWallpaperOptionsHandler::HandleRandomWallpaper, base::Unretained(this))); + web_ui()->RegisterMessageCallback("chooseWallpaper", + base::Bind(&SetWallpaperOptionsHandler::HandleChooseFile, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("changeWallpaperLayout", + base::Bind(&SetWallpaperOptionsHandler::HandleLayoutChanged, + base::Unretained(this))); +} + +void SetWallpaperOptionsHandler::SetCustomWallpaperThumbnail() { + web_ui()->CallJavascriptFunction("SetWallpaperOptions.setCustomImage"); +} + +void SetWallpaperOptionsHandler::FileSelected(const FilePath& path, + int index, + void* params) { + UserManager* user_manager = UserManager::Get(); + + // Default wallpaper layout is CENTER_CROPPED. + user_manager->SaveUserWallpaperFromFile( + user_manager->GetLoggedInUser().email(), path, ash::CENTER_CROPPED, this); + web_ui()->CallJavascriptFunction("SetWallpaperOptions.didSelectFile"); } void SetWallpaperOptionsHandler::SendDefaultImages() { @@ -82,6 +123,31 @@ void SetWallpaperOptionsHandler::SendDefaultImages() { images); } +void SetWallpaperOptionsHandler::SendLayoutOptions( + ash::WallpaperLayout layout) { + ListValue layouts; + DictionaryValue* entry; + + layouts.Append(entry = new DictionaryValue()); + entry->SetString("name", + l10n_util::GetStringUTF16(IDS_OPTIONS_WALLPAPER_CENTER_LAYOUT)); + entry->SetInteger("index", ash::CENTER); + + layouts.Append(entry = new DictionaryValue()); + entry->SetString("name", + l10n_util::GetStringUTF16(IDS_OPTIONS_WALLPAPER_CENTER_CROPPED_LAYOUT)); + entry->SetInteger("index", ash::CENTER_CROPPED); + + layouts.Append(entry = new DictionaryValue()); + entry->SetString("name", + l10n_util::GetStringUTF16(IDS_OPTIONS_WALLPAPER_STRETCH_LAYOUT)); + entry->SetInteger("index", ash::STRETCH); + + base::FundamentalValue selected_value(static_cast(layout)); + web_ui()->CallJavascriptFunction( + "SetWallpaperOptions.populateWallpaperLayouts", layouts, selected_value); +} + void SetWallpaperOptionsHandler::HandlePageInitialized( const base::ListValue* args) { DCHECK(args && args->empty()); @@ -96,8 +162,47 @@ void SetWallpaperOptionsHandler::HandlePageShown(const base::ListValue* args) { UserManager::Get()->GetLoggedInUserWallpaperProperties(&type, &index); base::StringValue image_url(GetDefaultWallpaperThumbnailURL(index)); base::FundamentalValue is_random(type == User::RANDOM); - web_ui()->CallJavascriptFunction("SetWallpaperOptions.setSelectedImage", - image_url, is_random); + if (type == User::CUSTOMIZED) { + ash::WallpaperLayout layout = static_cast(index); + SendLayoutOptions(layout); + web_ui()->CallJavascriptFunction("SetWallpaperOptions.setCustomImage"); + } else { + SendLayoutOptions(ash::CENTER_CROPPED); + web_ui()->CallJavascriptFunction("SetWallpaperOptions.setSelectedImage", + image_url, is_random); + } +} + +void SetWallpaperOptionsHandler::HandleChooseFile(const ListValue* args) { + DCHECK(args && args->empty()); + if (!select_file_dialog_.get()) + select_file_dialog_ = SelectFileDialog::Create(this); + + FilePath downloads_path; + if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &downloads_path)) + NOTREACHED(); + + // Static so we initialize it only once. + CR_DEFINE_STATIC_LOCAL(SelectFileDialog::FileTypeInfo, file_type_info, + (GetUserImageFileTypeInfo())); + + select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, + l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE), + downloads_path, &file_type_info, 0, + FILE_PATH_LITERAL(""), + web_ui()->GetWebContents(), + GetBrowserWindow(), NULL); +} + +void SetWallpaperOptionsHandler::HandleLayoutChanged(const ListValue* args) { + int selected_layout = ash::CENTER_CROPPED; + if (!ExtractIntegerValue(args, &selected_layout)) + NOTREACHED() << "Could not read wallpaper layout from JSON argument"; + + ash::WallpaperLayout layout = + static_cast(selected_layout); + + UserManager::Get()->SetLoggedInUserCustomWallpaperLayout(layout); } void SetWallpaperOptionsHandler::HandleDefaultWallpaper(const ListValue* args) { diff --git a/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h b/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h index da162ed4f3b9..6bcf981eb95b 100644 --- a/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h +++ b/chrome/browser/ui/webui/options2/chromeos/set_wallpaper_options_handler2.h @@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SET_WALLPAPER_OPTIONS_HANDLER2_H_ #define CHROME_BROWSER_UI_WEBUI_OPTIONS2_CHROMEOS_SET_WALLPAPER_OPTIONS_HANDLER2_H_ +#include "ash/desktop_background/desktop_background_resources.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/select_file_dialog.h" #include "chrome/browser/ui/webui/options2/options_ui2.h" #include "ui/gfx/native_widget_types.h" @@ -15,10 +17,23 @@ class ListValue; } namespace chromeos { + +class WallpaperDelegate { + public: + // Call javascript function to add/update custom wallpaper thumbnail in + // picker UI. + virtual void SetCustomWallpaperThumbnail() = 0; + + protected: + virtual ~WallpaperDelegate() {} +}; + namespace options2 { // ChromeOS user image options page UI handler. -class SetWallpaperOptionsHandler : public ::options2::OptionsPageUIHandler{ +class SetWallpaperOptionsHandler : public ::options2::OptionsPageUIHandler, + public SelectFileDialog::Listener, + public WallpaperDelegate { public: SetWallpaperOptionsHandler(); virtual ~SetWallpaperOptionsHandler(); @@ -30,16 +45,34 @@ class SetWallpaperOptionsHandler : public ::options2::OptionsPageUIHandler{ // WebUIMessageHandler implementation. virtual void RegisterMessages() OVERRIDE; + // WallpaperDelegate implementation. + virtual void SetCustomWallpaperThumbnail() OVERRIDE; + private: + // SelectFileDialog::Delegate implementation. + virtual void FileSelected(const FilePath& path, int index, + void* params) OVERRIDE; + // Sends list of available default images to the page. void SendDefaultImages(); + // Sends layout options for custom wallpaper. Only exposes CENTER, + // CENTER_CROPPED, STRETCH to users. Set the selected option to specified + // |layout|. + void SendLayoutOptions(ash::WallpaperLayout layout); + // Handles page initialized event. void HandlePageInitialized(const base::ListValue* args); // Handles page shown event. void HandlePageShown(const base::ListValue* args); + // Opens a file selection dialog to choose user image from file. + void HandleChooseFile(const base::ListValue* args); + + // Redraws the wallpaper with specified wallpaper layout. + void HandleLayoutChanged(const base::ListValue* args); + // Selects one of the available default wallpapers. void HandleDefaultWallpaper(const base::ListValue* args); @@ -49,6 +82,9 @@ class SetWallpaperOptionsHandler : public ::options2::OptionsPageUIHandler{ // Returns handle to browser window or NULL if it can't be found. gfx::NativeWindow GetBrowserWindow() const; + // Shows a dialog box for selecting a file. + scoped_refptr select_file_dialog_; + base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(SetWallpaperOptionsHandler); diff --git a/chrome/browser/ui/webui/options2/chromeos/wallpaper_thumbnail_source2.cc b/chrome/browser/ui/webui/options2/chromeos/wallpaper_thumbnail_source2.cc index 8186da8b2289..bc38e2da1843 100644 --- a/chrome/browser/ui/webui/options2/chromeos/wallpaper_thumbnail_source2.cc +++ b/chrome/browser/ui/webui/options2/chromeos/wallpaper_thumbnail_source2.cc @@ -12,6 +12,7 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/threading/thread_restrictions.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" #include "chrome/common/url_constants.h" @@ -27,8 +28,9 @@ namespace options2 { namespace { const char kDefaultWallpaperPrefix[] = "default_"; +const char kCustomWallpaperPrefix[] = "custom_"; -// Parse an integer from |path| and save it to |index|. For example, deafult_20 +// Parse an integer from |path| and save it to |index|. For example, default_20 // will set |index| to 20. // |path| and |index| must not be NULL. bool ParseIndexFromPath(const std::string& path, int* index) { @@ -51,6 +53,18 @@ int PathToIDR(const std::string& path) { return idr; } +// True if |path| is a custom wallpaper thumbnail URL and set |email| parsed +// from |path|. +// custom url = "custom_|email|?date" where date is current time. +bool IsCustomWallpaperPath(const std::string& path, std::string* email) { + if (!StartsWithASCII(path, kCustomWallpaperPrefix, false)) + return false; + + std::string sub_path = path.substr(strlen(kCustomWallpaperPrefix)); + *email = sub_path.substr(0, sub_path.find_first_of("?")); + return true; +} + } // namespace std::string GetDefaultWallpaperThumbnailURL(int index) { @@ -78,6 +92,17 @@ WallpaperThumbnailSource::~WallpaperThumbnailSource() { void WallpaperThumbnailSource::StartDataRequest(const std::string& path, bool is_incognito, int request_id) { + std::string email; + if (IsCustomWallpaperPath(path, &email)) { + const chromeos::User* user = chromeos::UserManager::Get()->FindUser(email); + if (user) { + std::vector data; + gfx::PNGCodec::EncodeBGRASkBitmap(user->wallpaper_thumbnail(), + false, &data); + SendResponse(request_id, new base::RefCountedBytes(data)); + return; + } + } int idr = PathToIDR(path); if (idr != -1) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));