Index: chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc |
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc |
index e2e49ef4c4ab7e7f6688b66afd2b4e6f5e9cf251..2b7b98895cbc61863f2137002bcaa0fc51e2e1b8 100644 |
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc |
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc |
@@ -15,6 +15,7 @@ |
#include "base/files/file_path.h" |
#include "base/logging.h" |
#include "base/metrics/histogram_macros.h" |
+#include "base/path_service.h" |
#include "base/sha1.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/sys_info.h" |
@@ -29,6 +30,7 @@ |
#include "chrome/browser/chromeos/login/startup_utils.h" |
#include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h" |
#include "chrome/browser/chromeos/login/wizard_controller.h" |
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" |
#include "chrome/browser/image_decoder.h" |
#include "chrome/browser/ui/ash/ash_util.h" |
#include "chrome/common/chrome_paths.h" |
@@ -49,7 +51,9 @@ |
#include "content/public/browser/notification_service.h" |
#include "content/public/common/content_switches.h" |
#include "content/public/common/service_manager_connection.h" |
+#include "crypto/sha2.h" |
#include "services/service_manager/public/cpp/connector.h" |
+#include "url/gurl.h" |
using content::BrowserThread; |
using wallpaper::WallpaperManagerBase; |
@@ -78,6 +82,11 @@ const char kNewWallpaperTypeNodeName[] = "type"; |
// Known user keys. |
const char kWallpaperFilesId[] = "wallpaper-files-id"; |
+// The directory and file name to save the downloaded device policy controlled |
+// wallpaper. |
+const char kDeviceWallpaperDir[] = "device_wallpaper"; |
+const char kDeviceWallpaperFile[] = "device_wallpaper_image.jpg"; |
+ |
// These global default values are used to set customized default |
// wallpaper path in WallpaperManager::InitializeWallpaper(). |
base::FilePath GetCustomizedWallpaperDefaultRescaledFileName( |
@@ -195,6 +204,21 @@ void SetWallpaper(const gfx::ImageSkia& image, |
} |
} |
+// A helper function to check the existing/downloaded device wallpaper file's |
+// hash value matches with the hash value provided in the policy settings. |
+bool CheckDeviceWallpaperMatchHash(const base::FilePath& device_wallpaper_file, |
+ const std::string& hash) { |
+ std::string image_data; |
+ if (base::ReadFileToString(device_wallpaper_file, &image_data)) { |
+ std::string sha_hash = crypto::SHA256HashString(image_data); |
+ if (base::ToLowerASCII(base::HexEncode( |
+ sha_hash.c_str(), sha_hash.size())) == base::ToLowerASCII(hash)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
} // namespace |
// This is "wallpaper either scheduled to load, or loading right now". |
@@ -347,6 +371,7 @@ class WallpaperManager::PendingWallpaper : |
WallpaperManager::~WallpaperManager() { |
show_user_name_on_signin_subscription_.reset(); |
+ device_wallpaper_image_subscription_.reset(); |
user_manager::UserManager::Get()->RemoveSessionStateObserver(this); |
weak_factory_.InvalidateWeakPtrs(); |
} |
@@ -386,6 +411,11 @@ void WallpaperManager::AddObservers() { |
kAccountsPrefShowUserNamesOnSignIn, |
base::Bind(&WallpaperManager::InitializeRegisteredDeviceWallpaper, |
weak_factory_.GetWeakPtr())); |
+ device_wallpaper_image_subscription_ = |
+ CrosSettings::Get()->AddSettingsObserver( |
+ kDeviceWallpaperImage, |
+ base::Bind(&WallpaperManager::OnDeviceWallpaperPolicyChanged, |
+ weak_factory_.GetWeakPtr())); |
} |
void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() { |
@@ -697,6 +727,12 @@ void WallpaperManager::ScheduleSetUserWallpaper(const AccountId& account_id, |
return; |
} |
+ // For a enterprise managed user, set the device wallpaper if we're at the |
+ // login screen. |
+ if (!user_manager::UserManager::Get()->IsUserLoggedIn() && |
+ SetDeviceWallpaperIfApplicable(account_id)) |
+ return; |
+ |
// Guest user or regular user in ephemeral mode. |
if ((user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral( |
account_id) && |
@@ -734,16 +770,23 @@ void WallpaperManager::ScheduleSetUserWallpaper(const AccountId& account_id, |
} |
if (info.type == user_manager::User::CUSTOMIZED || |
- info.type == user_manager::User::POLICY) { |
- const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution(); |
- // Wallpaper is not resized when layout is |
- // wallpaper::WALLPAPER_LAYOUT_CENTER. |
- // Original wallpaper should be used in this case. |
- // TODO(bshe): Generates cropped custom wallpaper for CENTER layout. |
- if (info.layout == wallpaper::WALLPAPER_LAYOUT_CENTER) |
- sub_dir = wallpaper::kOriginalWallpaperSubDir; |
- base::FilePath wallpaper_path = GetCustomWallpaperDir(sub_dir); |
- wallpaper_path = wallpaper_path.Append(info.location); |
+ info.type == user_manager::User::POLICY || |
+ info.type == user_manager::User::DEVICE) { |
+ base::FilePath wallpaper_path; |
+ if (info.type != user_manager::User::DEVICE) { |
+ const char* sub_dir = GetCustomWallpaperSubdirForCurrentResolution(); |
+ // Wallpaper is not resized when layout is |
+ // wallpaper::WALLPAPER_LAYOUT_CENTER. |
+ // Original wallpaper should be used in this case. |
+ // TODO(bshe): Generates cropped custom wallpaper for CENTER layout. |
+ if (info.layout == wallpaper::WALLPAPER_LAYOUT_CENTER) |
+ sub_dir = wallpaper::kOriginalWallpaperSubDir; |
+ wallpaper_path = GetCustomWallpaperDir(sub_dir); |
+ wallpaper_path = wallpaper_path.Append(info.location); |
+ } else { |
+ wallpaper_path = GetDeviceWallpaperFilePath(); |
+ } |
+ |
CustomWallpaperMap::iterator it = wallpaper_cache_.find(account_id); |
// Do not try to load the wallpaper if the path is the same. Since loading |
// could still be in progress, we ignore the existence of the image. |
@@ -891,6 +934,114 @@ void WallpaperManager::SetPolicyControlledWallpaper( |
true /* update wallpaper */); |
} |
+void WallpaperManager::OnDeviceWallpaperPolicyChanged() { |
+ SetDeviceWallpaperIfApplicable( |
+ user_manager::UserManager::Get()->IsUserLoggedIn() |
+ ? user_manager::UserManager::Get()->GetActiveUser()->GetAccountId() |
+ : user_manager::SignInAccountId()); |
+} |
+ |
+void WallpaperManager::OnDeviceWallpaperExists(const AccountId& account_id, |
+ const std::string& url, |
+ const std::string& hash, |
+ bool exist) { |
+ if (exist) { |
+ base::PostTaskAndReplyWithResult( |
+ BrowserThread::GetBlockingPool(), FROM_HERE, |
+ base::Bind(&CheckDeviceWallpaperMatchHash, GetDeviceWallpaperFilePath(), |
+ hash), |
+ base::Bind(&WallpaperManager::OnCheckDeviceWallpaperMatchHash, |
+ weak_factory_.GetWeakPtr(), account_id, url, hash)); |
+ } else { |
+ GURL device_wallpaper_url(url); |
+ device_wallpaper_downloader_.reset(new CustomizationWallpaperDownloader( |
+ g_browser_process->system_request_context(), device_wallpaper_url, |
+ GetDeviceWallpaperDir(), GetDeviceWallpaperFilePath(), |
+ base::Bind(&WallpaperManager::OnDeviceWallpaperDownloaded, |
+ weak_factory_.GetWeakPtr(), account_id, hash))); |
+ device_wallpaper_downloader_->Start(); |
+ } |
+} |
+ |
+void WallpaperManager::OnDeviceWallpaperDownloaded(const AccountId& account_id, |
+ const std::string& hash, |
+ bool success, |
+ const GURL& url) { |
+ if (!success) { |
+ LOG(ERROR) << "Failed to download the device wallpaper. Fallback to " |
+ "default wallpaper."; |
+ SetDefaultWallpaperDelayed(account_id); |
+ return; |
+ } |
+ |
+ base::PostTaskAndReplyWithResult( |
+ BrowserThread::GetBlockingPool(), FROM_HERE, |
+ base::Bind(&CheckDeviceWallpaperMatchHash, GetDeviceWallpaperFilePath(), |
+ hash), |
+ base::Bind(&WallpaperManager::OnCheckDeviceWallpaperMatchHash, |
+ weak_factory_.GetWeakPtr(), account_id, url.spec(), hash)); |
+} |
+ |
+void WallpaperManager::OnCheckDeviceWallpaperMatchHash( |
+ const AccountId& account_id, |
+ const std::string& url, |
+ const std::string& hash, |
+ bool match) { |
+ if (!match) { |
+ if (retry_download_if_failed_) { |
+ // We only retry to download the device wallpaper one more time if the |
+ // hash doesn't match. |
+ retry_download_if_failed_ = false; |
+ GURL device_wallpaper_url(url); |
+ device_wallpaper_downloader_.reset(new CustomizationWallpaperDownloader( |
+ g_browser_process->system_request_context(), device_wallpaper_url, |
+ GetDeviceWallpaperDir(), GetDeviceWallpaperFilePath(), |
+ base::Bind(&WallpaperManager::OnDeviceWallpaperDownloaded, |
+ weak_factory_.GetWeakPtr(), account_id, hash))); |
+ device_wallpaper_downloader_->Start(); |
+ } else { |
+ LOG(ERROR) << "The device wallpaper hash doesn't match with provided " |
+ "hash value. Fallback to default wallpaper! "; |
+ SetDefaultWallpaperDelayed(account_id); |
+ |
+ // Reset the boolean variable so that it can retry to download when the |
+ // next device wallpaper request comes in. |
+ retry_download_if_failed_ = true; |
+ } |
+ return; |
+ } |
+ |
+ user_image_loader::StartWithFilePath( |
+ task_runner_, GetDeviceWallpaperFilePath(), |
+ ImageDecoder::ROBUST_JPEG_CODEC, |
+ 0, // Do not crop. |
+ base::Bind(&WallpaperManager::OnDeviceWallpaperDecoded, |
+ weak_factory_.GetWeakPtr(), account_id)); |
+} |
+ |
+void WallpaperManager::OnDeviceWallpaperDecoded( |
+ const AccountId& account_id, |
+ std::unique_ptr<user_manager::UserImage> user_image) { |
+ WallpaperInfo wallpaper_info = {GetDeviceWallpaperFilePath().value(), |
+ wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, |
+ user_manager::User::DEVICE, |
+ base::Time::Now().LocalMidnight()}; |
+ if (user_manager::UserManager::Get()->IsUserLoggedIn()) { |
+ // In a user's session treat the device wallpaper as a normal custom |
+ // wallpaper. It should be persistent and can be overriden by other user |
+ // selected wallpapers. |
+ SetUserWallpaperInfo(account_id, wallpaper_info, true /* is_persistent */); |
+ GetPendingWallpaper(account_id, false) |
+ ->ResetSetWallpaperImage(user_image->image(), wallpaper_info); |
+ wallpaper_cache_[account_id] = CustomWallpaperElement( |
+ GetDeviceWallpaperFilePath(), user_image->image()); |
+ } else { |
+ // In the login screen set the device wallpaper as the wallpaper. |
+ GetPendingWallpaper(user_manager::SignInAccountId(), false) |
+ ->ResetSetWallpaperImage(user_image->image(), wallpaper_info); |
+ } |
+} |
+ |
void WallpaperManager::InitializeRegisteredDeviceWallpaper() { |
if (user_manager::UserManager::Get()->IsUserLoggedIn()) |
return; |
@@ -907,7 +1058,8 @@ void WallpaperManager::InitializeRegisteredDeviceWallpaper() { |
int public_session_user_index = FindPublicSession(users); |
if ((!show_users && public_session_user_index == -1) || users.empty()) { |
// Boot into sign in form, preload default wallpaper. |
- SetDefaultWallpaperDelayed(user_manager::SignInAccountId()); |
+ if (!SetDeviceWallpaperIfApplicable(user_manager::SignInAccountId())) |
+ SetDefaultWallpaperDelayed(user_manager::SignInAccountId()); |
return; |
} |
@@ -966,6 +1118,53 @@ bool WallpaperManager::GetUserWallpaperInfo(const AccountId& account_id, |
return true; |
} |
+bool WallpaperManager::ShouldSetDeviceWallpaper(const AccountId& account_id, |
+ std::string* url, |
+ std::string* hash) { |
+ // Only allow the device wallpaper for enterprise managed devices. |
+ if (!g_browser_process->platform_part() |
+ ->browser_policy_connector_chromeos() |
+ ->IsEnterpriseManaged()) { |
+ return false; |
+ } |
+ |
+ const base::DictionaryValue* dict = nullptr; |
+ if (!CrosSettings::Get()->GetDictionary(kDeviceWallpaperImage, &dict) || |
+ !dict->GetStringWithoutPathExpansion("url", url) || |
+ !dict->GetStringWithoutPathExpansion("hash", hash)) { |
+ return false; |
+ } |
+ |
+ // Only set the device wallpaper if 1) we're at the login screen or 2) there |
+ // is no user policy wallpaper in a user session and the user has the default |
+ // wallpaper or device wallpaper in a user session. Note in the latter case, |
+ // the device wallpaper can be overridden by user-selected wallpapers. |
+ if (user_manager::UserManager::Get()->IsUserLoggedIn()) { |
+ WallpaperInfo info; |
+ if (GetUserWallpaperInfo(account_id, &info) && |
+ (info.type == user_manager::User::POLICY || |
+ (info.type != user_manager::User::DEFAULT && |
+ info.type != user_manager::User::DEVICE))) { |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
+base::FilePath WallpaperManager::GetDeviceWallpaperDir() { |
+ base::FilePath wallpaper_dir; |
+ if (!PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir)) { |
+ LOG(ERROR) << "Unable to get wallpaper dir."; |
+ return base::FilePath(); |
+ } |
+ return wallpaper_dir.Append(kDeviceWallpaperDir); |
+} |
+ |
+base::FilePath WallpaperManager::GetDeviceWallpaperFilePath() { |
+ return GetDeviceWallpaperDir().Append(kDeviceWallpaperFile); |
+} |
+ |
void WallpaperManager::OnWallpaperDecoded( |
const AccountId& account_id, |
wallpaper::WallpaperLayout layout, |
@@ -1071,6 +1270,36 @@ size_t WallpaperManager::GetPendingListSizeForTesting() const { |
return loading_.size(); |
} |
+wallpaper::WallpaperFilesId WallpaperManager::GetFilesId( |
+ const AccountId& account_id) const { |
+ std::string stored_value; |
+ if (user_manager::known_user::GetStringPref(account_id, kWallpaperFilesId, |
+ &stored_value)) { |
+ return wallpaper::WallpaperFilesId::FromString(stored_value); |
+ } |
+ const std::string& old_id = account_id.GetUserEmail(); // Migrated |
+ const wallpaper::WallpaperFilesId files_id = HashWallpaperFilesIdStr(old_id); |
+ SetKnownUserWallpaperFilesId(account_id, files_id); |
+ return files_id; |
+} |
+ |
+bool WallpaperManager::SetDeviceWallpaperIfApplicable( |
+ const AccountId& account_id) { |
+ std::string url; |
+ std::string hash; |
+ if (ShouldSetDeviceWallpaper(account_id, &url, &hash)) { |
+ // Check if the device wallpaper exists and matches the hash. If so, use it |
+ // directly. Otherwise download it first. |
+ base::PostTaskAndReplyWithResult( |
+ BrowserThread::GetBlockingPool(), FROM_HERE, |
+ base::Bind(&base::PathExists, GetDeviceWallpaperFilePath()), |
+ base::Bind(&WallpaperManager::OnDeviceWallpaperExists, |
+ weak_factory_.GetWeakPtr(), account_id, url, hash)); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
void WallpaperManager::UserChangedChildStatus(user_manager::User* user) { |
SetUserWallpaperNow(user->GetAccountId()); |
} |
@@ -1157,17 +1386,4 @@ void WallpaperManager::SetDefaultWallpaperPath( |
DoSetDefaultWallpaper(EmptyAccountId(), MovableOnDestroyCallbackHolder()); |
} |
-wallpaper::WallpaperFilesId WallpaperManager::GetFilesId( |
- const AccountId& account_id) const { |
- std::string stored_value; |
- if (user_manager::known_user::GetStringPref(account_id, kWallpaperFilesId, |
- &stored_value)) { |
- return wallpaper::WallpaperFilesId::FromString(stored_value); |
- } |
- const std::string& old_id = account_id.GetUserEmail(); // Migrated |
- const wallpaper::WallpaperFilesId files_id = HashWallpaperFilesIdStr(old_id); |
- SetKnownUserWallpaperFilesId(account_id, files_id); |
- return files_id; |
-} |
- |
} // namespace chromeos |