From 9719234f971edce3c7d6f3c0c35bf935353c9cdf Mon Sep 17 00:00:00 2001 From: "tnagel@chromium.org" Date: Fri, 14 Mar 2014 14:40:07 +0000 Subject: Implement wallpaper policy BUG=220418 R=bshe@chromium.org (for ash_user_wallpaper_delegate.cc) R=nkostylev@chromium.org (for chrome/browser/chromeos/login/*) R=bartfab@chromium.org (for configuration_policy_handler_list_factory.cc) R=jhawkins@chromium.org (for chrome/browser/resources/options/browser_options_handler.{cc,h}) R=dconnelly@chromium.org (for policy_template.json) R=asvitkine@chromium.org (for histograms.xml) Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=257022 Review URL: https://codereview.chromium.org/184223004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257101 0039d316-1c4b-4281-b951-d872f2087c98 --- .../background/ash_user_wallpaper_delegate.cc | 11 +++- chrome/browser/chromeos/login/user.h | 3 +- chrome/browser/chromeos/login/user_manager_impl.cc | 39 ++++++++++--- chrome/browser/chromeos/login/user_manager_impl.h | 6 +- chrome/browser/chromeos/login/wallpaper_manager.cc | 67 ++++++++++++++++++++-- chrome/browser/chromeos/login/wallpaper_manager.h | 25 +++++++- .../configuration_policy_handler_list_factory.cc | 2 + .../browser/resources/options/browser_options.html | 2 + .../browser/resources/options/browser_options.js | 15 +++++ .../ui/webui/options/browser_options_handler.cc | 23 ++++++++ .../ui/webui/options/browser_options_handler.h | 9 +++ chrome/test/data/policy/policy_test_cases.json | 13 ++++- 12 files changed, 198 insertions(+), 17 deletions(-) (limited to 'chrome') diff --git a/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc b/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc index 69c285f..177b5ef 100644 --- a/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc +++ b/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc @@ -12,6 +12,8 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/extensions/wallpaper_manager_util.h" #include "chrome/browser/chromeos/login/startup_utils.h" +#include "chrome/browser/chromeos/login/user.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/login/wallpaper_manager.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chromeos/chromeos_switches.h" @@ -92,7 +94,14 @@ class UserWallpaperDelegate : public ash::UserWallpaperDelegate { } virtual bool CanOpenSetWallpaperPage() OVERRIDE { - return LoginState::Get()->IsUserAuthenticated(); + if (!LoginState::Get()->IsUserAuthenticated()) + return false; + const User* user = chromeos::UserManager::Get()->GetActiveUser(); + if (!user) + return false; + if (chromeos::WallpaperManager::Get()->IsPolicyControlled(user->email())) + return false; + return true; } virtual void OnWallpaperAnimationFinished() OVERRIDE { diff --git a/chrome/browser/chromeos/login/user.h b/chrome/browser/chromeos/login/user.h index 293769d..3458979 100644 --- a/chrome/browser/chromeos/login/user.h +++ b/chrome/browser/chromeos/login/user.h @@ -108,7 +108,8 @@ class User { DEFAULT = 2, UNKNOWN = 3, ONLINE = 4, - WALLPAPER_TYPE_COUNT = 5 + POLICY = 5, // Controlled by policy, can't be changed by the user. + WALLPAPER_TYPE_COUNT = 6 }; // Returns the user type. diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc index 1e0c61a..e1e359a 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.cc +++ b/chrome/browser/chromeos/login/user_manager_impl.cc @@ -239,13 +239,21 @@ UserManagerImpl::UserManagerImpl() policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos(); - policy_observer_.reset(new policy::CloudExternalDataPolicyObserver( + avatar_policy_observer_.reset(new policy::CloudExternalDataPolicyObserver( cros_settings_, this, connector->GetDeviceLocalAccountPolicyService(), policy::key::kUserAvatarImage, this)); - policy_observer_->Init(); + avatar_policy_observer_->Init(); + + wallpaper_policy_observer_.reset(new policy::CloudExternalDataPolicyObserver( + cros_settings_, + this, + connector->GetDeviceLocalAccountPolicyService(), + policy::key::kWallpaperImage, + this)); + wallpaper_policy_observer_->Init(); UpdateLoginState(); } @@ -279,7 +287,8 @@ void UserManagerImpl::Shutdown() { it->second->Shutdown(); } multi_profile_user_controller_.reset(); - policy_observer_.reset(); + avatar_policy_observer_.reset(); + wallpaper_policy_observer_.reset(); } MultiProfileUserController* UserManagerImpl::GetMultiProfileUserController() { @@ -898,7 +907,8 @@ bool UserManagerImpl::RespectLocalePreference( } void UserManagerImpl::StopPolicyObserverForTesting() { - policy_observer_.reset(); + avatar_policy_observer_.reset(); + wallpaper_policy_observer_.reset(); } void UserManagerImpl::Observe(int type, @@ -965,18 +975,33 @@ void UserManagerImpl::Observe(int type, void UserManagerImpl::OnExternalDataSet(const std::string& policy, const std::string& user_id) { - GetUserImageManager(user_id)->OnExternalDataSet(policy); + if (policy == policy::key::kUserAvatarImage) + GetUserImageManager(user_id)->OnExternalDataSet(policy); + else if (policy == policy::key::kWallpaperImage) + WallpaperManager::Get()->OnPolicySet(policy, user_id); + else + NOTREACHED(); } void UserManagerImpl::OnExternalDataCleared(const std::string& policy, const std::string& user_id) { - GetUserImageManager(user_id)->OnExternalDataCleared(policy); + if (policy == policy::key::kUserAvatarImage) + GetUserImageManager(user_id)->OnExternalDataCleared(policy); + else if (policy == policy::key::kWallpaperImage) + WallpaperManager::Get()->OnPolicyCleared(policy, user_id); + else + NOTREACHED(); } void UserManagerImpl::OnExternalDataFetched(const std::string& policy, const std::string& user_id, scoped_ptr data) { - GetUserImageManager(user_id)->OnExternalDataFetched(policy, data.Pass()); + if (policy == policy::key::kUserAvatarImage) + GetUserImageManager(user_id)->OnExternalDataFetched(policy, data.Pass()); + else if (policy == policy::key::kWallpaperImage) + WallpaperManager::Get()->OnPolicyFetched(policy, user_id, data.Pass()); + else + NOTREACHED(); } void UserManagerImpl::OnPolicyUpdated(const std::string& user_id) { diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h index 3123e64..9154ba4 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.h +++ b/chrome/browser/chromeos/login/user_manager_impl.h @@ -480,7 +480,11 @@ class UserManagerImpl multi_profile_first_run_notification_; // Observer for the policy that can be used to manage user images. - scoped_ptr policy_observer_; + scoped_ptr avatar_policy_observer_; + + // Observer for the policy that can be used to manage wallpapers. + scoped_ptr + wallpaper_policy_observer_; DISALLOW_COPY_AND_ASSIGN(UserManagerImpl); }; diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc index f5219da..84870fc 100644 --- a/chrome/browser/chromeos/login/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/wallpaper_manager.cc @@ -590,6 +590,61 @@ void WallpaperManager::ResizeAndSaveWallpaper(const UserImage& wallpaper, } } +bool WallpaperManager::IsPolicyControlled(const std::string& user_id) const { + chromeos::WallpaperInfo info; + if (!GetUserWallpaperInfo(user_id, &info)) + return false; + return info.type == chromeos::User::POLICY; +} + +void WallpaperManager::OnPolicySet(const std::string& policy, + const std::string& user_id) { + WallpaperInfo info; + GetUserWallpaperInfo(user_id, &info); + info.type = User::POLICY; + SetUserWallpaperInfo(user_id, info, true /* is_persistent */); +} + +void WallpaperManager::OnPolicyCleared(const std::string& policy, + const std::string& user_id) { + WallpaperInfo info; + GetUserWallpaperInfo(user_id, &info); + info.type = User::DEFAULT; + SetUserWallpaperInfo(user_id, info, true /* is_persistent */); + SetDefaultWallpaperNow(user_id); +} + +void WallpaperManager::OnPolicyFetched(const std::string& policy, + const std::string& user_id, + scoped_ptr data) { + if (!data) + return; + + wallpaper_loader_->Start( + data.Pass(), + 0, // Do not crop. + base::Bind(&WallpaperManager::SetPolicyControlledWallpaper, + weak_factory_.GetWeakPtr(), + user_id)); +} + +void WallpaperManager::SetPolicyControlledWallpaper( + const std::string& user_id, + const UserImage& wallpaper) { + const User *user = chromeos::UserManager::Get()->FindUser(user_id); + if (!user) { + NOTREACHED() << "Unknown user."; + return; + } + SetCustomWallpaper(user_id, + user->username_hash(), + "policy-controlled.jpeg", + ash::WALLPAPER_LAYOUT_CENTER_CROPPED, + User::POLICY, + wallpaper, + true /* update wallpaper */); +} + void WallpaperManager::SetCustomWallpaper(const std::string& user_id, const std::string& user_id_hash, const std::string& file, @@ -600,10 +655,14 @@ void WallpaperManager::SetCustomWallpaper(const std::string& user_id, DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(UserManager::Get()->IsUserLoggedIn()); - // There is no visible background in kiosk mode. + // There is no visible background in kiosk mode. if (UserManager::Get()->IsLoggedInAsKioskApp()) return; + // Don't allow custom wallpapers while policy is in effect. + if (type != User::POLICY && IsPolicyControlled(user_id)) + return; + base::FilePath wallpaper_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir, user_id_hash, file); @@ -649,7 +708,7 @@ void WallpaperManager::SetCustomWallpaper(const std::string& user_id, WallpaperInfo info = { relative_path, layout, - User::CUSTOMIZED, + type, base::Time::Now().LocalMidnight() }; SetUserWallpaperInfo(user_id, info, is_persistent); @@ -1089,7 +1148,7 @@ void WallpaperManager::LoadWallpaper(const std::string& user_id, } bool WallpaperManager::GetUserWallpaperInfo(const std::string& user_id, - WallpaperInfo* info) { + WallpaperInfo* info) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(user_id)) { @@ -1334,7 +1393,7 @@ void WallpaperManager::StartLoad(const std::string& user_id, TRACE_EVENT_ASYNC_BEGIN0("ui", "LoadAndDecodeWallpaper", this); wallpaper_loader_->Start(wallpaper_path.value(), - 0, + 0, // Do not crop. base::Bind(&WallpaperManager::OnWallpaperDecoded, base::Unretained(this), user_id, diff --git a/chrome/browser/chromeos/login/wallpaper_manager.h b/chrome/browser/chromeos/login/wallpaper_manager.h index 2ce442c..ff6b90a 100644 --- a/chrome/browser/chromeos/login/wallpaper_manager.h +++ b/chrome/browser/chromeos/login/wallpaper_manager.h @@ -107,7 +107,7 @@ class WallpaperManager: public content::NotificationObserver { // 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 + // is passed to other threads by PostTask() calls, therefore it is // RefCountedThreadSafe. class PendingWallpaper : public base::RefCountedThreadSafe { public: @@ -288,11 +288,31 @@ class WallpaperManager: public content::NotificationObserver { // Removes given observer from the list. void RemoveObserver(Observer* observer); + // Returns whether a wallpaper policy is enforced for |user_id|. + bool IsPolicyControlled(const std::string& user_id) const; + + // Called when a wallpaper policy has been set for |user_id|. Blocks user + // from changing the wallpaper. + void OnPolicySet(const std::string& policy, const std::string& user_id); + + // Called when the wallpaper policy has been cleared for |user_id|. + void OnPolicyCleared(const std::string& policy, const std::string& user_id); + + // Called when the policy-set wallpaper has been fetched. Initiates decoding + // of the JPEG |data| with a callback to SetPolicyControlledWallpaper(). + void OnPolicyFetched(const std::string& policy, + const std::string& user_id, + scoped_ptr data); + private: friend class TestApi; friend class WallpaperManagerBrowserTest; typedef std::map CustomWallpaperMap; + // Set |wallpaper| controlled by policy. + void SetPolicyControlledWallpaper(const std::string& user_id, + const UserImage& wallpaper); + // Gets encoded wallpaper from cache. Returns true if success. bool GetWallpaperFromCache(const std::string& user_id, gfx::ImageSkia* wallpaper); @@ -373,7 +393,8 @@ class WallpaperManager: public content::NotificationObserver { // Gets wallpaper information of |user_id| from Local State or memory. Returns // false if wallpaper information is not found. - bool GetUserWallpaperInfo(const std::string& user_id, WallpaperInfo* info); + bool GetUserWallpaperInfo(const std::string& user_id, + WallpaperInfo* info) const; // Sets wallpaper to the decoded wallpaper if |update_wallpaper| is true. // Otherwise, cache wallpaper to memory if not logged in. diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 847d363..6e59679 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc @@ -707,6 +707,8 @@ scoped_ptr BuildHandlerList( new ScreenLockDelayPolicyHandler(chrome_schema))))); handlers->AddHandler(make_scoped_ptr( new ExternalDataPolicyHandler(key::kUserAvatarImage))); + handlers->AddHandler(make_scoped_ptr( + new ExternalDataPolicyHandler(key::kWallpaperImage))); #endif // defined(OS_CHROMEOS) #if defined(OS_ANDROID) || defined(OS_IOS) diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 3c478fe..1d06b1c 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html @@ -34,6 +34,8 @@ + + diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index f482644..da20b3b 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js @@ -1312,6 +1312,20 @@ cr.define('options', function() { } }, + setWallpaperManaged_: function(managed) { + var button = $('set-wallpaper'); + button.disabled = !!managed; + + // Create a synthetic pref change event decorated as + // CoreOptionsHandler::CreateValueForPref() does. + var event = new Event('account-picture'); + if (managed) + event.value = { controlledBy: 'policy' }; + else + event.value = {}; + $('wallpaper-indicator').handlePrefChange(event); + }, + /** * Handle the 'add device' button click. * @private @@ -1646,6 +1660,7 @@ cr.define('options', function() { 'removeCloudPrintConnectorSection', 'scrollToSection', 'setAccountPictureManaged', + 'setWallpaperManaged', 'setAutoOpenFileTypesDisplayed', 'setBluetoothState', 'setFontSize', diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 68f27d7..fd82599 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc @@ -104,6 +104,7 @@ #include "chrome/browser/chromeos/extensions/wallpaper_manager_util.h" #include "chrome/browser/chromeos/login/user.h" #include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/login/wallpaper_manager.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/timezone_util.h" @@ -807,6 +808,10 @@ void BrowserOptionsHandler::InitializeHandler() { policy::key::kUserAvatarImage, base::Bind(&BrowserOptionsHandler::OnUserImagePolicyChanged, base::Unretained(this))); + policy_registrar_->Observe( + policy::key::kWallpaperImage, + base::Bind(&BrowserOptionsHandler::OnWallpaperPolicyChanged, + base::Unretained(this))); } #else // !defined(OS_CHROMEOS) profile_pref_registrar_.Add( @@ -862,6 +867,10 @@ void BrowserOptionsHandler::InitializePage() { policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())) .Get(policy::key::kUserAvatarImage)); + + OnWallpaperManagedChanged( + chromeos::WallpaperManager::Get()->IsPolicyControlled( + chromeos::UserManager::Get()->GetActiveUser()->email())); #endif } @@ -1249,6 +1258,11 @@ void BrowserOptionsHandler::OnAccountPictureManagedChanged(bool managed) { web_ui()->CallJavascriptFunction("BrowserOptions.setAccountPictureManaged", base::FundamentalValue(managed)); } + +void BrowserOptionsHandler::OnWallpaperManagedChanged(bool managed) { + web_ui()->CallJavascriptFunction("BrowserOptions.setWallpaperManaged", + base::FundamentalValue(managed)); +} #endif scoped_ptr @@ -1356,6 +1370,15 @@ void BrowserOptionsHandler::OnUserImagePolicyChanged( OnAccountPictureManagedChanged(has_policy); } +void BrowserOptionsHandler::OnWallpaperPolicyChanged( + const base::Value* previous_policy, + const base::Value* current_policy) { + const bool had_policy = previous_policy; + const bool has_policy = current_policy; + if (had_policy != has_policy) + OnWallpaperManagedChanged(has_policy); +} + #endif // defined(OS_CHROMEOS) void BrowserOptionsHandler::UpdateSyncState() { diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h index ca9cd37..85682a3 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.h +++ b/chrome/browser/ui/webui/options/browser_options_handler.h @@ -101,6 +101,10 @@ class BrowserOptionsHandler // Will be called when the policy::key::kUserAvatarImage policy changes. void OnUserImagePolicyChanged(const base::Value* previous_policy, const base::Value* current_policy); + + // Will be called when the policy::key::kWallpaperImage policy changes. + void OnWallpaperPolicyChanged(const base::Value* previous_policy, + const base::Value* current_policy); #endif void UpdateSyncState(); @@ -179,6 +183,11 @@ class BrowserOptionsHandler // is |false| and preventing the user from changing the avatar image if // |managed| is |true|. void OnAccountPictureManagedChanged(bool managed); + + // Updates the UI, allowing the user to change the wallpaper if |managed| is + // |false| and preventing the user from changing the wallpaper if |managed| is + // |true|. + void OnWallpaperManagedChanged(bool managed); #endif // Callback for the "selectDownloadLocation" message. This will prompt the diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index c11f95a..65b86ab 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json @@ -1569,12 +1569,23 @@ "test_policy": { "UserAvatarImage": { "url": "http://localhost/", - "hash": "01234567890012345678900123456789001234567890" + "hash": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" } }, "indicator_selector": "#account-picture-indicator" }, + "WallpaperImage": { + "os": ["chromeos"], + "test_policy": { + "WallpaperImage": { + "url": "http://localhost/", + "hash": "baddecafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecafbaddecaf" + } + }, + "indicator_selector": "#wallpaper-indicator" + }, + "----- Chrome OS policies ------------------------------------------------": {}, "ChromeOsLockOnIdleSuspend": { -- cgit v1.1